summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/common_funcs.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp16
-rw-r--r--src/core/hle/service/caps/caps.cpp2
-rw-r--r--src/core/hle/service/caps/caps_a.cpp4
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp86
-rw-r--r--src/core/hle/service/caps/caps_manager.h9
-rw-r--r--src/core/hle/service/caps/caps_types.h14
-rw-r--r--src/core/hle/service/caps/caps_u.cpp74
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp44
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h1
-rw-r--r--src/yuzu/util/util.cpp81
14 files changed, 250 insertions, 103 deletions
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 0dad9338a..47d028d48 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -39,8 +39,12 @@
#define Crash() exit(1)
#endif
+#define LTO_NOINLINE __attribute__((noinline))
+
#else // _MSC_VER
+#define LTO_NOINLINE
+
// Locale Cross-Compatibility
#define locale_t _locale_t
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index a1134b7e2..cb025c3d6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -373,7 +373,7 @@ struct KernelCore::Impl {
static inline thread_local u8 host_thread_id = UINT8_MAX;
/// Sets the host thread ID for the caller.
- u32 SetHostThreadId(std::size_t core_id) {
+ LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
// This should only be called during core init.
ASSERT(host_thread_id == UINT8_MAX);
@@ -384,13 +384,13 @@ struct KernelCore::Impl {
}
/// Gets the host thread ID for the caller
- u32 GetHostThreadId() const {
+ LTO_NOINLINE u32 GetHostThreadId() const {
return host_thread_id;
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
- KThread* GetHostDummyThread(KThread* existing_thread) {
- const auto initialize{[](KThread* thread) {
+ LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
+ const auto initialize{[](KThread* thread) LTO_NOINLINE {
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
return thread;
}};
@@ -424,11 +424,11 @@ struct KernelCore::Impl {
static inline thread_local bool is_phantom_mode_for_singlecore{false};
- bool IsPhantomModeForSingleCore() const {
+ LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
return is_phantom_mode_for_singlecore;
}
- void SetIsPhantomModeForSingleCore(bool value) {
+ LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
ASSERT(!is_multicore);
is_phantom_mode_for_singlecore = value;
}
@@ -439,14 +439,14 @@ struct KernelCore::Impl {
static inline thread_local KThread* current_thread{nullptr};
- KThread* GetCurrentEmuThread() {
+ LTO_NOINLINE KThread* GetCurrentEmuThread() {
if (!current_thread) {
current_thread = GetHostDummyThread(nullptr);
}
return current_thread;
}
- void SetCurrentEmuThread(KThread* thread) {
+ LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
current_thread = thread;
}
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index 286f9fd10..31dd98140 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -16,7 +16,7 @@ namespace Service::Capture {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- auto album_manager = std::make_shared<AlbumManager>();
+ auto album_manager = std::make_shared<AlbumManager>(system);
server_manager->RegisterNamedService(
"caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager));
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index e22f72bf6..9925720a3 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -128,9 +128,9 @@ void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
ctx.WriteBuffer(entries);
}
- IPC::ResponseBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
- rb.Push(entries.size());
+ rb.Push<u64>(entries.size());
}
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index 2df6a930a..2b4e3f076 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -8,12 +8,15 @@
#include "common/fs/file.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
+#include "core/hle/service/time/time_manager.h"
+#include "core/hle/service/time/time_zone_content_manager.h"
namespace Service::Capture {
-AlbumManager::AlbumManager() {}
+AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
AlbumManager::~AlbumManager() = default;
@@ -83,6 +86,34 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
}
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
+ ContentType contex_type, s64 start_posix_time,
+ s64 end_posix_time, u64 aruid) const {
+ if (!is_mounted) {
+ return ResultIsNotMounted;
+ }
+
+ std::vector<ApplicationAlbumEntry> album_entries;
+ const auto start_date = ConvertToAlbumDateTime(start_posix_time);
+ const auto end_date = ConvertToAlbumDateTime(end_posix_time);
+ const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ for (const auto& album_entry : album_entries) {
+ ApplicationAlbumFileEntry entry{
+ .entry = album_entry,
+ .datetime = album_entry.datetime,
+ .unknown = {},
+ };
+ out_entries.push_back(entry);
+ }
+
+ return ResultSuccess;
+}
+
+Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const {
if (!is_mounted) {
@@ -93,31 +124,25 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
if (file_id.type != contex_type) {
continue;
}
-
if (file_id.date > start_date) {
continue;
}
-
if (file_id.date < end_date) {
continue;
}
-
if (out_entries.size() >= SdAlbumFileLimit) {
break;
}
const auto entry_size = Common::FS::GetSize(path);
- ApplicationAlbumFileEntry entry{.entry =
- {
- .size = entry_size,
- .hash{},
- .datetime = file_id.date,
- .storage = file_id.storage,
- .content = contex_type,
- .unknown = 1,
- },
- .datetime = file_id.date,
- .unknown = {}};
+ ApplicationAlbumEntry entry{
+ .size = entry_size,
+ .hash{},
+ .datetime = file_id.date,
+ .storage = file_id.storage,
+ .content = contex_type,
+ .unknown = 1,
+ };
out_entries.push_back(entry);
}
@@ -274,12 +299,12 @@ Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem:
.application_id = static_cast<u64>(std::stoll(application, 0, 16)),
.date =
{
- .year = static_cast<u16>(std::stoi(year)),
- .month = static_cast<u8>(std::stoi(month)),
- .day = static_cast<u8>(std::stoi(day)),
- .hour = static_cast<u8>(std::stoi(hour)),
- .minute = static_cast<u8>(std::stoi(minute)),
- .second = static_cast<u8>(std::stoi(second)),
+ .year = static_cast<s16>(std::stoi(year)),
+ .month = static_cast<s8>(std::stoi(month)),
+ .day = static_cast<s8>(std::stoi(day)),
+ .hour = static_cast<s8>(std::stoi(hour)),
+ .minute = static_cast<s8>(std::stoi(minute)),
+ .second = static_cast<s8>(std::stoi(second)),
.unique_id = 0,
},
.storage = AlbumStorage::Sd,
@@ -339,4 +364,23 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
return ResultSuccess;
}
+
+AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
+ Time::TimeZone::CalendarInfo calendar_date{};
+ const auto& time_zone_manager =
+ system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
+
+ time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date);
+
+ return {
+ .year = calendar_date.time.year,
+ .month = calendar_date.time.month,
+ .day = calendar_date.time.day,
+ .hour = calendar_date.time.hour,
+ .minute = calendar_date.time.minute,
+ .second = calendar_date.time.second,
+ .unique_id = 0,
+ };
+}
+
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h
index 8337c655c..f65eb12c1 100644
--- a/src/core/hle/service/caps/caps_manager.h
+++ b/src/core/hle/service/caps/caps_manager.h
@@ -37,7 +37,7 @@ namespace Service::Capture {
class AlbumManager {
public:
- explicit AlbumManager();
+ explicit AlbumManager(Core::System& system_);
~AlbumManager();
Result DeleteAlbumFile(const AlbumFileId& file_id);
@@ -45,6 +45,9 @@ public:
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
+ ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
+ u64 aruid) const;
+ Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const;
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
@@ -65,8 +68,12 @@ private:
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
int height, ScreenShotDecoderFlag flag) const;
+ AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
+
bool is_mounted{};
std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
+
+ Core::System& system;
};
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_types.h b/src/core/hle/service/caps/caps_types.h
index bf6061273..7fd357954 100644
--- a/src/core/hle/service/caps/caps_types.h
+++ b/src/core/hle/service/caps/caps_types.h
@@ -41,13 +41,13 @@ enum class ScreenShotDecoderFlag : u64 {
// This is nn::capsrv::AlbumFileDateTime
struct AlbumFileDateTime {
- u16 year{};
- u8 month{};
- u8 day{};
- u8 hour{};
- u8 minute{};
- u8 second{};
- u8 unique_id{};
+ s16 year{};
+ s8 month{};
+ s8 day{};
+ s8 hour{};
+ s8 minute{};
+ s8 second{};
+ s8 unique_id{};
friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index 260f25490..b6b33fb2f 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -50,22 +50,35 @@ void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto pid{rp.Pop<s32>()};
- const auto content_type{rp.PopEnum<ContentType>()};
- const auto start_posix_time{rp.Pop<s64>()};
- const auto end_posix_time{rp.Pop<s64>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
+ struct Parameters {
+ ContentType content_type;
+ INSERT_PADDING_BYTES(7);
+ s64 start_posix_time;
+ s64 end_posix_time;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_Capture,
- "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
- "end_posix_time={}, applet_resource_user_id={}",
- pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
+ "(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, "
+ "applet_resource_user_id={}",
+ parameters.content_type, parameters.start_posix_time, parameters.end_posix_time,
+ parameters.applet_resource_user_id);
- // TODO: Translate posix to DateTime
+ Result result = ResultSuccess;
+
+ if (result.IsSuccess()) {
+ result = manager->IsAlbumMounted(AlbumStorage::Sd);
+ }
std::vector<ApplicationAlbumFileEntry> entries;
- const Result result =
- manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
+ if (result.IsSuccess()) {
+ result = manager->GetAlbumFileList(entries, parameters.content_type,
+ parameters.start_posix_time, parameters.end_posix_time,
+ parameters.applet_resource_user_id);
+ }
if (!entries.empty()) {
ctx.WriteBuffer(entries);
@@ -78,19 +91,38 @@ void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestCo
void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto pid{rp.Pop<s32>()};
- const auto content_type{rp.PopEnum<ContentType>()};
- const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()};
- const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
+ struct Parameters {
+ ContentType content_type;
+ INSERT_PADDING_BYTES(1);
+ AlbumFileDateTime start_date_time;
+ AlbumFileDateTime end_date_time;
+ INSERT_PADDING_BYTES(6);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_Capture,
- "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
- content_type, applet_resource_user_id);
+ "(STUBBED) called. content_type={}, start_date={}/{}/{}, "
+ "end_date={}/{}/{}, applet_resource_user_id={}",
+ parameters.content_type, parameters.start_date_time.year,
+ parameters.start_date_time.month, parameters.start_date_time.day,
+ parameters.end_date_time.year, parameters.end_date_time.month,
+ parameters.end_date_time.day, parameters.applet_resource_user_id);
- std::vector<ApplicationAlbumFileEntry> entries;
- const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time,
- end_date_time, applet_resource_user_id);
+ Result result = ResultSuccess;
+
+ if (result.IsSuccess()) {
+ result = manager->IsAlbumMounted(AlbumStorage::Sd);
+ }
+
+ std::vector<ApplicationAlbumEntry> entries;
+ if (result.IsSuccess()) {
+ result =
+ manager->GetAlbumFileList(entries, parameters.content_type, parameters.start_date_time,
+ parameters.end_date_time, parameters.applet_resource_user_id);
+ }
if (!entries.empty()) {
ctx.WriteBuffer(entries);
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 9cafd2983..512eef575 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -1048,6 +1048,10 @@ void Image::Scale(bool up_scale) {
}
bool Image::ScaleUp(bool ignore) {
+ const auto& resolution = runtime->resolution;
+ if (!resolution.active) {
+ return false;
+ }
if (True(flags & ImageFlagBits::Rescaled)) {
return false;
}
@@ -1060,9 +1064,6 @@ bool Image::ScaleUp(bool ignore) {
return false;
}
flags |= ImageFlagBits::Rescaled;
- if (!runtime->resolution.active) {
- return false;
- }
has_scaled = true;
if (ignore) {
current_texture = upscaled_backup.handle;
@@ -1073,13 +1074,14 @@ bool Image::ScaleUp(bool ignore) {
}
bool Image::ScaleDown(bool ignore) {
- if (False(flags & ImageFlagBits::Rescaled)) {
+ const auto& resolution = runtime->resolution;
+ if (!resolution.active) {
return false;
}
- flags &= ~ImageFlagBits::Rescaled;
- if (!runtime->resolution.active) {
+ if (False(flags & ImageFlagBits::Rescaled)) {
return false;
}
+ flags &= ~ImageFlagBits::Rescaled;
if (ignore) {
current_texture = texture.handle;
return true;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 3676eaaa9..e71b87e99 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -118,6 +118,8 @@ public:
void InsertUploadMemoryBarrier();
+ void TransitionImageLayout(Image& image) {}
+
FormatProperties FormatInfo(VideoCommon::ImageType type, GLenum internal_format) const;
bool HasNativeBgr() const noexcept {
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 00ab47268..93773a69f 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1530,15 +1530,15 @@ bool Image::IsRescaled() const noexcept {
}
bool Image::ScaleUp(bool ignore) {
+ const auto& resolution = runtime->resolution;
+ if (!resolution.active) {
+ return false;
+ }
if (True(flags & ImageFlagBits::Rescaled)) {
return false;
}
ASSERT(info.type != ImageType::Linear);
flags |= ImageFlagBits::Rescaled;
- const auto& resolution = runtime->resolution;
- if (!resolution.active) {
- return false;
- }
has_scaled = true;
if (!scaled_image) {
const bool is_2d = info.type == ImageType::e2D;
@@ -1567,15 +1567,15 @@ bool Image::ScaleUp(bool ignore) {
}
bool Image::ScaleDown(bool ignore) {
+ const auto& resolution = runtime->resolution;
+ if (!resolution.active) {
+ return false;
+ }
if (False(flags & ImageFlagBits::Rescaled)) {
return false;
}
ASSERT(info.type != ImageType::Linear);
flags &= ~ImageFlagBits::Rescaled;
- const auto& resolution = runtime->resolution;
- if (!resolution.active) {
- return false;
- }
current_image = *original_image;
if (ignore) {
return true;
@@ -2013,4 +2013,32 @@ void TextureCacheRuntime::AccelerateImageUpload(
ASSERT(false);
}
+void TextureCacheRuntime::TransitionImageLayout(Image& image) {
+ if (!image.ExchangeInitialization()) {
+ VkImageMemoryBarrier barrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_NONE,
+ .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = image.Handle(),
+ .subresourceRange{
+ .aspectMask = image.AspectMask(),
+ .baseMipLevel = 0,
+ .levelCount = VK_REMAINING_MIP_LEVELS,
+ .baseArrayLayer = 0,
+ .layerCount = VK_REMAINING_ARRAY_LAYERS,
+ },
+ };
+ scheduler.RequestOutsideRenderPassOperationContext();
+ scheduler.Record([barrier = barrier](vk::CommandBuffer cmdbuf) {
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
+ });
+ }
+}
+
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index d6c5a15cc..7a0807709 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -92,6 +92,8 @@ public:
void InsertUploadMemoryBarrier() {}
+ void TransitionImageLayout(Image& image);
+
bool HasBrokenTextureViewFormats() const noexcept {
// No known Vulkan driver has broken image views
return false;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 1bdb0def5..d575c57ca 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1016,6 +1016,7 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) {
LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented");
+ runtime.TransitionImageLayout(image);
return;
}
if (True(image.flags & ImageFlagBits::AsynchronousDecode)) {
diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp
index 61cf00176..f2854c8ec 100644
--- a/src/yuzu/util/util.cpp
+++ b/src/yuzu/util/util.cpp
@@ -63,25 +63,15 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
};
#pragma pack(pop)
- QImage source_image = image.convertToFormat(QImage::Format_RGB32);
+ const QImage source_image = image.convertToFormat(QImage::Format_RGB32);
+ constexpr std::array<int, 7> scale_sizes{256, 128, 64, 48, 32, 24, 16};
constexpr int bytes_per_pixel = 4;
- const int image_size = source_image.width() * source_image.height() * bytes_per_pixel;
-
- BITMAPINFOHEADER info_header{};
- info_header.biSize = sizeof(BITMAPINFOHEADER), info_header.biWidth = source_image.width(),
- info_header.biHeight = source_image.height() * 2, info_header.biPlanes = 1,
- info_header.biBitCount = bytes_per_pixel * 8, info_header.biCompression = BI_RGB;
-
- const IconDir icon_dir{.id_reserved = 0, .id_type = 1, .id_count = 1};
- const IconDirEntry icon_entry{.width = static_cast<BYTE>(source_image.width()),
- .height = static_cast<BYTE>(source_image.height() * 2),
- .color_count = 0,
- .reserved = 0,
- .planes = 1,
- .bit_count = bytes_per_pixel * 8,
- .bytes_in_res =
- static_cast<DWORD>(sizeof(BITMAPINFOHEADER) + image_size),
- .image_offset = sizeof(IconDir) + sizeof(IconDirEntry)};
+
+ const IconDir icon_dir{
+ .id_reserved = 0,
+ .id_type = 1,
+ .id_count = static_cast<WORD>(scale_sizes.size()),
+ };
Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write,
Common::FS::FileType::BinaryFile);
@@ -92,20 +82,55 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
if (!icon_file.Write(icon_dir)) {
return false;
}
- if (!icon_file.Write(icon_entry)) {
- return false;
- }
- if (!icon_file.Write(info_header)) {
- return false;
+
+ std::size_t image_offset = sizeof(IconDir) + (sizeof(IconDirEntry) * scale_sizes.size());
+ for (std::size_t i = 0; i < scale_sizes.size(); i++) {
+ const int image_size = scale_sizes[i] * scale_sizes[i] * bytes_per_pixel;
+ const IconDirEntry icon_entry{
+ .width = static_cast<BYTE>(scale_sizes[i]),
+ .height = static_cast<BYTE>(scale_sizes[i]),
+ .color_count = 0,
+ .reserved = 0,
+ .planes = 1,
+ .bit_count = bytes_per_pixel * 8,
+ .bytes_in_res = static_cast<DWORD>(sizeof(BITMAPINFOHEADER) + image_size),
+ .image_offset = static_cast<DWORD>(image_offset),
+ };
+ image_offset += icon_entry.bytes_in_res;
+ if (!icon_file.Write(icon_entry)) {
+ return false;
+ }
}
- for (int y = 0; y < image.height(); y++) {
- const auto* line = source_image.scanLine(source_image.height() - 1 - y);
- std::vector<u8> line_data(source_image.width() * bytes_per_pixel);
- std::memcpy(line_data.data(), line, line_data.size());
- if (!icon_file.Write(line_data)) {
+ for (std::size_t i = 0; i < scale_sizes.size(); i++) {
+ const QImage scaled_image = source_image.scaled(
+ scale_sizes[i], scale_sizes[i], Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ const BITMAPINFOHEADER info_header{
+ .biSize = sizeof(BITMAPINFOHEADER),
+ .biWidth = scaled_image.width(),
+ .biHeight = scaled_image.height() * 2,
+ .biPlanes = 1,
+ .biBitCount = bytes_per_pixel * 8,
+ .biCompression = BI_RGB,
+ .biSizeImage{},
+ .biXPelsPerMeter{},
+ .biYPelsPerMeter{},
+ .biClrUsed{},
+ .biClrImportant{},
+ };
+
+ if (!icon_file.Write(info_header)) {
return false;
}
+
+ for (int y = 0; y < scaled_image.height(); y++) {
+ const auto* line = scaled_image.scanLine(scaled_image.height() - 1 - y);
+ std::vector<u8> line_data(scaled_image.width() * bytes_per_pixel);
+ std::memcpy(line_data.data(), line, line_data.size());
+ if (!icon_file.Write(line_data)) {
+ return false;
+ }
+ }
}
icon_file.Close();