summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp9
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.h2
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h46
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp16
-rw-r--r--src/video_core/texture_cache/util.cpp41
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/yuzu/applets/qt_controller.cpp39
-rw-r--r--src/yuzu/applets/qt_controller.h6
-rw-r--r--src/yuzu/applets/qt_controller.ui54
10 files changed, 167 insertions, 68 deletions
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
index 972d5e45b..ef301d8b4 100644
--- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
@@ -77,6 +77,7 @@ void AudioRenderer::Wait() {
77 "{}, got {}", 77 "{}, got {}",
78 Message::RenderResponse, msg); 78 Message::RenderResponse, msg);
79 } 79 }
80 PostDSPClearCommandBuffer();
80} 81}
81 82
82void AudioRenderer::Send(Direction dir, u32 message) { 83void AudioRenderer::Send(Direction dir, u32 message) {
@@ -96,6 +97,14 @@ void AudioRenderer::SetCommandBuffer(s32 session_id, CpuAddr buffer, u64 size, u
96 command_buffers[session_id].reset_buffer = reset; 97 command_buffers[session_id].reset_buffer = reset;
97} 98}
98 99
100void AudioRenderer::PostDSPClearCommandBuffer() noexcept {
101 for (auto& buffer : command_buffers) {
102 buffer.buffer = 0;
103 buffer.size = 0;
104 buffer.reset_buffer = false;
105 }
106}
107
99u32 AudioRenderer::GetRemainCommandCount(s32 session_id) const noexcept { 108u32 AudioRenderer::GetRemainCommandCount(s32 session_id) const noexcept {
100 return command_buffers[session_id].remaining_command_count; 109 return command_buffers[session_id].remaining_command_count;
101} 110}
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
index 85874d88a..57b89d9fe 100644
--- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
@@ -85,6 +85,8 @@ private:
85 */ 85 */
86 void CreateSinkStreams(); 86 void CreateSinkStreams();
87 87
88 void PostDSPClearCommandBuffer() noexcept;
89
88 /// Core system 90 /// Core system
89 Core::System& system; 91 Core::System& system;
90 /// The output sink the AudioRenderer will send samples to 92 /// The output sink the AudioRenderer will send samples to
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 9e90c587c..9b2698fad 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -544,7 +544,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
544 it++; 544 it++;
545 } 545 }
546 546
547 boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads; 547 boost::container::small_vector<std::pair<BufferCopy, BufferId>, 16> downloads;
548 u64 total_size_bytes = 0; 548 u64 total_size_bytes = 0;
549 u64 largest_copy = 0; 549 u64 largest_copy = 0;
550 for (const IntervalSet& intervals : committed_ranges) { 550 for (const IntervalSet& intervals : committed_ranges) {
@@ -914,6 +914,11 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
914 914
915 const u32 offset = buffer.Offset(binding.cpu_addr); 915 const u32 offset = buffer.Offset(binding.cpu_addr);
916 const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; 916 const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
917
918 if (is_written) {
919 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
920 }
921
917 if constexpr (NEEDS_BIND_STORAGE_INDEX) { 922 if constexpr (NEEDS_BIND_STORAGE_INDEX) {
918 runtime.BindStorageBuffer(stage, binding_index, buffer, offset, size, is_written); 923 runtime.BindStorageBuffer(stage, binding_index, buffer, offset, size, is_written);
919 ++binding_index; 924 ++binding_index;
@@ -931,6 +936,11 @@ void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) {
931 const u32 size = binding.size; 936 const u32 size = binding.size;
932 SynchronizeBuffer(buffer, binding.cpu_addr, size); 937 SynchronizeBuffer(buffer, binding.cpu_addr, size);
933 938
939 const bool is_written = ((channel_state->written_texture_buffers[stage] >> index) & 1) != 0;
940 if (is_written) {
941 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
942 }
943
934 const u32 offset = buffer.Offset(binding.cpu_addr); 944 const u32 offset = buffer.Offset(binding.cpu_addr);
935 const PixelFormat format = binding.format; 945 const PixelFormat format = binding.format;
936 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { 946 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@@ -962,6 +972,8 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
962 const u32 size = binding.size; 972 const u32 size = binding.size;
963 SynchronizeBuffer(buffer, binding.cpu_addr, size); 973 SynchronizeBuffer(buffer, binding.cpu_addr, size);
964 974
975 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
976
965 const u32 offset = buffer.Offset(binding.cpu_addr); 977 const u32 offset = buffer.Offset(binding.cpu_addr);
966 host_bindings.buffers.push_back(&buffer); 978 host_bindings.buffers.push_back(&buffer);
967 host_bindings.offsets.push_back(offset); 979 host_bindings.offsets.push_back(offset);
@@ -1011,6 +1023,11 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
1011 const u32 offset = buffer.Offset(binding.cpu_addr); 1023 const u32 offset = buffer.Offset(binding.cpu_addr);
1012 const bool is_written = 1024 const bool is_written =
1013 ((channel_state->written_compute_storage_buffers >> index) & 1) != 0; 1025 ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
1026
1027 if (is_written) {
1028 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
1029 }
1030
1014 if constexpr (NEEDS_BIND_STORAGE_INDEX) { 1031 if constexpr (NEEDS_BIND_STORAGE_INDEX) {
1015 runtime.BindComputeStorageBuffer(binding_index, buffer, offset, size, is_written); 1032 runtime.BindComputeStorageBuffer(binding_index, buffer, offset, size, is_written);
1016 ++binding_index; 1033 ++binding_index;
@@ -1028,6 +1045,12 @@ void BufferCache<P>::BindHostComputeTextureBuffers() {
1028 const u32 size = binding.size; 1045 const u32 size = binding.size;
1029 SynchronizeBuffer(buffer, binding.cpu_addr, size); 1046 SynchronizeBuffer(buffer, binding.cpu_addr, size);
1030 1047
1048 const bool is_written =
1049 ((channel_state->written_compute_texture_buffers >> index) & 1) != 0;
1050 if (is_written) {
1051 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
1052 }
1053
1031 const u32 offset = buffer.Offset(binding.cpu_addr); 1054 const u32 offset = buffer.Offset(binding.cpu_addr);
1032 const PixelFormat format = binding.format; 1055 const PixelFormat format = binding.format;
1033 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { 1056 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@@ -1201,16 +1224,11 @@ void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
1201 1224
1202template <class P> 1225template <class P>
1203void BufferCache<P>::UpdateStorageBuffers(size_t stage) { 1226void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
1204 const u32 written_mask = channel_state->written_storage_buffers[stage];
1205 ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) { 1227 ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
1206 // Resolve buffer 1228 // Resolve buffer
1207 Binding& binding = channel_state->storage_buffers[stage][index]; 1229 Binding& binding = channel_state->storage_buffers[stage][index];
1208 const BufferId buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1230 const BufferId buffer_id = FindBuffer(binding.cpu_addr, binding.size);
1209 binding.buffer_id = buffer_id; 1231 binding.buffer_id = buffer_id;
1210 // Mark buffer as written if needed
1211 if (((written_mask >> index) & 1) != 0) {
1212 MarkWrittenBuffer(buffer_id, binding.cpu_addr, binding.size);
1213 }
1214 }); 1232 });
1215} 1233}
1216 1234
@@ -1219,10 +1237,6 @@ void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
1219 ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) { 1237 ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
1220 Binding& binding = channel_state->texture_buffers[stage][index]; 1238 Binding& binding = channel_state->texture_buffers[stage][index];
1221 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1239 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
1222 // Mark buffer as written if needed
1223 if (((channel_state->written_texture_buffers[stage] >> index) & 1) != 0) {
1224 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
1225 }
1226 }); 1240 });
1227} 1241}
1228 1242
@@ -1252,7 +1266,6 @@ void BufferCache<P>::UpdateTransformFeedbackBuffer(u32 index) {
1252 .size = size, 1266 .size = size,
1253 .buffer_id = buffer_id, 1267 .buffer_id = buffer_id,
1254 }; 1268 };
1255 MarkWrittenBuffer(buffer_id, *cpu_addr, size);
1256} 1269}
1257 1270
1258template <class P> 1271template <class P>
@@ -1279,10 +1292,6 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
1279 // Resolve buffer 1292 // Resolve buffer
1280 Binding& binding = channel_state->compute_storage_buffers[index]; 1293 Binding& binding = channel_state->compute_storage_buffers[index];
1281 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1294 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
1282 // Mark as written if needed
1283 if (((channel_state->written_compute_storage_buffers >> index) & 1) != 0) {
1284 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
1285 }
1286 }); 1295 });
1287} 1296}
1288 1297
@@ -1291,18 +1300,11 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
1291 ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) { 1300 ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
1292 Binding& binding = channel_state->compute_texture_buffers[index]; 1301 Binding& binding = channel_state->compute_texture_buffers[index];
1293 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1302 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
1294 // Mark as written if needed
1295 if (((channel_state->written_compute_texture_buffers >> index) & 1) != 0) {
1296 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
1297 }
1298 }); 1303 });
1299} 1304}
1300 1305
1301template <class P> 1306template <class P>
1302void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { 1307void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
1303 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
1304 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
1305 }
1306 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size); 1308 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1307 1309
1308 const IntervalType base_interval{cpu_addr, cpu_addr + size}; 1310 const IntervalType base_interval{cpu_addr, cpu_addr + size};
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_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 00ab47268..1b8bb9662 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;
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 0a86ce139..8151cabf0 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -68,6 +68,7 @@ struct LevelInfo {
68 Extent2D tile_size; 68 Extent2D tile_size;
69 u32 bpp_log2; 69 u32 bpp_log2;
70 u32 tile_width_spacing; 70 u32 tile_width_spacing;
71 u32 num_levels;
71}; 72};
72 73
73[[nodiscard]] constexpr u32 AdjustTileSize(u32 shift, u32 unit_factor, u32 dimension) { 74[[nodiscard]] constexpr u32 AdjustTileSize(u32 shift, u32 unit_factor, u32 dimension) {
@@ -118,11 +119,11 @@ template <u32 GOB_EXTENT>
118} 119}
119 120
120[[nodiscard]] constexpr Extent3D AdjustMipBlockSize(Extent3D num_tiles, Extent3D block_size, 121[[nodiscard]] constexpr Extent3D AdjustMipBlockSize(Extent3D num_tiles, Extent3D block_size,
121 u32 level) { 122 u32 level, u32 num_levels) {
122 return { 123 return {
123 .width = AdjustMipBlockSize<GOB_SIZE_X>(num_tiles.width, block_size.width, level), 124 .width = AdjustMipBlockSize<GOB_SIZE_X>(num_tiles.width, block_size.width, level),
124 .height = AdjustMipBlockSize<GOB_SIZE_Y>(num_tiles.height, block_size.height, level), 125 .height = AdjustMipBlockSize<GOB_SIZE_Y>(num_tiles.height, block_size.height, level),
125 .depth = level == 0 126 .depth = level == 0 && num_levels == 1
126 ? block_size.depth 127 ? block_size.depth
127 : AdjustMipBlockSize<GOB_SIZE_Z>(num_tiles.depth, block_size.depth, level), 128 : AdjustMipBlockSize<GOB_SIZE_Z>(num_tiles.depth, block_size.depth, level),
128 }; 129 };
@@ -166,13 +167,6 @@ template <u32 GOB_EXTENT>
166} 167}
167 168
168[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) { 169[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) {
169 if (level == 0) {
170 return Extent3D{
171 .width = info.block.width,
172 .height = info.block.height,
173 .depth = info.block.depth,
174 };
175 }
176 const Extent3D blocks = NumLevelBlocks(info, level); 170 const Extent3D blocks = NumLevelBlocks(info, level);
177 return Extent3D{ 171 return Extent3D{
178 .width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width), 172 .width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width),
@@ -257,7 +251,7 @@ template <u32 GOB_EXTENT>
257} 251}
258 252
259[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block, 253[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
260 u32 tile_width_spacing) { 254 u32 tile_width_spacing, u32 num_levels) {
261 const u32 bytes_per_block = BytesPerBlock(format); 255 const u32 bytes_per_block = BytesPerBlock(format);
262 return { 256 return {
263 .size = 257 .size =
@@ -270,16 +264,18 @@ template <u32 GOB_EXTENT>
270 .tile_size = DefaultBlockSize(format), 264 .tile_size = DefaultBlockSize(format),
271 .bpp_log2 = BytesPerBlockLog2(bytes_per_block), 265 .bpp_log2 = BytesPerBlockLog2(bytes_per_block),
272 .tile_width_spacing = tile_width_spacing, 266 .tile_width_spacing = tile_width_spacing,
267 .num_levels = num_levels,
273 }; 268 };
274} 269}
275 270
276[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) { 271[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
277 return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing); 272 return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing,
273 info.resources.levels);
278} 274}
279 275
280[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block, 276[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
281 u32 tile_width_spacing, u32 level) { 277 u32 tile_width_spacing, u32 level) {
282 const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing); 278 const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing, level);
283 u32 offset = 0; 279 u32 offset = 0;
284 for (u32 current_level = 0; current_level < level; ++current_level) { 280 for (u32 current_level = 0; current_level < level; ++current_level) {
285 offset += CalculateLevelSize(info, current_level); 281 offset += CalculateLevelSize(info, current_level);
@@ -466,7 +462,7 @@ template <u32 GOB_EXTENT>
466 }; 462 };
467 const u32 bpp_log2 = BytesPerBlockLog2(info.format); 463 const u32 bpp_log2 = BytesPerBlockLog2(info.format);
468 const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing); 464 const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
469 const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0); 465 const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0, info.resources.levels);
470 return Extent3D{ 466 return Extent3D{
471 .width = Common::AlignUpLog2(num_tiles.width, alignment), 467 .width = Common::AlignUpLog2(num_tiles.width, alignment),
472 .height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), 468 .height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
@@ -533,7 +529,8 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
533 UNIMPLEMENTED_IF(copy.image_extent != level_size); 529 UNIMPLEMENTED_IF(copy.image_extent != level_size);
534 530
535 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); 531 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
536 const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level); 532 const Extent3D block =
533 AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
537 534
538 size_t host_offset = copy.buffer_offset; 535 size_t host_offset = copy.buffer_offset;
539 536
@@ -698,7 +695,7 @@ u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level) {
698 const Extent2D tile_size = DefaultBlockSize(info.format); 695 const Extent2D tile_size = DefaultBlockSize(info.format);
699 const Extent3D level_size = AdjustMipSize(info.size, level); 696 const Extent3D level_size = AdjustMipSize(info.size, level);
700 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); 697 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
701 const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level); 698 const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level, info.resources.levels);
702 const u32 bpp_log2 = BytesPerBlockLog2(info.format); 699 const u32 bpp_log2 = BytesPerBlockLog2(info.format);
703 return StrideAlignment(num_tiles, block, bpp_log2, info.tile_width_spacing); 700 return StrideAlignment(num_tiles, block, bpp_log2, info.tile_width_spacing);
704} 701}
@@ -887,7 +884,8 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
887 .image_extent = level_size, 884 .image_extent = level_size,
888 }; 885 };
889 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); 886 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
890 const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level); 887 const Extent3D block =
888 AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
891 const u32 stride_alignment = StrideAlignment(num_tiles, info.block, gob, bpp_log2); 889 const u32 stride_alignment = StrideAlignment(num_tiles, info.block, gob, bpp_log2);
892 size_t guest_layer_offset = 0; 890 size_t guest_layer_offset = 0;
893 891
@@ -1041,7 +1039,7 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) {
1041 const Extent2D tile_size = DefaultBlockSize(info.format); 1039 const Extent2D tile_size = DefaultBlockSize(info.format);
1042 const Extent3D level_size = AdjustMipSize(info.size, level); 1040 const Extent3D level_size = AdjustMipSize(info.size, level);
1043 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); 1041 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
1044 return AdjustMipBlockSize(num_tiles, level_info.block, level); 1042 return AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
1045} 1043}
1046 1044
1047boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) { 1045boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) {
@@ -1063,7 +1061,8 @@ boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const I
1063 for (s32 level = 0; level < num_levels; ++level) { 1061 for (s32 level = 0; level < num_levels; ++level) {
1064 const Extent3D level_size = AdjustMipSize(size, level); 1062 const Extent3D level_size = AdjustMipSize(size, level);
1065 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); 1063 const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
1066 const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level); 1064 const Extent3D block =
1065 AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
1067 params[level] = SwizzleParameters{ 1066 params[level] = SwizzleParameters{
1068 .num_tiles = num_tiles, 1067 .num_tiles = num_tiles,
1069 .block = block, 1068 .block = block,
@@ -1292,11 +1291,11 @@ u32 MapSizeBytes(const ImageBase& image) {
1292 } 1291 }
1293} 1292}
1294 1293
1295static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0}, 0) == 1294static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0, 1}, 0) ==
1296 0x7f8000); 1295 0x7f8000);
1297static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x40000); 1296static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
1298 1297
1299static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0}, 0) == 0x40000); 1298static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
1300 1299
1301static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) == 1300static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
1302 0x2afc00); 1301 0x2afc00);
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 82767fdf0..8dd1667f3 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -66,9 +66,10 @@ struct Range {
66 switch (usage) { 66 switch (usage) {
67 case MemoryUsage::Upload: 67 case MemoryUsage::Upload:
68 case MemoryUsage::Stream: 68 case MemoryUsage::Stream:
69 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; 69 return VMA_ALLOCATION_CREATE_MAPPED_BIT |
70 VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
70 case MemoryUsage::Download: 71 case MemoryUsage::Download:
71 return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; 72 return VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
72 case MemoryUsage::DeviceLocal: 73 case MemoryUsage::DeviceLocal:
73 return {}; 74 return {};
74 } 75 }
@@ -252,8 +253,7 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
252 253
253vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { 254vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
254 const VmaAllocationCreateInfo alloc_ci = { 255 const VmaAllocationCreateInfo alloc_ci = {
255 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | 256 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
256 MemoryUsageVmaFlags(usage),
257 .usage = MemoryUsageVma(usage), 257 .usage = MemoryUsageVma(usage),
258 .requiredFlags = 0, 258 .requiredFlags = 0,
259 .preferredFlags = MemoryUsagePreferedVmaFlags(usage), 259 .preferredFlags = MemoryUsagePreferedVmaFlags(usage),
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index d15559518..ca0e14fad 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -23,6 +23,7 @@
23#include "yuzu/configuration/configure_vibration.h" 23#include "yuzu/configuration/configure_vibration.h"
24#include "yuzu/configuration/input_profiles.h" 24#include "yuzu/configuration/input_profiles.h"
25#include "yuzu/main.h" 25#include "yuzu/main.h"
26#include "yuzu/util/controller_navigation.h"
26 27
27namespace { 28namespace {
28 29
@@ -132,6 +133,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
132 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected, 133 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
133 }; 134 };
134 135
136 ui->labelError->setVisible(false);
137
135 // Setup/load everything prior to setting up connections. 138 // Setup/load everything prior to setting up connections.
136 // This avoids unintentionally changing the states of elements while loading them in. 139 // This avoids unintentionally changing the states of elements while loading them in.
137 SetSupportedControllers(); 140 SetSupportedControllers();
@@ -143,6 +146,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
143 146
144 LoadConfiguration(); 147 LoadConfiguration();
145 148
149 controller_navigation = new ControllerNavigation(system.HIDCore(), this);
150
146 for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { 151 for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
147 SetExplainText(i); 152 SetExplainText(i);
148 UpdateControllerIcon(i); 153 UpdateControllerIcon(i);
@@ -151,6 +156,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
151 156
152 connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) { 157 connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
153 if (checked) { 158 if (checked) {
159 // Hide eventual error message about number of controllers
160 ui->labelError->setVisible(false);
154 for (std::size_t index = 0; index <= i; ++index) { 161 for (std::size_t index = 0; index <= i; ++index) {
155 connected_controller_checkboxes[index]->setChecked(checked); 162 connected_controller_checkboxes[index]->setChecked(checked);
156 } 163 }
@@ -199,6 +206,12 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
199 connect(ui->buttonBox, &QDialogButtonBox::accepted, this, 206 connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
200 &QtControllerSelectorDialog::ApplyConfiguration); 207 &QtControllerSelectorDialog::ApplyConfiguration);
201 208
209 connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
210 [this](Qt::Key key) {
211 QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
212 QCoreApplication::postEvent(this, event);
213 });
214
202 // Enhancement: Check if the parameters have already been met before disconnecting controllers. 215 // Enhancement: Check if the parameters have already been met before disconnecting controllers.
203 // If all the parameters are met AND only allows a single player, 216 // If all the parameters are met AND only allows a single player,
204 // stop the constructor here as we do not need to continue. 217 // stop the constructor here as we do not need to continue.
@@ -217,6 +230,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
217} 230}
218 231
219QtControllerSelectorDialog::~QtControllerSelectorDialog() { 232QtControllerSelectorDialog::~QtControllerSelectorDialog() {
233 controller_navigation->UnloadController();
220 system.HIDCore().DisableAllControllerConfiguration(); 234 system.HIDCore().DisableAllControllerConfiguration();
221} 235}
222 236
@@ -291,6 +305,31 @@ void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
291 dialog.exec(); 305 dialog.exec();
292} 306}
293 307
308void QtControllerSelectorDialog::keyPressEvent(QKeyEvent* evt) {
309 const auto num_connected_players = static_cast<int>(
310 std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
311 [](const QGroupBox* player) { return player->isChecked(); }));
312
313 const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
314 const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
315
316 if ((evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) && !parameters_met) {
317 // Display error message when trying to validate using "Enter" and "OK" button is disabled
318 ui->labelError->setVisible(true);
319 return;
320 } else if (evt->key() == Qt::Key_Left && num_connected_players > min_supported_players) {
321 // Remove a player if possible
322 connected_controller_checkboxes[num_connected_players - 1]->setChecked(false);
323 return;
324 } else if (evt->key() == Qt::Key_Right && num_connected_players < max_supported_players) {
325 // Add a player, if possible
326 ui->labelError->setVisible(false);
327 connected_controller_checkboxes[num_connected_players]->setChecked(true);
328 return;
329 }
330 QDialog::keyPressEvent(evt);
331}
332
294bool QtControllerSelectorDialog::CheckIfParametersMet() { 333bool QtControllerSelectorDialog::CheckIfParametersMet() {
295 // Here, we check and validate the current configuration against all applicable parameters. 334 // Here, we check and validate the current configuration against all applicable parameters.
296 const auto num_connected_players = static_cast<int>( 335 const auto num_connected_players = static_cast<int>(
diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h
index 2fdc35857..7f0673d06 100644
--- a/src/yuzu/applets/qt_controller.h
+++ b/src/yuzu/applets/qt_controller.h
@@ -34,6 +34,8 @@ class HIDCore;
34enum class NpadStyleIndex : u8; 34enum class NpadStyleIndex : u8;
35} // namespace Core::HID 35} // namespace Core::HID
36 36
37class ControllerNavigation;
38
37class QtControllerSelectorDialog final : public QDialog { 39class QtControllerSelectorDialog final : public QDialog {
38 Q_OBJECT 40 Q_OBJECT
39 41
@@ -46,6 +48,8 @@ public:
46 48
47 int exec() override; 49 int exec() override;
48 50
51 void keyPressEvent(QKeyEvent* evt) override;
52
49private: 53private:
50 // Applies the current configuration. 54 // Applies the current configuration.
51 void ApplyConfiguration(); 55 void ApplyConfiguration();
@@ -110,6 +114,8 @@ private:
110 114
111 Core::System& system; 115 Core::System& system;
112 116
117 ControllerNavigation* controller_navigation = nullptr;
118
113 // This is true if and only if all parameters are met. Otherwise, this is false. 119 // This is true if and only if all parameters are met. Otherwise, this is false.
114 // This determines whether the "OK" button can be clicked to exit the applet. 120 // This determines whether the "OK" button can be clicked to exit the applet.
115 bool parameters_met{false}; 121 bool parameters_met{false};
diff --git a/src/yuzu/applets/qt_controller.ui b/src/yuzu/applets/qt_controller.ui
index 729e921ee..6f7cb3c13 100644
--- a/src/yuzu/applets/qt_controller.ui
+++ b/src/yuzu/applets/qt_controller.ui
@@ -2624,13 +2624,53 @@
2624 </spacer> 2624 </spacer>
2625 </item> 2625 </item>
2626 <item alignment="Qt::AlignBottom"> 2626 <item alignment="Qt::AlignBottom">
2627 <widget class="QDialogButtonBox" name="buttonBox"> 2627 <widget class="QWidget" name="closeButtons" native="true">
2628 <property name="enabled"> 2628 <layout class="QVBoxLayout" name="verticalLayout_46">
2629 <bool>true</bool> 2629 <property name="spacing">
2630 </property> 2630 <number>7</number>
2631 <property name="standardButtons"> 2631 </property>
2632 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> 2632 <property name="leftMargin">
2633 </property> 2633 <number>0</number>
2634 </property>
2635 <property name="topMargin">
2636 <number>0</number>
2637 </property>
2638 <property name="rightMargin">
2639 <number>0</number>
2640 </property>
2641 <property name="bottomMargin">
2642 <number>0</number>
2643 </property>
2644 <item>
2645 <widget class="QLabel" name="labelError">
2646 <property name="enabled">
2647 <bool>true</bool>
2648 </property>
2649 <property name="styleSheet">
2650 <string notr="true">QLabel { color : red; }</string>
2651 </property>
2652 <property name="text">
2653 <string>Not enough controllers</string>
2654 </property>
2655 <property name="alignment">
2656 <set>Qt::AlignCenter</set>
2657 </property>
2658 <property name="margin">
2659 <number>0</number>
2660 </property>
2661 </widget>
2662 </item>
2663 <item>
2664 <widget class="QDialogButtonBox" name="buttonBox">
2665 <property name="enabled">
2666 <bool>true</bool>
2667 </property>
2668 <property name="standardButtons">
2669 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
2670 </property>
2671 </widget>
2672 </item>
2673 </layout>
2634 </widget> 2674 </widget>
2635 </item> 2675 </item>
2636 </layout> 2676 </layout>