summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/uuid.h11
-rw-r--r--src/core/memory.cpp552
-rw-r--r--src/core/memory.h102
-rw-r--r--src/input_common/main.cpp8
-rw-r--r--src/input_common/mouse/mouse_poller.cpp1
-rw-r--r--src/input_common/sdl/sdl_impl.cpp87
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp4
-rw-r--r--src/video_core/command_classes/codecs/vp9_types.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h2
-rw-r--r--src/yuzu/configuration/configure_general.ui60
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui7
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp13
-rw-r--r--src/yuzu_cmd/CMakeLists.txt1
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp1
15 files changed, 298 insertions, 561 deletions
diff --git a/src/common/uuid.h b/src/common/uuid.h
index aeb36939a..2353179d8 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -69,3 +69,14 @@ struct UUID {
69static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 69static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
70 70
71} // namespace Common 71} // namespace Common
72
73namespace std {
74
75template <>
76struct hash<Common::UUID> {
77 size_t operator()(const Common::UUID& uuid) const noexcept {
78 return uuid.uuid[1] ^ uuid.uuid[0];
79 }
80};
81
82} // namespace std
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index f285c6f63..51c4dea26 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,8 +4,6 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <optional>
8#include <utility>
9 7
10#include "common/assert.h" 8#include "common/assert.h"
11#include "common/atomic_ops.h" 9#include "common/atomic_ops.h"
@@ -14,12 +12,10 @@
14#include "common/page_table.h" 12#include "common/page_table.h"
15#include "common/settings.h" 13#include "common/settings.h"
16#include "common/swap.h" 14#include "common/swap.h"
17#include "core/arm/arm_interface.h"
18#include "core/core.h" 15#include "core/core.h"
19#include "core/device_memory.h" 16#include "core/device_memory.h"
20#include "core/hle/kernel/k_page_table.h" 17#include "core/hle/kernel/k_page_table.h"
21#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
22#include "core/hle/kernel/physical_memory.h"
23#include "core/memory.h" 19#include "core/memory.h"
24#include "video_core/gpu.h" 20#include "video_core/gpu.h"
25 21
@@ -62,17 +58,7 @@ struct Memory::Impl {
62 } 58 }
63 } 59 }
64 60
65 bool IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const { 61 [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(VAddr vaddr) const {
66 const auto& page_table = process.PageTable().PageTableImpl();
67 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType();
68 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
69 }
70
71 bool IsValidVirtualAddress(VAddr vaddr) const {
72 return IsValidVirtualAddress(*system.CurrentProcess(), vaddr);
73 }
74
75 u8* GetPointerFromRasterizerCachedMemory(VAddr vaddr) const {
76 const PAddr paddr{current_page_table->backing_addr[vaddr >> PAGE_BITS]}; 62 const PAddr paddr{current_page_table->backing_addr[vaddr >> PAGE_BITS]};
77 63
78 if (!paddr) { 64 if (!paddr) {
@@ -82,18 +68,6 @@ struct Memory::Impl {
82 return system.DeviceMemory().GetPointer(paddr) + vaddr; 68 return system.DeviceMemory().GetPointer(paddr) + vaddr;
83 } 69 }
84 70
85 u8* GetPointer(const VAddr vaddr) const {
86 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
87 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
88 return pointer + vaddr;
89 }
90 const auto type = Common::PageTable::PageInfo::ExtractType(raw_pointer);
91 if (type == Common::PageType::RasterizerCachedMemory) {
92 return GetPointerFromRasterizerCachedMemory(vaddr);
93 }
94 return nullptr;
95 }
96
97 u8 Read8(const VAddr addr) { 71 u8 Read8(const VAddr addr) {
98 return Read<u8>(addr); 72 return Read<u8>(addr);
99 } 73 }
@@ -179,7 +153,7 @@ struct Memory::Impl {
179 std::string string; 153 std::string string;
180 string.reserve(max_length); 154 string.reserve(max_length);
181 for (std::size_t i = 0; i < max_length; ++i) { 155 for (std::size_t i = 0; i < max_length; ++i) {
182 const char c = Read8(vaddr); 156 const char c = Read<s8>(vaddr);
183 if (c == '\0') { 157 if (c == '\0') {
184 break; 158 break;
185 } 159 }
@@ -190,15 +164,14 @@ struct Memory::Impl {
190 return string; 164 return string;
191 } 165 }
192 166
193 void ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, 167 void WalkBlock(const Kernel::KProcess& process, const VAddr addr, const std::size_t size,
194 const std::size_t size) { 168 auto on_unmapped, auto on_memory, auto on_rasterizer, auto increment) {
195 const auto& page_table = process.PageTable().PageTableImpl(); 169 const auto& page_table = process.PageTable().PageTableImpl();
196
197 std::size_t remaining_size = size; 170 std::size_t remaining_size = size;
198 std::size_t page_index = src_addr >> PAGE_BITS; 171 std::size_t page_index = addr >> PAGE_BITS;
199 std::size_t page_offset = src_addr & PAGE_MASK; 172 std::size_t page_offset = addr & PAGE_MASK;
200 173
201 while (remaining_size > 0) { 174 while (remaining_size) {
202 const std::size_t copy_amount = 175 const std::size_t copy_amount =
203 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 176 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
204 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 177 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
@@ -206,22 +179,18 @@ struct Memory::Impl {
206 const auto [pointer, type] = page_table.pointers[page_index].PointerType(); 179 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
207 switch (type) { 180 switch (type) {
208 case Common::PageType::Unmapped: { 181 case Common::PageType::Unmapped: {
209 LOG_ERROR(HW_Memory, 182 on_unmapped(copy_amount, current_vaddr);
210 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
211 current_vaddr, src_addr, size);
212 std::memset(dest_buffer, 0, copy_amount);
213 break; 183 break;
214 } 184 }
215 case Common::PageType::Memory: { 185 case Common::PageType::Memory: {
216 DEBUG_ASSERT(pointer); 186 DEBUG_ASSERT(pointer);
217 const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS); 187 u8* mem_ptr = pointer + page_offset + (page_index << PAGE_BITS);
218 std::memcpy(dest_buffer, src_ptr, copy_amount); 188 on_memory(copy_amount, mem_ptr);
219 break; 189 break;
220 } 190 }
221 case Common::PageType::RasterizerCachedMemory: { 191 case Common::PageType::RasterizerCachedMemory: {
222 const u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)}; 192 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)};
223 system.GPU().FlushRegion(current_vaddr, copy_amount); 193 on_rasterizer(current_vaddr, copy_amount, host_ptr);
224 std::memcpy(dest_buffer, host_ptr, copy_amount);
225 break; 194 break;
226 } 195 }
227 default: 196 default:
@@ -230,248 +199,122 @@ struct Memory::Impl {
230 199
231 page_index++; 200 page_index++;
232 page_offset = 0; 201 page_offset = 0;
233 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; 202 increment(copy_amount);
234 remaining_size -= copy_amount; 203 remaining_size -= copy_amount;
235 } 204 }
236 } 205 }
237 206
238 void ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, 207 template <bool UNSAFE>
239 const std::size_t size) { 208 void ReadBlockImpl(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
240 const auto& page_table = process.PageTable().PageTableImpl(); 209 const std::size_t size) {
241 210 WalkBlock(
242 std::size_t remaining_size = size; 211 process, src_addr, size,
243 std::size_t page_index = src_addr >> PAGE_BITS; 212 [src_addr, size, &dest_buffer](const std::size_t copy_amount,
244 std::size_t page_offset = src_addr & PAGE_MASK; 213 const VAddr current_vaddr) {
245
246 while (remaining_size > 0) {
247 const std::size_t copy_amount =
248 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
249 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
250
251 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
252 switch (type) {
253 case Common::PageType::Unmapped: {
254 LOG_ERROR(HW_Memory, 214 LOG_ERROR(HW_Memory,
255 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 215 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
256 current_vaddr, src_addr, size); 216 current_vaddr, src_addr, size);
257 std::memset(dest_buffer, 0, copy_amount); 217 std::memset(dest_buffer, 0, copy_amount);
258 break; 218 },
259 } 219 [&dest_buffer](const std::size_t copy_amount, const u8* const src_ptr) {
260 case Common::PageType::Memory: {
261 DEBUG_ASSERT(pointer);
262 const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS);
263 std::memcpy(dest_buffer, src_ptr, copy_amount); 220 std::memcpy(dest_buffer, src_ptr, copy_amount);
264 break; 221 },
265 } 222 [&system = system, &dest_buffer](const VAddr current_vaddr,
266 case Common::PageType::RasterizerCachedMemory: { 223 const std::size_t copy_amount,
267 const u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)}; 224 const u8* const host_ptr) {
225 if constexpr (!UNSAFE) {
226 system.GPU().FlushRegion(current_vaddr, copy_amount);
227 }
268 std::memcpy(dest_buffer, host_ptr, copy_amount); 228 std::memcpy(dest_buffer, host_ptr, copy_amount);
269 break; 229 },
270 } 230 [&dest_buffer](const std::size_t copy_amount) {
271 default: 231 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
272 UNREACHABLE(); 232 });
273 }
274
275 page_index++;
276 page_offset = 0;
277 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
278 remaining_size -= copy_amount;
279 }
280 } 233 }
281 234
282 void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 235 void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
283 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); 236 ReadBlockImpl<false>(*system.CurrentProcess(), src_addr, dest_buffer, size);
284 } 237 }
285 238
286 void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 239 void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
287 ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size); 240 ReadBlockImpl<true>(*system.CurrentProcess(), src_addr, dest_buffer, size);
288 } 241 }
289 242
290 void WriteBlock(const Kernel::KProcess& process, const VAddr dest_addr, const void* src_buffer, 243 template <bool UNSAFE>
291 const std::size_t size) { 244 void WriteBlockImpl(const Kernel::KProcess& process, const VAddr dest_addr,
292 const auto& page_table = process.PageTable().PageTableImpl(); 245 const void* src_buffer, const std::size_t size) {
293 std::size_t remaining_size = size; 246 WalkBlock(
294 std::size_t page_index = dest_addr >> PAGE_BITS; 247 process, dest_addr, size,
295 std::size_t page_offset = dest_addr & PAGE_MASK; 248 [dest_addr, size](const std::size_t copy_amount, const VAddr current_vaddr) {
296
297 while (remaining_size > 0) {
298 const std::size_t copy_amount =
299 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
300 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
301
302 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
303 switch (type) {
304 case Common::PageType::Unmapped: {
305 LOG_ERROR(HW_Memory, 249 LOG_ERROR(HW_Memory,
306 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 250 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
307 current_vaddr, dest_addr, size); 251 current_vaddr, dest_addr, size);
308 break; 252 },
309 } 253 [&src_buffer](const std::size_t copy_amount, u8* const dest_ptr) {
310 case Common::PageType::Memory: {
311 DEBUG_ASSERT(pointer);
312 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
313 std::memcpy(dest_ptr, src_buffer, copy_amount); 254 std::memcpy(dest_ptr, src_buffer, copy_amount);
314 break; 255 },
315 } 256 [&system = system, &src_buffer](const VAddr current_vaddr,
316 case Common::PageType::RasterizerCachedMemory: { 257 const std::size_t copy_amount, u8* const host_ptr) {
317 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)}; 258 if constexpr (!UNSAFE) {
318 system.GPU().InvalidateRegion(current_vaddr, copy_amount); 259 system.GPU().InvalidateRegion(current_vaddr, copy_amount);
319 std::memcpy(host_ptr, src_buffer, copy_amount); 260 }
320 break;
321 }
322 default:
323 UNREACHABLE();
324 }
325
326 page_index++;
327 page_offset = 0;
328 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
329 remaining_size -= copy_amount;
330 }
331 }
332
333 void WriteBlockUnsafe(const Kernel::KProcess& process, const VAddr dest_addr,
334 const void* src_buffer, const std::size_t size) {
335 const auto& page_table = process.PageTable().PageTableImpl();
336 std::size_t remaining_size = size;
337 std::size_t page_index = dest_addr >> PAGE_BITS;
338 std::size_t page_offset = dest_addr & PAGE_MASK;
339
340 while (remaining_size > 0) {
341 const std::size_t copy_amount =
342 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
343 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
344
345 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
346 switch (type) {
347 case Common::PageType::Unmapped: {
348 LOG_ERROR(HW_Memory,
349 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
350 current_vaddr, dest_addr, size);
351 break;
352 }
353 case Common::PageType::Memory: {
354 DEBUG_ASSERT(pointer);
355 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
356 std::memcpy(dest_ptr, src_buffer, copy_amount);
357 break;
358 }
359 case Common::PageType::RasterizerCachedMemory: {
360 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)};
361 std::memcpy(host_ptr, src_buffer, copy_amount); 261 std::memcpy(host_ptr, src_buffer, copy_amount);
362 break; 262 },
363 } 263 [&src_buffer](const std::size_t copy_amount) {
364 default: 264 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
365 UNREACHABLE(); 265 });
366 }
367
368 page_index++;
369 page_offset = 0;
370 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
371 remaining_size -= copy_amount;
372 }
373 } 266 }
374 267
375 void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { 268 void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
376 WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size); 269 WriteBlockImpl<false>(*system.CurrentProcess(), dest_addr, src_buffer, size);
377 } 270 }
378 271
379 void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { 272 void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
380 WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size); 273 WriteBlockImpl<true>(*system.CurrentProcess(), dest_addr, src_buffer, size);
381 } 274 }
382 275
383 void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) { 276 void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) {
384 const auto& page_table = process.PageTable().PageTableImpl(); 277 WalkBlock(
385 std::size_t remaining_size = size; 278 process, dest_addr, size,
386 std::size_t page_index = dest_addr >> PAGE_BITS; 279 [dest_addr, size](const std::size_t copy_amount, const VAddr current_vaddr) {
387 std::size_t page_offset = dest_addr & PAGE_MASK;
388
389 while (remaining_size > 0) {
390 const std::size_t copy_amount =
391 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
392 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
393
394 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
395 switch (type) {
396 case Common::PageType::Unmapped: {
397 LOG_ERROR(HW_Memory, 280 LOG_ERROR(HW_Memory,
398 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 281 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
399 current_vaddr, dest_addr, size); 282 current_vaddr, dest_addr, size);
400 break; 283 },
401 } 284 [](const std::size_t copy_amount, u8* const dest_ptr) {
402 case Common::PageType::Memory: {
403 DEBUG_ASSERT(pointer);
404 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
405 std::memset(dest_ptr, 0, copy_amount); 285 std::memset(dest_ptr, 0, copy_amount);
406 break; 286 },
407 } 287 [&system = system](const VAddr current_vaddr, const std::size_t copy_amount,
408 case Common::PageType::RasterizerCachedMemory: { 288 u8* const host_ptr) {
409 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)};
410 system.GPU().InvalidateRegion(current_vaddr, copy_amount); 289 system.GPU().InvalidateRegion(current_vaddr, copy_amount);
411 std::memset(host_ptr, 0, copy_amount); 290 std::memset(host_ptr, 0, copy_amount);
412 break; 291 },
413 } 292 [](const std::size_t copy_amount) {});
414 default:
415 UNREACHABLE();
416 }
417
418 page_index++;
419 page_offset = 0;
420 remaining_size -= copy_amount;
421 }
422 }
423
424 void ZeroBlock(const VAddr dest_addr, const std::size_t size) {
425 ZeroBlock(*system.CurrentProcess(), dest_addr, size);
426 } 293 }
427 294
428 void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr, 295 void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
429 const std::size_t size) { 296 const std::size_t size) {
430 const auto& page_table = process.PageTable().PageTableImpl(); 297 WalkBlock(
431 std::size_t remaining_size = size; 298 process, dest_addr, size,
432 std::size_t page_index = src_addr >> PAGE_BITS; 299 [this, &process, &dest_addr, &src_addr, size](const std::size_t copy_amount,
433 std::size_t page_offset = src_addr & PAGE_MASK; 300 const VAddr current_vaddr) {
434
435 while (remaining_size > 0) {
436 const std::size_t copy_amount =
437 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
438 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
439
440 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
441 switch (type) {
442 case Common::PageType::Unmapped: {
443 LOG_ERROR(HW_Memory, 301 LOG_ERROR(HW_Memory,
444 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 302 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
445 current_vaddr, src_addr, size); 303 current_vaddr, src_addr, size);
446 ZeroBlock(process, dest_addr, copy_amount); 304 ZeroBlock(process, dest_addr, copy_amount);
447 break; 305 },
448 } 306 [this, &process, &dest_addr](const std::size_t copy_amount, const u8* const src_ptr) {
449 case Common::PageType::Memory: { 307 WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount);
450 DEBUG_ASSERT(pointer); 308 },
451 const u8* src_ptr = pointer + page_offset + (page_index << PAGE_BITS); 309 [this, &system = system, &process, &dest_addr](
452 WriteBlock(process, dest_addr, src_ptr, copy_amount); 310 const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
453 break;
454 }
455 case Common::PageType::RasterizerCachedMemory: {
456 const u8* const host_ptr{GetPointerFromRasterizerCachedMemory(current_vaddr)};
457 system.GPU().FlushRegion(current_vaddr, copy_amount); 311 system.GPU().FlushRegion(current_vaddr, copy_amount);
458 WriteBlock(process, dest_addr, host_ptr, copy_amount); 312 WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount);
459 break; 313 },
460 } 314 [&dest_addr, &src_addr](const std::size_t copy_amount) {
461 default: 315 dest_addr += static_cast<VAddr>(copy_amount);
462 UNREACHABLE(); 316 src_addr += static_cast<VAddr>(copy_amount);
463 } 317 });
464
465 page_index++;
466 page_offset = 0;
467 dest_addr += static_cast<VAddr>(copy_amount);
468 src_addr += static_cast<VAddr>(copy_amount);
469 remaining_size -= copy_amount;
470 }
471 }
472
473 void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
474 return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size);
475 } 318 }
476 319
477 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { 320 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
@@ -514,7 +357,7 @@ struct Memory::Impl {
514 } else { 357 } else {
515 // Switch page type to uncached if now uncached 358 // Switch page type to uncached if now uncached
516 switch (page_type) { 359 switch (page_type) {
517 case Common::PageType::Unmapped: 360 case Common::PageType::Unmapped: // NOLINT(bugprone-branch-clone)
518 // It is not necessary for a process to have this region mapped into its address 361 // It is not necessary for a process to have this region mapped into its address
519 // space, for example, a system module need not have a VRAM mapping. 362 // space, for example, a system module need not have a VRAM mapping.
520 break; 363 break;
@@ -597,52 +440,68 @@ struct Memory::Impl {
597 } 440 }
598 } 441 }
599 442
600 /** 443 [[nodiscard]] u8* GetPointerImpl(VAddr vaddr, auto on_unmapped, auto on_rasterizer) const {
601 * Reads a particular data type out of memory at the given virtual address.
602 *
603 * @param vaddr The virtual address to read the data type from.
604 *
605 * @tparam T The data type to read out of memory. This type *must* be
606 * trivially copyable, otherwise the behavior of this function
607 * is undefined.
608 *
609 * @returns The instance of T read from the specified virtual address.
610 */
611 template <typename T>
612 T Read(VAddr vaddr) {
613 // AARCH64 masks the upper 16 bit of all memory accesses 444 // AARCH64 masks the upper 16 bit of all memory accesses
614 vaddr &= 0xffffffffffffLL; 445 vaddr &= 0xffffffffffffLL;
615 446
616 if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) { 447 if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) {
617 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); 448 on_unmapped();
618 return 0; 449 return nullptr;
619 } 450 }
620 451
621 // Avoid adding any extra logic to this fast-path block 452 // Avoid adding any extra logic to this fast-path block
622 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); 453 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
623 if (const u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { 454 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
624 T value; 455 return &pointer[vaddr];
625 std::memcpy(&value, &pointer[vaddr], sizeof(T));
626 return value;
627 } 456 }
628 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { 457 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
629 case Common::PageType::Unmapped: 458 case Common::PageType::Unmapped:
630 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); 459 on_unmapped();
631 return 0; 460 return nullptr;
632 case Common::PageType::Memory: 461 case Common::PageType::Memory:
633 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); 462 ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr);
634 break; 463 return nullptr;
635 case Common::PageType::RasterizerCachedMemory: { 464 case Common::PageType::RasterizerCachedMemory: {
636 const u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; 465 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
637 system.GPU().FlushRegion(vaddr, sizeof(T)); 466 on_rasterizer();
638 T value; 467 return host_ptr;
639 std::memcpy(&value, host_ptr, sizeof(T));
640 return value;
641 } 468 }
642 default: 469 default:
643 UNREACHABLE(); 470 UNREACHABLE();
644 } 471 }
645 return {}; 472 return nullptr;
473 }
474
475 [[nodiscard]] u8* GetPointer(const VAddr vaddr) const {
476 return GetPointerImpl(
477 vaddr, [vaddr]() { LOG_ERROR(HW_Memory, "Unmapped GetPointer @ 0x{:016X}", vaddr); },
478 []() {});
479 }
480
481 /**
482 * Reads a particular data type out of memory at the given virtual address.
483 *
484 * @param vaddr The virtual address to read the data type from.
485 *
486 * @tparam T The data type to read out of memory. This type *must* be
487 * trivially copyable, otherwise the behavior of this function
488 * is undefined.
489 *
490 * @returns The instance of T read from the specified virtual address.
491 */
492 template <typename T>
493 T Read(VAddr vaddr) {
494 T result = 0;
495 const u8* const ptr = GetPointerImpl(
496 vaddr,
497 [vaddr]() {
498 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr);
499 },
500 [&system = system, vaddr]() { system.GPU().FlushRegion(vaddr, sizeof(T)); });
501 if (ptr) {
502 std::memcpy(&result, ptr, sizeof(T));
503 }
504 return result;
646 } 505 }
647 506
648 /** 507 /**
@@ -656,110 +515,46 @@ struct Memory::Impl {
656 */ 515 */
657 template <typename T> 516 template <typename T>
658 void Write(VAddr vaddr, const T data) { 517 void Write(VAddr vaddr, const T data) {
659 // AARCH64 masks the upper 16 bit of all memory accesses 518 u8* const ptr = GetPointerImpl(
660 vaddr &= 0xffffffffffffLL; 519 vaddr,
661 520 [vaddr, data]() {
662 if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) { 521 LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
663 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, 522 vaddr, static_cast<u64>(data));
664 static_cast<u32>(data), vaddr); 523 },
665 return; 524 [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
666 } 525 if (ptr) {
667 526 std::memcpy(ptr, &data, sizeof(T));
668 // Avoid adding any extra logic to this fast-path block
669 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
670 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
671 std::memcpy(&pointer[vaddr], &data, sizeof(T));
672 return;
673 }
674 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
675 case Common::PageType::Unmapped:
676 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
677 static_cast<u32>(data), vaddr);
678 return;
679 case Common::PageType::Memory:
680 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
681 break;
682 case Common::PageType::RasterizerCachedMemory: {
683 u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
684 system.GPU().InvalidateRegion(vaddr, sizeof(T));
685 std::memcpy(host_ptr, &data, sizeof(T));
686 break;
687 }
688 default:
689 UNREACHABLE();
690 } 527 }
691 } 528 }
692 529
693 template <typename T> 530 template <typename T>
694 bool WriteExclusive(VAddr vaddr, const T data, const T expected) { 531 bool WriteExclusive(VAddr vaddr, const T data, const T expected) {
695 // AARCH64 masks the upper 16 bit of all memory accesses 532 u8* const ptr = GetPointerImpl(
696 vaddr &= 0xffffffffffffLL; 533 vaddr,
697 534 [vaddr, data]() {
698 if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) { 535 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}",
699 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, 536 sizeof(T) * 8, vaddr, static_cast<u64>(data));
700 static_cast<u32>(data), vaddr); 537 },
701 return true; 538 [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
702 } 539 if (ptr) {
703 540 const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr);
704 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
705 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
706 // NOTE: Avoid adding any extra logic to this fast-path block
707 const auto volatile_pointer = reinterpret_cast<volatile T*>(&pointer[vaddr]);
708 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); 541 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
709 } 542 }
710 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
711 case Common::PageType::Unmapped:
712 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
713 static_cast<u32>(data), vaddr);
714 return true;
715 case Common::PageType::Memory:
716 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
717 break;
718 case Common::PageType::RasterizerCachedMemory: {
719 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
720 system.GPU().InvalidateRegion(vaddr, sizeof(T));
721 auto* pointer = reinterpret_cast<volatile T*>(&host_ptr);
722 return Common::AtomicCompareAndSwap(pointer, data, expected);
723 }
724 default:
725 UNREACHABLE();
726 }
727 return true; 543 return true;
728 } 544 }
729 545
730 bool WriteExclusive128(VAddr vaddr, const u128 data, const u128 expected) { 546 bool WriteExclusive128(VAddr vaddr, const u128 data, const u128 expected) {
731 // AARCH64 masks the upper 16 bit of all memory accesses 547 u8* const ptr = GetPointerImpl(
732 vaddr &= 0xffffffffffffLL; 548 vaddr,
733 549 [vaddr, data]() {
734 if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) { 550 LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}",
735 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, 551 vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0]));
736 static_cast<u32>(data[0]), vaddr); 552 },
737 return true; 553 [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); });
738 } 554 if (ptr) {
739 555 const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr);
740 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
741 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
742 // NOTE: Avoid adding any extra logic to this fast-path block
743 const auto volatile_pointer = reinterpret_cast<volatile u64*>(&pointer[vaddr]);
744 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); 556 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
745 } 557 }
746 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
747 case Common::PageType::Unmapped:
748 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8,
749 static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr);
750 return true;
751 case Common::PageType::Memory:
752 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
753 break;
754 case Common::PageType::RasterizerCachedMemory: {
755 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
756 system.GPU().InvalidateRegion(vaddr, sizeof(u128));
757 auto* pointer = reinterpret_cast<volatile u64*>(&host_ptr);
758 return Common::AtomicCompareAndSwap(pointer, data, expected);
759 }
760 default:
761 UNREACHABLE();
762 }
763 return true; 558 return true;
764 } 559 }
765 560
@@ -789,12 +584,11 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
789 impl->UnmapRegion(page_table, base, size); 584 impl->UnmapRegion(page_table, base, size);
790} 585}
791 586
792bool Memory::IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
793 return impl->IsValidVirtualAddress(process, vaddr);
794}
795
796bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { 587bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
797 return impl->IsValidVirtualAddress(vaddr); 588 const Kernel::KProcess& process = *system.CurrentProcess();
589 const auto& page_table = process.PageTable().PageTableImpl();
590 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType();
591 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
798} 592}
799 593
800u8* Memory::GetPointer(VAddr vaddr) { 594u8* Memory::GetPointer(VAddr vaddr) {
@@ -863,64 +657,38 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
863 657
864void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer, 658void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
865 const std::size_t size) { 659 const std::size_t size) {
866 impl->ReadBlock(process, src_addr, dest_buffer, size); 660 impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size);
867} 661}
868 662
869void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 663void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
870 impl->ReadBlock(src_addr, dest_buffer, size); 664 impl->ReadBlock(src_addr, dest_buffer, size);
871} 665}
872 666
873void Memory::ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr,
874 void* dest_buffer, const std::size_t size) {
875 impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size);
876}
877
878void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 667void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
879 impl->ReadBlockUnsafe(src_addr, dest_buffer, size); 668 impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
880} 669}
881 670
882void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer, 671void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
883 std::size_t size) { 672 std::size_t size) {
884 impl->WriteBlock(process, dest_addr, src_buffer, size); 673 impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size);
885} 674}
886 675
887void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { 676void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
888 impl->WriteBlock(dest_addr, src_buffer, size); 677 impl->WriteBlock(dest_addr, src_buffer, size);
889} 678}
890 679
891void Memory::WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr,
892 const void* src_buffer, std::size_t size) {
893 impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size);
894}
895
896void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, 680void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer,
897 const std::size_t size) { 681 const std::size_t size) {
898 impl->WriteBlockUnsafe(dest_addr, src_buffer, size); 682 impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
899} 683}
900 684
901void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
902 impl->ZeroBlock(process, dest_addr, size);
903}
904
905void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) {
906 impl->ZeroBlock(dest_addr, size);
907}
908
909void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr, 685void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
910 const std::size_t size) { 686 const std::size_t size) {
911 impl->CopyBlock(process, dest_addr, src_addr, size); 687 impl->CopyBlock(process, dest_addr, src_addr, size);
912} 688}
913 689
914void Memory::CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
915 impl->CopyBlock(dest_addr, src_addr, size);
916}
917
918void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { 690void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
919 impl->RasterizerMarkRegionCached(vaddr, size, cached); 691 impl->RasterizerMarkRegionCached(vaddr, size, cached);
920} 692}
921 693
922bool IsKernelVirtualAddress(const VAddr vaddr) {
923 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
924}
925
926} // namespace Core::Memory 694} // namespace Core::Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index c91eeced9..b5721b740 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -39,11 +39,6 @@ enum : VAddr {
39 39
40 /// Application stack 40 /// Application stack
41 DEFAULT_STACK_SIZE = 0x100000, 41 DEFAULT_STACK_SIZE = 0x100000,
42
43 /// Kernel Virtual Address Range
44 KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
45 KERNEL_REGION_SIZE = 0x7FFFE00000,
46 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
47}; 42};
48 43
49/// Central class that handles all memory operations and state. 44/// Central class that handles all memory operations and state.
@@ -56,7 +51,7 @@ public:
56 Memory& operator=(const Memory&) = delete; 51 Memory& operator=(const Memory&) = delete;
57 52
58 Memory(Memory&&) = default; 53 Memory(Memory&&) = default;
59 Memory& operator=(Memory&&) = default; 54 Memory& operator=(Memory&&) = delete;
60 55
61 /** 56 /**
62 * Resets the state of the Memory system. 57 * Resets the state of the Memory system.
@@ -92,24 +87,13 @@ public:
92 87
93 /** 88 /**
94 * Checks whether or not the supplied address is a valid virtual 89 * Checks whether or not the supplied address is a valid virtual
95 * address for the given process.
96 *
97 * @param process The emulated process to check the address against.
98 * @param vaddr The virtual address to check the validity of.
99 *
100 * @returns True if the given virtual address is valid, false otherwise.
101 */
102 bool IsValidVirtualAddress(const Kernel::KProcess& process, VAddr vaddr) const;
103
104 /**
105 * Checks whether or not the supplied address is a valid virtual
106 * address for the current process. 90 * address for the current process.
107 * 91 *
108 * @param vaddr The virtual address to check the validity of. 92 * @param vaddr The virtual address to check the validity of.
109 * 93 *
110 * @returns True if the given virtual address is valid, false otherwise. 94 * @returns True if the given virtual address is valid, false otherwise.
111 */ 95 */
112 bool IsValidVirtualAddress(VAddr vaddr) const; 96 [[nodiscard]] bool IsValidVirtualAddress(VAddr vaddr) const;
113 97
114 /** 98 /**
115 * Gets a pointer to the given address. 99 * Gets a pointer to the given address.
@@ -134,7 +118,7 @@ public:
134 * @returns The pointer to the given address, if the address is valid. 118 * @returns The pointer to the given address, if the address is valid.
135 * If the address is not valid, nullptr will be returned. 119 * If the address is not valid, nullptr will be returned.
136 */ 120 */
137 const u8* GetPointer(VAddr vaddr) const; 121 [[nodiscard]] const u8* GetPointer(VAddr vaddr) const;
138 122
139 template <typename T> 123 template <typename T>
140 const T* GetPointer(VAddr vaddr) const { 124 const T* GetPointer(VAddr vaddr) const {
@@ -328,27 +312,6 @@ public:
328 std::size_t size); 312 std::size_t size);
329 313
330 /** 314 /**
331 * Reads a contiguous block of bytes from a specified process' address space.
332 * This unsafe version does not trigger GPU flushing.
333 *
334 * @param process The process to read the data from.
335 * @param src_addr The virtual address to begin reading from.
336 * @param dest_buffer The buffer to place the read bytes into.
337 * @param size The amount of data to read, in bytes.
338 *
339 * @note If a size of 0 is specified, then this function reads nothing and
340 * no attempts to access memory are made at all.
341 *
342 * @pre dest_buffer must be at least size bytes in length, otherwise a
343 * buffer overrun will occur.
344 *
345 * @post The range [dest_buffer, size) contains the read bytes from the
346 * process' address space.
347 */
348 void ReadBlockUnsafe(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
349 std::size_t size);
350
351 /**
352 * Reads a contiguous block of bytes from the current process' address space. 315 * Reads a contiguous block of bytes from the current process' address space.
353 * 316 *
354 * @param src_addr The virtual address to begin reading from. 317 * @param src_addr The virtual address to begin reading from.
@@ -409,26 +372,6 @@ public:
409 std::size_t size); 372 std::size_t size);
410 373
411 /** 374 /**
412 * Writes a range of bytes into a given process' address space at the specified
413 * virtual address.
414 * This unsafe version does not invalidate GPU Memory.
415 *
416 * @param process The process to write data into the address space of.
417 * @param dest_addr The destination virtual address to begin writing the data at.
418 * @param src_buffer The data to write into the process' address space.
419 * @param size The size of the data to write, in bytes.
420 *
421 * @post The address range [dest_addr, size) in the process' address space
422 * contains the data that was within src_buffer.
423 *
424 * @post If an attempt is made to write into an unmapped region of memory, the writes
425 * will be ignored and an error will be logged.
426 *
427 */
428 void WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
429 std::size_t size);
430
431 /**
432 * Writes a range of bytes into the current process' address space at the specified 375 * Writes a range of bytes into the current process' address space at the specified
433 * virtual address. 376 * virtual address.
434 * 377 *
@@ -468,29 +411,6 @@ public:
468 void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size); 411 void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size);
469 412
470 /** 413 /**
471 * Fills the specified address range within a process' address space with zeroes.
472 *
473 * @param process The process that will have a portion of its memory zeroed out.
474 * @param dest_addr The starting virtual address of the range to zero out.
475 * @param size The size of the address range to zero out, in bytes.
476 *
477 * @post The range [dest_addr, size) within the process' address space is
478 * filled with zeroes.
479 */
480 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
481
482 /**
483 * Fills the specified address range within the current process' address space with zeroes.
484 *
485 * @param dest_addr The starting virtual address of the range to zero out.
486 * @param size The size of the address range to zero out, in bytes.
487 *
488 * @post The range [dest_addr, size) within the current process' address space is
489 * filled with zeroes.
490 */
491 void ZeroBlock(VAddr dest_addr, std::size_t size);
492
493 /**
494 * Copies data within a process' address space to another location within the 414 * Copies data within a process' address space to another location within the
495 * same address space. 415 * same address space.
496 * 416 *
@@ -506,19 +426,6 @@ public:
506 std::size_t size); 426 std::size_t size);
507 427
508 /** 428 /**
509 * Copies data within the current process' address space to another location within the
510 * same address space.
511 *
512 * @param dest_addr The destination virtual address to begin copying the data into.
513 * @param src_addr The source virtual address to begin copying the data from.
514 * @param size The size of the data to copy, in bytes.
515 *
516 * @post The range [dest_addr, size) within the current process' address space
517 * contains the same data within the range [src_addr, size).
518 */
519 void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
520
521 /**
522 * Marks each page within the specified address range as cached or uncached. 429 * Marks each page within the specified address range as cached or uncached.
523 * 430 *
524 * @param vaddr The virtual address indicating the start of the address range. 431 * @param vaddr The virtual address indicating the start of the address range.
@@ -535,7 +442,4 @@ private:
535 std::unique_ptr<Impl> impl; 442 std::unique_ptr<Impl> impl;
536}; 443};
537 444
538/// Determines if the given VAddr is a kernel address
539bool IsKernelVirtualAddress(VAddr vaddr);
540
541} // namespace Core::Memory 445} // namespace Core::Memory
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 8de3d4520..ff23230f0 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -304,10 +304,10 @@ std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers([
304} 304}
305 305
306std::string GenerateKeyboardParam(int key_code) { 306std::string GenerateKeyboardParam(int key_code) {
307 Common::ParamPackage param{ 307 Common::ParamPackage param;
308 {"engine", "keyboard"}, 308 param.Set("engine", "keyboard");
309 {"code", std::to_string(key_code)}, 309 param.Set("code", key_code);
310 }; 310 param.Set("toggle", false);
311 return param.Serialize(); 311 return param.Serialize();
312} 312}
313 313
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index efcdd85d2..090b26972 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -57,6 +57,7 @@ Common::ParamPackage MouseButtonFactory::GetNextInput() const {
57 if (pad.button != MouseInput::MouseButton::Undefined) { 57 if (pad.button != MouseInput::MouseButton::Undefined) {
58 params.Set("engine", "mouse"); 58 params.Set("engine", "mouse");
59 params.Set("button", static_cast<u16>(pad.button)); 59 params.Set("button", static_cast<u16>(pad.button));
60 params.Set("toggle", false);
60 return params; 61 return params;
61 } 62 }
62 } 63 }
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 70a0ba09c..f1f950d8a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -82,6 +82,12 @@ public:
82 state.buttons.insert_or_assign(button, value); 82 state.buttons.insert_or_assign(button, value);
83 } 83 }
84 84
85 void PreSetButton(int button) {
86 if (!state.buttons.contains(button)) {
87 SetButton(button, false);
88 }
89 }
90
85 void SetMotion(SDL_ControllerSensorEvent event) { 91 void SetMotion(SDL_ControllerSensorEvent event) {
86 constexpr float gravity_constant = 9.80665f; 92 constexpr float gravity_constant = 9.80665f;
87 std::lock_guard lock{mutex}; 93 std::lock_guard lock{mutex};
@@ -155,9 +161,16 @@ public:
155 state.axes.insert_or_assign(axis, value); 161 state.axes.insert_or_assign(axis, value);
156 } 162 }
157 163
158 float GetAxis(int axis, float range) const { 164 void PreSetAxis(int axis) {
165 if (!state.axes.contains(axis)) {
166 SetAxis(axis, 0);
167 }
168 }
169
170 float GetAxis(int axis, float range, float offset) const {
159 std::lock_guard lock{mutex}; 171 std::lock_guard lock{mutex};
160 return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); 172 const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f;
173 return (value + offset) / range;
161 } 174 }
162 175
163 bool RumblePlay(u16 amp_low, u16 amp_high) { 176 bool RumblePlay(u16 amp_low, u16 amp_high) {
@@ -174,9 +187,10 @@ public:
174 return false; 187 return false;
175 } 188 }
176 189
177 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { 190 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range, float offset_x,
178 float x = GetAxis(axis_x, range); 191 float offset_y) const {
179 float y = GetAxis(axis_y, range); 192 float x = GetAxis(axis_x, range, offset_x);
193 float y = GetAxis(axis_y, range, offset_y);
180 y = -y; // 3DS uses an y-axis inverse from SDL 194 y = -y; // 3DS uses an y-axis inverse from SDL
181 195
182 // Make sure the coordinates are in the unit circle, 196 // Make sure the coordinates are in the unit circle,
@@ -483,7 +497,7 @@ public:
483 trigger_if_greater(trigger_if_greater_) {} 497 trigger_if_greater(trigger_if_greater_) {}
484 498
485 bool GetStatus() const override { 499 bool GetStatus() const override {
486 const float axis_value = joystick->GetAxis(axis, 1.0f); 500 const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
487 if (trigger_if_greater) { 501 if (trigger_if_greater) {
488 return axis_value > threshold; 502 return axis_value > threshold;
489 } 503 }
@@ -500,12 +514,14 @@ private:
500class SDLAnalog final : public Input::AnalogDevice { 514class SDLAnalog final : public Input::AnalogDevice {
501public: 515public:
502 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, 516 explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
503 bool invert_x_, bool invert_y_, float deadzone_, float range_) 517 bool invert_x_, bool invert_y_, float deadzone_, float range_,
518 float offset_x_, float offset_y_)
504 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), 519 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_),
505 invert_y(invert_y_), deadzone(deadzone_), range(range_) {} 520 invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_),
521 offset_y(offset_y_) {}
506 522
507 std::tuple<float, float> GetStatus() const override { 523 std::tuple<float, float> GetStatus() const override {
508 auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); 524 auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y);
509 const float r = std::sqrt((x * x) + (y * y)); 525 const float r = std::sqrt((x * x) + (y * y));
510 if (invert_x) { 526 if (invert_x) {
511 x = -x; 527 x = -x;
@@ -522,8 +538,8 @@ public:
522 } 538 }
523 539
524 std::tuple<float, float> GetRawStatus() const override { 540 std::tuple<float, float> GetRawStatus() const override {
525 const float x = joystick->GetAxis(axis_x, range); 541 const float x = joystick->GetAxis(axis_x, range, offset_x);
526 const float y = joystick->GetAxis(axis_y, range); 542 const float y = joystick->GetAxis(axis_y, range, offset_y);
527 return {x, -y}; 543 return {x, -y};
528 } 544 }
529 545
@@ -555,6 +571,8 @@ private:
555 const bool invert_y; 571 const bool invert_y;
556 const float deadzone; 572 const float deadzone;
557 const float range; 573 const float range;
574 const float offset_x;
575 const float offset_y;
558}; 576};
559 577
560class SDLVibration final : public Input::VibrationDevice { 578class SDLVibration final : public Input::VibrationDevice {
@@ -621,7 +639,7 @@ public:
621 trigger_if_greater(trigger_if_greater_) {} 639 trigger_if_greater(trigger_if_greater_) {}
622 640
623 Input::MotionStatus GetStatus() const override { 641 Input::MotionStatus GetStatus() const override {
624 const float axis_value = joystick->GetAxis(axis, 1.0f); 642 const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
625 bool trigger = axis_value < threshold; 643 bool trigger = axis_value < threshold;
626 if (trigger_if_greater) { 644 if (trigger_if_greater) {
627 trigger = axis_value > threshold; 645 trigger = axis_value > threshold;
@@ -720,13 +738,13 @@ public:
720 LOG_ERROR(Input, "Unknown direction {}", direction_name); 738 LOG_ERROR(Input, "Unknown direction {}", direction_name);
721 } 739 }
722 // This is necessary so accessing GetAxis with axis won't crash 740 // This is necessary so accessing GetAxis with axis won't crash
723 joystick->SetAxis(axis, 0); 741 joystick->PreSetAxis(axis);
724 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); 742 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
725 } 743 }
726 744
727 const int button = params.Get("button", 0); 745 const int button = params.Get("button", 0);
728 // This is necessary so accessing GetButton with button won't crash 746 // This is necessary so accessing GetButton with button won't crash
729 joystick->SetButton(button, false); 747 joystick->PreSetButton(button);
730 return std::make_unique<SDLButton>(joystick, button, toggle); 748 return std::make_unique<SDLButton>(joystick, button, toggle);
731 } 749 }
732 750
@@ -757,13 +775,15 @@ public:
757 const std::string invert_y_value = params.Get("invert_y", "+"); 775 const std::string invert_y_value = params.Get("invert_y", "+");
758 const bool invert_x = invert_x_value == "-"; 776 const bool invert_x = invert_x_value == "-";
759 const bool invert_y = invert_y_value == "-"; 777 const bool invert_y = invert_y_value == "-";
778 const float offset_x = params.Get("offset_x", 0.0f);
779 const float offset_y = params.Get("offset_y", 0.0f);
760 auto joystick = state.GetSDLJoystickByGUID(guid, port); 780 auto joystick = state.GetSDLJoystickByGUID(guid, port);
761 781
762 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 782 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
763 joystick->SetAxis(axis_x, 0); 783 joystick->PreSetAxis(axis_x);
764 joystick->SetAxis(axis_y, 0); 784 joystick->PreSetAxis(axis_y);
765 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, 785 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone,
766 range); 786 range, offset_x, offset_y);
767 } 787 }
768 788
769private: 789private:
@@ -844,13 +864,13 @@ public:
844 LOG_ERROR(Input, "Unknown direction {}", direction_name); 864 LOG_ERROR(Input, "Unknown direction {}", direction_name);
845 } 865 }
846 // This is necessary so accessing GetAxis with axis won't crash 866 // This is necessary so accessing GetAxis with axis won't crash
847 joystick->SetAxis(axis, 0); 867 joystick->PreSetAxis(axis);
848 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater); 868 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
849 } 869 }
850 870
851 const int button = params.Get("button", 0); 871 const int button = params.Get("button", 0);
852 // This is necessary so accessing GetButton with button won't crash 872 // This is necessary so accessing GetButton with button won't crash
853 joystick->SetButton(button, false); 873 joystick->PreSetButton(button);
854 return std::make_unique<SDLButtonMotion>(joystick, button); 874 return std::make_unique<SDLButtonMotion>(joystick, button);
855 } 875 }
856 876
@@ -995,6 +1015,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid
995 params.Set("port", port); 1015 params.Set("port", port);
996 params.Set("guid", std::move(guid)); 1016 params.Set("guid", std::move(guid));
997 params.Set("button", button); 1017 params.Set("button", button);
1018 params.Set("toggle", false);
998 return params; 1019 return params;
999} 1020}
1000 1021
@@ -1134,13 +1155,15 @@ Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& gu
1134} 1155}
1135 1156
1136Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, 1157Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
1137 int axis_y) { 1158 int axis_y, float offset_x, float offset_y) {
1138 Common::ParamPackage params; 1159 Common::ParamPackage params;
1139 params.Set("engine", "sdl"); 1160 params.Set("engine", "sdl");
1140 params.Set("port", port); 1161 params.Set("port", port);
1141 params.Set("guid", guid); 1162 params.Set("guid", guid);
1142 params.Set("axis_x", axis_x); 1163 params.Set("axis_x", axis_x);
1143 params.Set("axis_y", axis_y); 1164 params.Set("axis_y", axis_y);
1165 params.Set("offset_x", offset_x);
1166 params.Set("offset_y", offset_y);
1144 params.Set("invert_x", "+"); 1167 params.Set("invert_x", "+");
1145 params.Set("invert_y", "+"); 1168 params.Set("invert_y", "+");
1146 return params; 1169 return params;
@@ -1342,24 +1365,39 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
1342 const auto& binding_left_y = 1365 const auto& binding_left_y =
1343 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); 1366 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
1344 if (params.Has("guid2")) { 1367 if (params.Has("guid2")) {
1368 joystick2->PreSetAxis(binding_left_x.value.axis);
1369 joystick2->PreSetAxis(binding_left_y.value.axis);
1370 const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0);
1371 const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0);
1345 mapping.insert_or_assign( 1372 mapping.insert_or_assign(
1346 Settings::NativeAnalog::LStick, 1373 Settings::NativeAnalog::LStick,
1347 BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), 1374 BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(),
1348 binding_left_x.value.axis, binding_left_y.value.axis)); 1375 binding_left_x.value.axis, binding_left_y.value.axis,
1376 left_offset_x, left_offset_y));
1349 } else { 1377 } else {
1378 joystick->PreSetAxis(binding_left_x.value.axis);
1379 joystick->PreSetAxis(binding_left_y.value.axis);
1380 const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0);
1381 const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0);
1350 mapping.insert_or_assign( 1382 mapping.insert_or_assign(
1351 Settings::NativeAnalog::LStick, 1383 Settings::NativeAnalog::LStick,
1352 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1384 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1353 binding_left_x.value.axis, binding_left_y.value.axis)); 1385 binding_left_x.value.axis, binding_left_y.value.axis,
1386 left_offset_x, left_offset_y));
1354 } 1387 }
1355 const auto& binding_right_x = 1388 const auto& binding_right_x =
1356 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); 1389 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
1357 const auto& binding_right_y = 1390 const auto& binding_right_y =
1358 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); 1391 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
1392 joystick->PreSetAxis(binding_right_x.value.axis);
1393 joystick->PreSetAxis(binding_right_y.value.axis);
1394 const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0);
1395 const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0);
1359 mapping.insert_or_assign(Settings::NativeAnalog::RStick, 1396 mapping.insert_or_assign(Settings::NativeAnalog::RStick,
1360 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1397 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1361 binding_right_x.value.axis, 1398 binding_right_x.value.axis,
1362 binding_right_y.value.axis)); 1399 binding_right_y.value.axis, right_offset_x,
1400 right_offset_y));
1363 return mapping; 1401 return mapping;
1364} 1402}
1365 1403
@@ -1563,8 +1601,9 @@ public:
1563 } 1601 }
1564 1602
1565 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { 1603 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
1604 // Set offset to zero since the joystick is not on center
1566 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1605 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1567 first_axis, axis); 1606 first_axis, axis, 0, 0);
1568 first_axis = -1; 1607 first_axis = -1;
1569 return params; 1608 return params;
1570 } 1609 }
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 7eecb3991..70030066a 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -397,14 +397,14 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
397 next_frame = std::move(temp); 397 next_frame = std::move(temp);
398 } else { 398 } else {
399 next_frame.info = current_frame.info; 399 next_frame.info = current_frame.info;
400 next_frame.bit_stream = std::move(current_frame.bit_stream); 400 next_frame.bit_stream = current_frame.bit_stream;
401 } 401 }
402 return current_frame; 402 return current_frame;
403} 403}
404 404
405std::vector<u8> VP9::ComposeCompressedHeader() { 405std::vector<u8> VP9::ComposeCompressedHeader() {
406 VpxRangeEncoder writer{}; 406 VpxRangeEncoder writer{};
407 const bool update_probs = current_frame_info.show_frame && !current_frame_info.is_key_frame; 407 const bool update_probs = !current_frame_info.is_key_frame && current_frame_info.show_frame;
408 if (!current_frame_info.lossless) { 408 if (!current_frame_info.lossless) {
409 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) { 409 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) {
410 writer.Write(3, 2); 410 writer.Write(3, 2);
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h
index 6820afa26..87eafdb03 100644
--- a/src/video_core/command_classes/codecs/vp9_types.h
+++ b/src/video_core/command_classes/codecs/vp9_types.h
@@ -176,7 +176,7 @@ struct PictureInfo {
176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0, 176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0, 177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0, 178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
179 .show_frame = false, 179 .show_frame = true,
180 .ref_frame_sign_bias = ref_frame_sign_bias, 180 .ref_frame_sign_bias = ref_frame_sign_bias,
181 .base_q_index = base_q_index, 181 .base_q_index = base_q_index,
182 .y_dc_delta_q = y_dc_delta_q, 182 .y_dc_delta_q = y_dc_delta_q,
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index aa173d19e..300a61205 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -228,7 +228,9 @@ void MemoryCommit::Release() {
228 228
229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) 229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_)
230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()}, 230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()},
231 export_allocations{export_allocations_} {} 231 export_allocations{export_allocations_},
232 buffer_image_granularity{
233 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
232 234
233MemoryAllocator::~MemoryAllocator() = default; 235MemoryAllocator::~MemoryAllocator() = default;
234 236
@@ -258,7 +260,9 @@ MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage
258} 260}
259 261
260MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { 262MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) {
261 auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); 263 VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image);
264 requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity);
265 auto commit = Commit(requirements, usage);
262 image.BindMemory(commit.Memory(), commit.Offset()); 266 image.BindMemory(commit.Memory(), commit.Offset());
263 return commit; 267 return commit;
264} 268}
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index b61e931e0..86e8ed119 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -123,6 +123,8 @@ private:
123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
124 const bool export_allocations; ///< True when memory allocations have to be exported. 124 const bool export_allocations; ///< True when memory allocations have to be exported.
125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
126 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
127 // and optimal images
126}; 128};
127 129
128/// Returns true when a memory usage is guaranteed to be host visible. 130/// Returns true when a memory usage is guaranteed to be host visible.
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 8ce97edec..69b6c2d66 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -25,6 +25,36 @@
25 <item> 25 <item>
26 <layout class="QVBoxLayout" name="GeneralVerticalLayout"> 26 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
27 <item> 27 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_2">
29 <item>
30 <widget class="QLabel" name="fps_cap_label">
31 <property name="text">
32 <string>Framerate Cap</string>
33 </property>
34 <property name="toolTip">
35 <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string>
36 </property>
37 </widget>
38 </item>
39 <item>
40 <widget class="QSpinBox" name="fps_cap">
41 <property name="suffix">
42 <string>x</string>
43 </property>
44 <property name="minimum">
45 <number>1</number>
46 </property>
47 <property name="maximum">
48 <number>1000</number>
49 </property>
50 <property name="value">
51 <number>500</number>
52 </property>
53 </widget>
54 </item>
55 </layout>
56 </item>
57 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_2"> 58 <layout class="QHBoxLayout" name="horizontalLayout_2">
29 <item> 59 <item>
30 <widget class="QCheckBox" name="toggle_speed_limit"> 60 <widget class="QCheckBox" name="toggle_speed_limit">
@@ -52,36 +82,6 @@
52 </layout> 82 </layout>
53 </item> 83 </item>
54 <item> 84 <item>
55 <layout class="QHBoxLayout" name="horizontalLayout_2">
56 <item>
57 <widget class="QLabel" name="fps_cap_label">
58 <property name="text">
59 <string>Framerate Cap</string>
60 </property>
61 <property name="toolTip">
62 <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string>
63 </property>
64 </widget>
65 </item>
66 <item>
67 <widget class="QSpinBox" name="fps_cap">
68 <property name="suffix">
69 <string>x</string>
70 </property>
71 <property name="minimum">
72 <number>1</number>
73 </property>
74 <property name="maximum">
75 <number>1000</number>
76 </property>
77 <property name="value">
78 <number>500</number>
79 </property>
80 </widget>
81 </item>
82 </layout>
83 </item>
84 <item>
85 <widget class="QCheckBox" name="use_multi_core"> 85 <widget class="QCheckBox" name="use_multi_core">
86 <property name="text"> 86 <property name="text">
87 <string>Multicore CPU Emulation</string> 87 <string>Multicore CPU Emulation</string>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 379dc5d2e..4fe6b86ae 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -82,14 +82,17 @@
82 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 82 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
83 </property> 83 </property>
84 <property name="text"> 84 <property name="text">
85 <string>Use asynchronous shader building</string> 85 <string>Use asynchronous shader building (hack)</string>
86 </property> 86 </property>
87 </widget> 87 </widget>
88 </item> 88 </item>
89 <item> 89 <item>
90 <widget class="QCheckBox" name="use_fast_gpu_time"> 90 <widget class="QCheckBox" name="use_fast_gpu_time">
91 <property name="toolTip">
92 <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
93 </property>
91 <property name="text"> 94 <property name="text">
92 <string>Use Fast GPU Time</string> 95 <string>Use Fast GPU Time (hack)</string>
93 </property> 96 </property>
94 </widget> 97 </widget>
95 </item> 98 </item>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 6b9bd05f1..7527c068b 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -309,11 +309,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
309 buttons_param[button_id].Clear(); 309 buttons_param[button_id].Clear();
310 button_map[button_id]->setText(tr("[not set]")); 310 button_map[button_id]->setText(tr("[not set]"));
311 }); 311 });
312 context_menu.addAction(tr("Toggle button"), [&] { 312 if (buttons_param[button_id].Has("toggle")) {
313 const bool toggle_value = !buttons_param[button_id].Get("toggle", false); 313 context_menu.addAction(tr("Toggle button"), [&] {
314 buttons_param[button_id].Set("toggle", toggle_value); 314 const bool toggle_value =
315 button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); 315 !buttons_param[button_id].Get("toggle", false);
316 }); 316 buttons_param[button_id].Set("toggle", toggle_value);
317 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
318 });
319 }
317 if (buttons_param[button_id].Has("threshold")) { 320 if (buttons_param[button_id].Has("threshold")) {
318 context_menu.addAction(tr("Set threshold"), [&] { 321 context_menu.addAction(tr("Set threshold"), [&] {
319 const int button_threshold = static_cast<int>( 322 const int button_threshold = static_cast<int>(
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index e55a19649..74fc24972 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -1,5 +1,6 @@
1set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) 1set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
2 2
3# Credits to Samantas5855 and others for this function.
3function(create_resource file output filename) 4function(create_resource file output filename)
4 # Read hex data from file 5 # Read hex data from file
5 file(READ ${file} filedata HEX) 6 file(READ ${file} filedata HEX)
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index c80f7791c..87fce0c23 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -232,6 +232,7 @@ void EmuWindow_SDL2::WaitEvent() {
232 } 232 }
233} 233}
234 234
235// Credits to Samantas5855 and others for this function.
235void EmuWindow_SDL2::SetWindowIcon() { 236void EmuWindow_SDL2::SetWindowIcon() {
236 SDL_RWops* const yuzu_icon_stream = SDL_RWFromConstMem((void*)yuzu_icon, yuzu_icon_size); 237 SDL_RWops* const yuzu_icon_stream = SDL_RWFromConstMem((void*)yuzu_icon, yuzu_icon_size);
237 if (yuzu_icon_stream == nullptr) { 238 if (yuzu_icon_stream == nullptr) {