summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/scripts/common/pre-upload.sh2
-rwxr-xr-x.ci/scripts/linux/docker.sh15
-rwxr-xr-x.ci/scripts/linux/upload.sh5
-rw-r--r--externals/nx_tzdb/CMakeLists.txt2
m---------externals/nx_tzdb/tzdb_to_nx0
-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
19 files changed, 271 insertions, 106 deletions
diff --git a/.ci/scripts/common/pre-upload.sh b/.ci/scripts/common/pre-upload.sh
index 705362a3c..3583f9840 100644
--- a/.ci/scripts/common/pre-upload.sh
+++ b/.ci/scripts/common/pre-upload.sh
@@ -5,6 +5,6 @@
5 5
6GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`" 6GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
7GITREV="`git show -s --format='%h'`" 7GITREV="`git show -s --format='%h'`"
8ARTIFACTS_DIR="artifacts" 8ARTIFACTS_DIR="$PWD/artifacts"
9 9
10mkdir -p "${ARTIFACTS_DIR}/" 10mkdir -p "${ARTIFACTS_DIR}/"
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh
index e5d83d4b9..a16577b27 100755
--- a/.ci/scripts/linux/docker.sh
+++ b/.ci/scripts/linux/docker.sh
@@ -11,7 +11,7 @@ ccache -s
11mkdir build || true && cd build 11mkdir build || true && cd build
12cmake .. \ 12cmake .. \
13 -DBoost_USE_STATIC_LIBS=ON \ 13 -DBoost_USE_STATIC_LIBS=ON \
14 -DCMAKE_BUILD_TYPE=Release \ 14 -DCMAKE_BUILD_TYPE=RelWithDebInfo \
15 -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \ 15 -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
16 -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \ 16 -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
17 -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \ 17 -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
@@ -31,6 +31,19 @@ ccache -s
31 31
32ctest -VV -C Release 32ctest -VV -C Release
33 33
34# Separate debug symbols from specified executables
35for EXE in yuzu; do
36 EXE_PATH="bin/$EXE"
37 # Copy debug symbols out
38 objcopy --only-keep-debug $EXE_PATH $EXE_PATH.debug
39 # Add debug link and strip debug symbols
40 objcopy -g --add-gnu-debuglink=$EXE_PATH.debug $EXE_PATH $EXE_PATH.out
41 # Overwrite original with stripped copy
42 mv $EXE_PATH.out $EXE_PATH
43done
44# Strip debug symbols from all executables
45find bin/ -type f -not -regex '.*.debug' -exec strip -g {} ';'
46
34DESTDIR="$PWD/AppDir" ninja install 47DESTDIR="$PWD/AppDir" ninja install
35rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester 48rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
36 49
diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh
index e0f336427..fbb2d9c1b 100755
--- a/.ci/scripts/linux/upload.sh
+++ b/.ci/scripts/linux/upload.sh
@@ -59,4 +59,9 @@ if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ];
59 cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage" 59 cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage"
60fi 60fi
61 61
62# Copy debug symbols to artifacts
63cd build/bin
64tar $COMPRESSION_FLAGS "${ARTIFACTS_DIR}/${REV_NAME}-debug.tar.xz" *.debug
65cd -
66
62. .ci/scripts/common/post-upload.sh 67. .ci/scripts/common/post-upload.sh
diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt
index 593786250..0fad24642 100644
--- a/externals/nx_tzdb/CMakeLists.txt
+++ b/externals/nx_tzdb/CMakeLists.txt
@@ -27,7 +27,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
27 set(CAN_BUILD_NX_TZDB false) 27 set(CAN_BUILD_NX_TZDB false)
28endif() 28endif()
29 29
30set(NX_TZDB_VERSION "220816") 30set(NX_TZDB_VERSION "221202")
31set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip") 31set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
32 32
33set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb") 33set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx
Subproject 212afa2394a74226dcf1b7996a570aae17debb6 Subproject 0d17dd066d91f954a4c89d46dcb067eead6b1e4
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 @@
39#define Crash() exit(1) 39#define Crash() exit(1)
40#endif 40#endif
41 41
42#define LTO_NOINLINE __attribute__((noinline))
43
42#else // _MSC_VER 44#else // _MSC_VER
43 45
46#define LTO_NOINLINE
47
44// Locale Cross-Compatibility 48// Locale Cross-Compatibility
45#define locale_t _locale_t 49#define locale_t _locale_t
46 50
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 {
373 static inline thread_local u8 host_thread_id = UINT8_MAX; 373 static inline thread_local u8 host_thread_id = UINT8_MAX;
374 374
375 /// Sets the host thread ID for the caller. 375 /// Sets the host thread ID for the caller.
376 u32 SetHostThreadId(std::size_t core_id) { 376 LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
377 // This should only be called during core init. 377 // This should only be called during core init.
378 ASSERT(host_thread_id == UINT8_MAX); 378 ASSERT(host_thread_id == UINT8_MAX);
379 379
@@ -384,13 +384,13 @@ struct KernelCore::Impl {
384 } 384 }
385 385
386 /// Gets the host thread ID for the caller 386 /// Gets the host thread ID for the caller
387 u32 GetHostThreadId() const { 387 LTO_NOINLINE u32 GetHostThreadId() const {
388 return host_thread_id; 388 return host_thread_id;
389 } 389 }
390 390
391 // Gets the dummy KThread for the caller, allocating a new one if this is the first time 391 // Gets the dummy KThread for the caller, allocating a new one if this is the first time
392 KThread* GetHostDummyThread(KThread* existing_thread) { 392 LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
393 const auto initialize{[](KThread* thread) { 393 const auto initialize{[](KThread* thread) LTO_NOINLINE {
394 ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess()); 394 ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
395 return thread; 395 return thread;
396 }}; 396 }};
@@ -424,11 +424,11 @@ struct KernelCore::Impl {
424 424
425 static inline thread_local bool is_phantom_mode_for_singlecore{false}; 425 static inline thread_local bool is_phantom_mode_for_singlecore{false};
426 426
427 bool IsPhantomModeForSingleCore() const { 427 LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
428 return is_phantom_mode_for_singlecore; 428 return is_phantom_mode_for_singlecore;
429 } 429 }
430 430
431 void SetIsPhantomModeForSingleCore(bool value) { 431 LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
432 ASSERT(!is_multicore); 432 ASSERT(!is_multicore);
433 is_phantom_mode_for_singlecore = value; 433 is_phantom_mode_for_singlecore = value;
434 } 434 }
@@ -439,14 +439,14 @@ struct KernelCore::Impl {
439 439
440 static inline thread_local KThread* current_thread{nullptr}; 440 static inline thread_local KThread* current_thread{nullptr};
441 441
442 KThread* GetCurrentEmuThread() { 442 LTO_NOINLINE KThread* GetCurrentEmuThread() {
443 if (!current_thread) { 443 if (!current_thread) {
444 current_thread = GetHostDummyThread(nullptr); 444 current_thread = GetHostDummyThread(nullptr);
445 } 445 }
446 return current_thread; 446 return current_thread;
447 } 447 }
448 448
449 void SetCurrentEmuThread(KThread* thread) { 449 LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
450 current_thread = thread; 450 current_thread = thread;
451 } 451 }
452 452
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 {
16 16
17void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
18 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
19 auto album_manager = std::make_shared<AlbumManager>(); 19 auto album_manager = std::make_shared<AlbumManager>(system);
20 20
21 server_manager->RegisterNamedService( 21 server_manager->RegisterNamedService(
22 "caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager)); 22 "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) {
128 ctx.WriteBuffer(entries); 128 ctx.WriteBuffer(entries);
129 } 129 }
130 130
131 IPC::ResponseBuilder rb{ctx, 3}; 131 IPC::ResponseBuilder rb{ctx, 4};
132 rb.Push(result); 132 rb.Push(result);
133 rb.Push(entries.size()); 133 rb.Push<u64>(entries.size());
134} 134}
135 135
136void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) { 136void 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 @@
8#include "common/fs/file.h" 8#include "common/fs/file.h"
9#include "common/fs/path_util.h" 9#include "common/fs/path_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/core.h"
11#include "core/hle/service/caps/caps_manager.h" 12#include "core/hle/service/caps/caps_manager.h"
12#include "core/hle/service/caps/caps_result.h" 13#include "core/hle/service/caps/caps_result.h"
14#include "core/hle/service/time/time_manager.h"
15#include "core/hle/service/time/time_zone_content_manager.h"
13 16
14namespace Service::Capture { 17namespace Service::Capture {
15 18
16AlbumManager::AlbumManager() {} 19AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
17 20
18AlbumManager::~AlbumManager() = default; 21AlbumManager::~AlbumManager() = default;
19 22
@@ -83,6 +86,34 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
83} 86}
84 87
85Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, 88Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
89 ContentType contex_type, s64 start_posix_time,
90 s64 end_posix_time, u64 aruid) const {
91 if (!is_mounted) {
92 return ResultIsNotMounted;
93 }
94
95 std::vector<ApplicationAlbumEntry> album_entries;
96 const auto start_date = ConvertToAlbumDateTime(start_posix_time);
97 const auto end_date = ConvertToAlbumDateTime(end_posix_time);
98 const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid);
99
100 if (result.IsError()) {
101 return result;
102 }
103
104 for (const auto& album_entry : album_entries) {
105 ApplicationAlbumFileEntry entry{
106 .entry = album_entry,
107 .datetime = album_entry.datetime,
108 .unknown = {},
109 };
110 out_entries.push_back(entry);
111 }
112
113 return ResultSuccess;
114}
115
116Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
86 ContentType contex_type, AlbumFileDateTime start_date, 117 ContentType contex_type, AlbumFileDateTime start_date,
87 AlbumFileDateTime end_date, u64 aruid) const { 118 AlbumFileDateTime end_date, u64 aruid) const {
88 if (!is_mounted) { 119 if (!is_mounted) {
@@ -93,31 +124,25 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
93 if (file_id.type != contex_type) { 124 if (file_id.type != contex_type) {
94 continue; 125 continue;
95 } 126 }
96
97 if (file_id.date > start_date) { 127 if (file_id.date > start_date) {
98 continue; 128 continue;
99 } 129 }
100
101 if (file_id.date < end_date) { 130 if (file_id.date < end_date) {
102 continue; 131 continue;
103 } 132 }
104
105 if (out_entries.size() >= SdAlbumFileLimit) { 133 if (out_entries.size() >= SdAlbumFileLimit) {
106 break; 134 break;
107 } 135 }
108 136
109 const auto entry_size = Common::FS::GetSize(path); 137 const auto entry_size = Common::FS::GetSize(path);
110 ApplicationAlbumFileEntry entry{.entry = 138 ApplicationAlbumEntry entry{
111 { 139 .size = entry_size,
112 .size = entry_size, 140 .hash{},
113 .hash{}, 141 .datetime = file_id.date,
114 .datetime = file_id.date, 142 .storage = file_id.storage,
115 .storage = file_id.storage, 143 .content = contex_type,
116 .content = contex_type, 144 .unknown = 1,
117 .unknown = 1, 145 };
118 },
119 .datetime = file_id.date,
120 .unknown = {}};
121 out_entries.push_back(entry); 146 out_entries.push_back(entry);
122 } 147 }
123 148
@@ -274,12 +299,12 @@ Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem:
274 .application_id = static_cast<u64>(std::stoll(application, 0, 16)), 299 .application_id = static_cast<u64>(std::stoll(application, 0, 16)),
275 .date = 300 .date =
276 { 301 {
277 .year = static_cast<u16>(std::stoi(year)), 302 .year = static_cast<s16>(std::stoi(year)),
278 .month = static_cast<u8>(std::stoi(month)), 303 .month = static_cast<s8>(std::stoi(month)),
279 .day = static_cast<u8>(std::stoi(day)), 304 .day = static_cast<s8>(std::stoi(day)),
280 .hour = static_cast<u8>(std::stoi(hour)), 305 .hour = static_cast<s8>(std::stoi(hour)),
281 .minute = static_cast<u8>(std::stoi(minute)), 306 .minute = static_cast<s8>(std::stoi(minute)),
282 .second = static_cast<u8>(std::stoi(second)), 307 .second = static_cast<s8>(std::stoi(second)),
283 .unique_id = 0, 308 .unique_id = 0,
284 }, 309 },
285 .storage = AlbumStorage::Sd, 310 .storage = AlbumStorage::Sd,
@@ -339,4 +364,23 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
339 364
340 return ResultSuccess; 365 return ResultSuccess;
341} 366}
367
368AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
369 Time::TimeZone::CalendarInfo calendar_date{};
370 const auto& time_zone_manager =
371 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
372
373 time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date);
374
375 return {
376 .year = calendar_date.time.year,
377 .month = calendar_date.time.month,
378 .day = calendar_date.time.day,
379 .hour = calendar_date.time.hour,
380 .minute = calendar_date.time.minute,
381 .second = calendar_date.time.second,
382 .unique_id = 0,
383 };
384}
385
342} // namespace Service::Capture 386} // 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 {
37 37
38class AlbumManager { 38class AlbumManager {
39public: 39public:
40 explicit AlbumManager(); 40 explicit AlbumManager(Core::System& system_);
41 ~AlbumManager(); 41 ~AlbumManager();
42 42
43 Result DeleteAlbumFile(const AlbumFileId& file_id); 43 Result DeleteAlbumFile(const AlbumFileId& file_id);
@@ -45,6 +45,9 @@ public:
45 Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, 45 Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
46 u8 flags) const; 46 u8 flags) const;
47 Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, 47 Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
48 ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
49 u64 aruid) const;
50 Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
48 ContentType contex_type, AlbumFileDateTime start_date, 51 ContentType contex_type, AlbumFileDateTime start_date,
49 AlbumFileDateTime end_date, u64 aruid) const; 52 AlbumFileDateTime end_date, u64 aruid) const;
50 Result GetAutoSavingStorage(bool& out_is_autosaving) const; 53 Result GetAutoSavingStorage(bool& out_is_autosaving) const;
@@ -65,8 +68,12 @@ private:
65 Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, 68 Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
66 int height, ScreenShotDecoderFlag flag) const; 69 int height, ScreenShotDecoderFlag flag) const;
67 70
71 AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
72
68 bool is_mounted{}; 73 bool is_mounted{};
69 std::unordered_map<AlbumFileId, std::filesystem::path> album_files; 74 std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
75
76 Core::System& system;
70}; 77};
71 78
72} // namespace Service::Capture 79} // 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 {
41 41
42// This is nn::capsrv::AlbumFileDateTime 42// This is nn::capsrv::AlbumFileDateTime
43struct AlbumFileDateTime { 43struct AlbumFileDateTime {
44 u16 year{}; 44 s16 year{};
45 u8 month{}; 45 s8 month{};
46 u8 day{}; 46 s8 day{};
47 u8 hour{}; 47 s8 hour{};
48 u8 minute{}; 48 s8 minute{};
49 u8 second{}; 49 s8 second{};
50 u8 unique_id{}; 50 s8 unique_id{};
51 51
52 friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default; 52 friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
53 friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { 53 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) {
50 50
51void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) { 51void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
52 IPC::RequestParser rp{ctx}; 52 IPC::RequestParser rp{ctx};
53 const auto pid{rp.Pop<s32>()}; 53 struct Parameters {
54 const auto content_type{rp.PopEnum<ContentType>()}; 54 ContentType content_type;
55 const auto start_posix_time{rp.Pop<s64>()}; 55 INSERT_PADDING_BYTES(7);
56 const auto end_posix_time{rp.Pop<s64>()}; 56 s64 start_posix_time;
57 const auto applet_resource_user_id{rp.Pop<u64>()}; 57 s64 end_posix_time;
58 u64 applet_resource_user_id;
59 };
60 static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
61
62 const auto parameters{rp.PopRaw<Parameters>()};
58 63
59 LOG_WARNING(Service_Capture, 64 LOG_WARNING(Service_Capture,
60 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " 65 "(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, "
61 "end_posix_time={}, applet_resource_user_id={}", 66 "applet_resource_user_id={}",
62 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id); 67 parameters.content_type, parameters.start_posix_time, parameters.end_posix_time,
68 parameters.applet_resource_user_id);
63 69
64 // TODO: Translate posix to DateTime 70 Result result = ResultSuccess;
71
72 if (result.IsSuccess()) {
73 result = manager->IsAlbumMounted(AlbumStorage::Sd);
74 }
65 75
66 std::vector<ApplicationAlbumFileEntry> entries; 76 std::vector<ApplicationAlbumFileEntry> entries;
67 const Result result = 77 if (result.IsSuccess()) {
68 manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id); 78 result = manager->GetAlbumFileList(entries, parameters.content_type,
79 parameters.start_posix_time, parameters.end_posix_time,
80 parameters.applet_resource_user_id);
81 }
69 82
70 if (!entries.empty()) { 83 if (!entries.empty()) {
71 ctx.WriteBuffer(entries); 84 ctx.WriteBuffer(entries);
@@ -78,19 +91,38 @@ void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestCo
78 91
79void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { 92void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx}; 93 IPC::RequestParser rp{ctx};
81 const auto pid{rp.Pop<s32>()}; 94 struct Parameters {
82 const auto content_type{rp.PopEnum<ContentType>()}; 95 ContentType content_type;
83 const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()}; 96 INSERT_PADDING_BYTES(1);
84 const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()}; 97 AlbumFileDateTime start_date_time;
85 const auto applet_resource_user_id{rp.Pop<u64>()}; 98 AlbumFileDateTime end_date_time;
99 INSERT_PADDING_BYTES(6);
100 u64 applet_resource_user_id;
101 };
102 static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
103
104 const auto parameters{rp.PopRaw<Parameters>()};
86 105
87 LOG_WARNING(Service_Capture, 106 LOG_WARNING(Service_Capture,
88 "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid, 107 "(STUBBED) called. content_type={}, start_date={}/{}/{}, "
89 content_type, applet_resource_user_id); 108 "end_date={}/{}/{}, applet_resource_user_id={}",
109 parameters.content_type, parameters.start_date_time.year,
110 parameters.start_date_time.month, parameters.start_date_time.day,
111 parameters.end_date_time.year, parameters.end_date_time.month,
112 parameters.end_date_time.day, parameters.applet_resource_user_id);
90 113
91 std::vector<ApplicationAlbumFileEntry> entries; 114 Result result = ResultSuccess;
92 const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time, 115
93 end_date_time, applet_resource_user_id); 116 if (result.IsSuccess()) {
117 result = manager->IsAlbumMounted(AlbumStorage::Sd);
118 }
119
120 std::vector<ApplicationAlbumEntry> entries;
121 if (result.IsSuccess()) {
122 result =
123 manager->GetAlbumFileList(entries, parameters.content_type, parameters.start_date_time,
124 parameters.end_date_time, parameters.applet_resource_user_id);
125 }
94 126
95 if (!entries.empty()) { 127 if (!entries.empty()) {
96 ctx.WriteBuffer(entries); 128 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) {
1048} 1048}
1049 1049
1050bool Image::ScaleUp(bool ignore) { 1050bool Image::ScaleUp(bool ignore) {
1051 const auto& resolution = runtime->resolution;
1052 if (!resolution.active) {
1053 return false;
1054 }
1051 if (True(flags & ImageFlagBits::Rescaled)) { 1055 if (True(flags & ImageFlagBits::Rescaled)) {
1052 return false; 1056 return false;
1053 } 1057 }
@@ -1060,9 +1064,6 @@ bool Image::ScaleUp(bool ignore) {
1060 return false; 1064 return false;
1061 } 1065 }
1062 flags |= ImageFlagBits::Rescaled; 1066 flags |= ImageFlagBits::Rescaled;
1063 if (!runtime->resolution.active) {
1064 return false;
1065 }
1066 has_scaled = true; 1067 has_scaled = true;
1067 if (ignore) { 1068 if (ignore) {
1068 current_texture = upscaled_backup.handle; 1069 current_texture = upscaled_backup.handle;
@@ -1073,13 +1074,14 @@ bool Image::ScaleUp(bool ignore) {
1073} 1074}
1074 1075
1075bool Image::ScaleDown(bool ignore) { 1076bool Image::ScaleDown(bool ignore) {
1076 if (False(flags & ImageFlagBits::Rescaled)) { 1077 const auto& resolution = runtime->resolution;
1078 if (!resolution.active) {
1077 return false; 1079 return false;
1078 } 1080 }
1079 flags &= ~ImageFlagBits::Rescaled; 1081 if (False(flags & ImageFlagBits::Rescaled)) {
1080 if (!runtime->resolution.active) {
1081 return false; 1082 return false;
1082 } 1083 }
1084 flags &= ~ImageFlagBits::Rescaled;
1083 if (ignore) { 1085 if (ignore) {
1084 current_texture = texture.handle; 1086 current_texture = texture.handle;
1085 return true; 1087 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:
118 118
119 void InsertUploadMemoryBarrier(); 119 void InsertUploadMemoryBarrier();
120 120
121 void TransitionImageLayout(Image& image) {}
122
121 FormatProperties FormatInfo(VideoCommon::ImageType type, GLenum internal_format) const; 123 FormatProperties FormatInfo(VideoCommon::ImageType type, GLenum internal_format) const;
122 124
123 bool HasNativeBgr() const noexcept { 125 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 {
1530} 1530}
1531 1531
1532bool Image::ScaleUp(bool ignore) { 1532bool Image::ScaleUp(bool ignore) {
1533 const auto& resolution = runtime->resolution;
1534 if (!resolution.active) {
1535 return false;
1536 }
1533 if (True(flags & ImageFlagBits::Rescaled)) { 1537 if (True(flags & ImageFlagBits::Rescaled)) {
1534 return false; 1538 return false;
1535 } 1539 }
1536 ASSERT(info.type != ImageType::Linear); 1540 ASSERT(info.type != ImageType::Linear);
1537 flags |= ImageFlagBits::Rescaled; 1541 flags |= ImageFlagBits::Rescaled;
1538 const auto& resolution = runtime->resolution;
1539 if (!resolution.active) {
1540 return false;
1541 }
1542 has_scaled = true; 1542 has_scaled = true;
1543 if (!scaled_image) { 1543 if (!scaled_image) {
1544 const bool is_2d = info.type == ImageType::e2D; 1544 const bool is_2d = info.type == ImageType::e2D;
@@ -1567,15 +1567,15 @@ bool Image::ScaleUp(bool ignore) {
1567} 1567}
1568 1568
1569bool Image::ScaleDown(bool ignore) { 1569bool Image::ScaleDown(bool ignore) {
1570 const auto& resolution = runtime->resolution;
1571 if (!resolution.active) {
1572 return false;
1573 }
1570 if (False(flags & ImageFlagBits::Rescaled)) { 1574 if (False(flags & ImageFlagBits::Rescaled)) {
1571 return false; 1575 return false;
1572 } 1576 }
1573 ASSERT(info.type != ImageType::Linear); 1577 ASSERT(info.type != ImageType::Linear);
1574 flags &= ~ImageFlagBits::Rescaled; 1578 flags &= ~ImageFlagBits::Rescaled;
1575 const auto& resolution = runtime->resolution;
1576 if (!resolution.active) {
1577 return false;
1578 }
1579 current_image = *original_image; 1579 current_image = *original_image;
1580 if (ignore) { 1580 if (ignore) {
1581 return true; 1581 return true;
@@ -2013,4 +2013,32 @@ void TextureCacheRuntime::AccelerateImageUpload(
2013 ASSERT(false); 2013 ASSERT(false);
2014} 2014}
2015 2015
2016void TextureCacheRuntime::TransitionImageLayout(Image& image) {
2017 if (!image.ExchangeInitialization()) {
2018 VkImageMemoryBarrier barrier{
2019 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2020 .pNext = nullptr,
2021 .srcAccessMask = VK_ACCESS_NONE,
2022 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2023 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2024 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
2025 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2026 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2027 .image = image.Handle(),
2028 .subresourceRange{
2029 .aspectMask = image.AspectMask(),
2030 .baseMipLevel = 0,
2031 .levelCount = VK_REMAINING_MIP_LEVELS,
2032 .baseArrayLayer = 0,
2033 .layerCount = VK_REMAINING_ARRAY_LAYERS,
2034 },
2035 };
2036 scheduler.RequestOutsideRenderPassOperationContext();
2037 scheduler.Record([barrier = barrier](vk::CommandBuffer cmdbuf) {
2038 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2039 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
2040 });
2041 }
2042}
2043
2016} // namespace Vulkan 2044} // 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:
92 92
93 void InsertUploadMemoryBarrier() {} 93 void InsertUploadMemoryBarrier() {}
94 94
95 void TransitionImageLayout(Image& image);
96
95 bool HasBrokenTextureViewFormats() const noexcept { 97 bool HasBrokenTextureViewFormats() const noexcept {
96 // No known Vulkan driver has broken image views 98 // No known Vulkan driver has broken image views
97 return false; 99 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) {
1016 1016
1017 if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) { 1017 if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) {
1018 LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); 1018 LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented");
1019 runtime.TransitionImageLayout(image);
1019 return; 1020 return;
1020 } 1021 }
1021 if (True(image.flags & ImageFlagBits::AsynchronousDecode)) { 1022 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) {
63 }; 63 };
64#pragma pack(pop) 64#pragma pack(pop)
65 65
66 QImage source_image = image.convertToFormat(QImage::Format_RGB32); 66 const QImage source_image = image.convertToFormat(QImage::Format_RGB32);
67 constexpr std::array<int, 7> scale_sizes{256, 128, 64, 48, 32, 24, 16};
67 constexpr int bytes_per_pixel = 4; 68 constexpr int bytes_per_pixel = 4;
68 const int image_size = source_image.width() * source_image.height() * bytes_per_pixel; 69
69 70 const IconDir icon_dir{
70 BITMAPINFOHEADER info_header{}; 71 .id_reserved = 0,
71 info_header.biSize = sizeof(BITMAPINFOHEADER), info_header.biWidth = source_image.width(), 72 .id_type = 1,
72 info_header.biHeight = source_image.height() * 2, info_header.biPlanes = 1, 73 .id_count = static_cast<WORD>(scale_sizes.size()),
73 info_header.biBitCount = bytes_per_pixel * 8, info_header.biCompression = BI_RGB; 74 };
74
75 const IconDir icon_dir{.id_reserved = 0, .id_type = 1, .id_count = 1};
76 const IconDirEntry icon_entry{.width = static_cast<BYTE>(source_image.width()),
77 .height = static_cast<BYTE>(source_image.height() * 2),
78 .color_count = 0,
79 .reserved = 0,
80 .planes = 1,
81 .bit_count = bytes_per_pixel * 8,
82 .bytes_in_res =
83 static_cast<DWORD>(sizeof(BITMAPINFOHEADER) + image_size),
84 .image_offset = sizeof(IconDir) + sizeof(IconDirEntry)};
85 75
86 Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write, 76 Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write,
87 Common::FS::FileType::BinaryFile); 77 Common::FS::FileType::BinaryFile);
@@ -92,20 +82,55 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
92 if (!icon_file.Write(icon_dir)) { 82 if (!icon_file.Write(icon_dir)) {
93 return false; 83 return false;
94 } 84 }
95 if (!icon_file.Write(icon_entry)) { 85
96 return false; 86 std::size_t image_offset = sizeof(IconDir) + (sizeof(IconDirEntry) * scale_sizes.size());
97 } 87 for (std::size_t i = 0; i < scale_sizes.size(); i++) {
98 if (!icon_file.Write(info_header)) { 88 const int image_size = scale_sizes[i] * scale_sizes[i] * bytes_per_pixel;
99 return false; 89 const IconDirEntry icon_entry{
90 .width = static_cast<BYTE>(scale_sizes[i]),
91 .height = static_cast<BYTE>(scale_sizes[i]),
92 .color_count = 0,
93 .reserved = 0,
94 .planes = 1,
95 .bit_count = bytes_per_pixel * 8,
96 .bytes_in_res = static_cast<DWORD>(sizeof(BITMAPINFOHEADER) + image_size),
97 .image_offset = static_cast<DWORD>(image_offset),
98 };
99 image_offset += icon_entry.bytes_in_res;
100 if (!icon_file.Write(icon_entry)) {
101 return false;
102 }
100 } 103 }
101 104
102 for (int y = 0; y < image.height(); y++) { 105 for (std::size_t i = 0; i < scale_sizes.size(); i++) {
103 const auto* line = source_image.scanLine(source_image.height() - 1 - y); 106 const QImage scaled_image = source_image.scaled(
104 std::vector<u8> line_data(source_image.width() * bytes_per_pixel); 107 scale_sizes[i], scale_sizes[i], Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
105 std::memcpy(line_data.data(), line, line_data.size()); 108 const BITMAPINFOHEADER info_header{
106 if (!icon_file.Write(line_data)) { 109 .biSize = sizeof(BITMAPINFOHEADER),
110 .biWidth = scaled_image.width(),
111 .biHeight = scaled_image.height() * 2,
112 .biPlanes = 1,
113 .biBitCount = bytes_per_pixel * 8,
114 .biCompression = BI_RGB,
115 .biSizeImage{},
116 .biXPelsPerMeter{},
117 .biYPelsPerMeter{},
118 .biClrUsed{},
119 .biClrImportant{},
120 };
121
122 if (!icon_file.Write(info_header)) {
107 return false; 123 return false;
108 } 124 }
125
126 for (int y = 0; y < scaled_image.height(); y++) {
127 const auto* line = scaled_image.scanLine(scaled_image.height() - 1 - y);
128 std::vector<u8> line_data(scaled_image.width() * bytes_per_pixel);
129 std::memcpy(line_data.data(), line, line_data.size());
130 if (!icon_file.Write(line_data)) {
131 return false;
132 }
133 }
109 } 134 }
110 icon_file.Close(); 135 icon_file.Close();
111 136