diff options
| author | 2017-07-22 10:15:52 +0300 | |
|---|---|---|
| committer | 2017-07-22 10:15:52 +0300 | |
| commit | 045d0b5bbdf790952ddfedcfc8816c0afc7a2300 (patch) | |
| tree | fba1a440adf7d7ecd59edaf48e215e70b7c6cf9e /src | |
| parent | Merge pull request #2833 from j-selby/single-header-json (diff) | |
| parent | Memory: Add function to flush a virtual range from the rasterizer cache (diff) | |
| download | yuzu-045d0b5bbdf790952ddfedcfc8816c0afc7a2300.tar.gz yuzu-045d0b5bbdf790952ddfedcfc8816c0afc7a2300.tar.xz yuzu-045d0b5bbdf790952ddfedcfc8816c0afc7a2300.zip | |
Merge pull request #2799 from yuriks/virtual-cached-range-flush
Add address conversion functions returning optional, Add function to flush virtual region from rasterizer cache
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/y2r_u.cpp | 4 | ||||
| -rw-r--r-- | src/core/memory.cpp | 128 | ||||
| -rw-r--r-- | src/core/memory.h | 34 |
6 files changed, 113 insertions, 68 deletions
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 922e5ab58..a7b66142f 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -149,7 +149,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 149 | 149 | ||
| 150 | if (base_address == 0 && target_address == 0) { | 150 | if (base_address == 0 && target_address == 0) { |
| 151 | // Calculate the address at which to map the memory block. | 151 | // Calculate the address at which to map the memory block. |
| 152 | target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address); | 152 | target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address).value(); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | // Map the memory block into the target process | 155 | // Map the memory block into the target process |
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index df4b5cc3f..5c44b43bb 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -85,7 +85,7 @@ void GetSharedFont(Service::Interface* self) { | |||
| 85 | // The shared font has to be relocated to the new address before being passed to the | 85 | // The shared font has to be relocated to the new address before being passed to the |
| 86 | // application. | 86 | // application. |
| 87 | VAddr target_address = | 87 | VAddr target_address = |
| 88 | Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address); | 88 | Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address).value(); |
| 89 | if (!shared_font_relocated) { | 89 | if (!shared_font_relocated) { |
| 90 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); | 90 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); |
| 91 | shared_font_relocated = true; | 91 | shared_font_relocated = true; |
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index bc964ec60..88684b82d 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -475,12 +475,11 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 475 | 475 | ||
| 476 | // TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever | 476 | // TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever |
| 477 | // possible/likely | 477 | // possible/likely |
| 478 | Memory::RasterizerFlushRegion( | 478 | Memory::RasterizerFlushVirtualRegion(command.dma_request.source_address, |
| 479 | Memory::VirtualToPhysicalAddress(command.dma_request.source_address), | 479 | command.dma_request.size, Memory::FlushMode::Flush); |
| 480 | command.dma_request.size); | 480 | Memory::RasterizerFlushVirtualRegion(command.dma_request.dest_address, |
| 481 | Memory::RasterizerFlushAndInvalidateRegion( | 481 | command.dma_request.size, |
| 482 | Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), | 482 | Memory::FlushMode::FlushAndInvalidate); |
| 483 | command.dma_request.size); | ||
| 484 | 483 | ||
| 485 | // TODO(Subv): These memory accesses should not go through the application's memory mapping. | 484 | // TODO(Subv): These memory accesses should not go through the application's memory mapping. |
| 486 | // They should go through the GSP module's memory mapping. | 485 | // They should go through the GSP module's memory mapping. |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index e73971d5f..57172ddd6 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -587,8 +587,8 @@ static void StartConversion(Interface* self) { | |||
| 587 | // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( | 587 | // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( |
| 588 | u32 total_output_size = | 588 | u32 total_output_size = |
| 589 | conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); | 589 | conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); |
| 590 | Memory::RasterizerFlushAndInvalidateRegion( | 590 | Memory::RasterizerFlushVirtualRegion(conversion.dst.address, total_output_size, |
| 591 | Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); | 591 | Memory::FlushMode::FlushAndInvalidate); |
| 592 | 592 | ||
| 593 | HW::Y2R::PerformConversion(conversion); | 593 | HW::Y2R::PerformConversion(conversion); |
| 594 | 594 | ||
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9024f4922..65649d9d7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -83,19 +83,13 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 83 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, | 83 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, |
| 84 | (base + size) * PAGE_SIZE); | 84 | (base + size) * PAGE_SIZE); |
| 85 | 85 | ||
| 86 | u32 end = base + size; | 86 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, |
| 87 | FlushMode::FlushAndInvalidate); | ||
| 87 | 88 | ||
| 89 | u32 end = base + size; | ||
| 88 | while (base != end) { | 90 | while (base != end) { |
| 89 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); | 91 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); |
| 90 | 92 | ||
| 91 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 92 | // null here | ||
| 93 | if (current_page_table->attributes[base] == PageType::RasterizerCachedMemory || | ||
| 94 | current_page_table->attributes[base] == PageType::RasterizerCachedSpecial) { | ||
| 95 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(base << PAGE_BITS), | ||
| 96 | PAGE_SIZE); | ||
| 97 | } | ||
| 98 | |||
| 99 | current_page_table->attributes[base] = type; | 93 | current_page_table->attributes[base] = type; |
| 100 | current_page_table->pointers[base] = memory; | 94 | current_page_table->pointers[base] = memory; |
| 101 | current_page_table->cached_res_count[base] = 0; | 95 | current_page_table->cached_res_count[base] = 0; |
| @@ -196,7 +190,7 @@ T Read(const VAddr vaddr) { | |||
| 196 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 190 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 197 | break; | 191 | break; |
| 198 | case PageType::RasterizerCachedMemory: { | 192 | case PageType::RasterizerCachedMemory: { |
| 199 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 193 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| 200 | 194 | ||
| 201 | T value; | 195 | T value; |
| 202 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); | 196 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); |
| @@ -205,8 +199,7 @@ T Read(const VAddr vaddr) { | |||
| 205 | case PageType::Special: | 199 | case PageType::Special: |
| 206 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | 200 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); |
| 207 | case PageType::RasterizerCachedSpecial: { | 201 | case PageType::RasterizerCachedSpecial: { |
| 208 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 202 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| 209 | |||
| 210 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | 203 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); |
| 211 | } | 204 | } |
| 212 | default: | 205 | default: |
| @@ -236,8 +229,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 236 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 229 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 237 | break; | 230 | break; |
| 238 | case PageType::RasterizerCachedMemory: { | 231 | case PageType::RasterizerCachedMemory: { |
| 239 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 232 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate); |
| 240 | |||
| 241 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); | 233 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); |
| 242 | break; | 234 | break; |
| 243 | } | 235 | } |
| @@ -245,8 +237,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 245 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | 237 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); |
| 246 | break; | 238 | break; |
| 247 | case PageType::RasterizerCachedSpecial: { | 239 | case PageType::RasterizerCachedSpecial: { |
| 248 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 240 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate); |
| 249 | |||
| 250 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | 241 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); |
| 251 | break; | 242 | break; |
| 252 | } | 243 | } |
| @@ -275,7 +266,8 @@ bool IsValidVirtualAddress(const VAddr vaddr) { | |||
| 275 | } | 266 | } |
| 276 | 267 | ||
| 277 | bool IsValidPhysicalAddress(const PAddr paddr) { | 268 | bool IsValidPhysicalAddress(const PAddr paddr) { |
| 278 | return IsValidVirtualAddress(PhysicalToVirtualAddress(paddr)); | 269 | boost::optional<VAddr> vaddr = PhysicalToVirtualAddress(paddr); |
| 270 | return vaddr && IsValidVirtualAddress(*vaddr); | ||
| 279 | } | 271 | } |
| 280 | 272 | ||
| 281 | u8* GetPointer(const VAddr vaddr) { | 273 | u8* GetPointer(const VAddr vaddr) { |
| @@ -308,7 +300,8 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) { | |||
| 308 | 300 | ||
| 309 | u8* GetPhysicalPointer(PAddr address) { | 301 | u8* GetPhysicalPointer(PAddr address) { |
| 310 | // TODO(Subv): This call should not go through the application's memory mapping. | 302 | // TODO(Subv): This call should not go through the application's memory mapping. |
| 311 | return GetPointer(PhysicalToVirtualAddress(address)); | 303 | boost::optional<VAddr> vaddr = PhysicalToVirtualAddress(address); |
| 304 | return vaddr ? GetPointer(*vaddr) : nullptr; | ||
| 312 | } | 305 | } |
| 313 | 306 | ||
| 314 | void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | 307 | void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { |
| @@ -319,8 +312,12 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | |||
| 319 | u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; | 312 | u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; |
| 320 | PAddr paddr = start; | 313 | PAddr paddr = start; |
| 321 | 314 | ||
| 322 | for (unsigned i = 0; i < num_pages; ++i) { | 315 | for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { |
| 323 | VAddr vaddr = PhysicalToVirtualAddress(paddr); | 316 | boost::optional<VAddr> maybe_vaddr = PhysicalToVirtualAddress(paddr); |
| 317 | if (!maybe_vaddr) | ||
| 318 | continue; | ||
| 319 | VAddr vaddr = *maybe_vaddr; | ||
| 320 | |||
| 324 | u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; | 321 | u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; |
| 325 | ASSERT_MSG(count_delta <= UINT8_MAX - res_count, | 322 | ASSERT_MSG(count_delta <= UINT8_MAX - res_count, |
| 326 | "Rasterizer resource cache counter overflow!"); | 323 | "Rasterizer resource cache counter overflow!"); |
| @@ -368,7 +365,6 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | |||
| 368 | UNREACHABLE(); | 365 | UNREACHABLE(); |
| 369 | } | 366 | } |
| 370 | } | 367 | } |
| 371 | paddr += PAGE_SIZE; | ||
| 372 | } | 368 | } |
| 373 | } | 369 | } |
| 374 | 370 | ||
| @@ -379,11 +375,48 @@ void RasterizerFlushRegion(PAddr start, u32 size) { | |||
| 379 | } | 375 | } |
| 380 | 376 | ||
| 381 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { | 377 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { |
| 378 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 379 | // null here | ||
| 382 | if (VideoCore::g_renderer != nullptr) { | 380 | if (VideoCore::g_renderer != nullptr) { |
| 383 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); | 381 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); |
| 384 | } | 382 | } |
| 385 | } | 383 | } |
| 386 | 384 | ||
| 385 | void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) { | ||
| 386 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 387 | // null here | ||
| 388 | if (VideoCore::g_renderer != nullptr) { | ||
| 389 | VAddr end = start + size; | ||
| 390 | |||
| 391 | auto CheckRegion = [&](VAddr region_start, VAddr region_end) { | ||
| 392 | if (start >= region_end || end <= region_start) { | ||
| 393 | // No overlap with region | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | VAddr overlap_start = std::max(start, region_start); | ||
| 398 | VAddr overlap_end = std::min(end, region_end); | ||
| 399 | |||
| 400 | PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value(); | ||
| 401 | u32 overlap_size = overlap_end - overlap_start; | ||
| 402 | |||
| 403 | auto* rasterizer = VideoCore::g_renderer->Rasterizer(); | ||
| 404 | switch (mode) { | ||
| 405 | case FlushMode::Flush: | ||
| 406 | rasterizer->FlushRegion(physical_start, overlap_size); | ||
| 407 | break; | ||
| 408 | case FlushMode::FlushAndInvalidate: | ||
| 409 | rasterizer->FlushAndInvalidateRegion(physical_start, overlap_size); | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | }; | ||
| 413 | |||
| 414 | CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END); | ||
| 415 | CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END); | ||
| 416 | CheckRegion(VRAM_VADDR, VRAM_VADDR_END); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 387 | u8 Read8(const VAddr addr) { | 420 | u8 Read8(const VAddr addr) { |
| 388 | return Read<u8>(addr); | 421 | return Read<u8>(addr); |
| 389 | } | 422 | } |
| @@ -430,16 +463,13 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { | |||
| 430 | break; | 463 | break; |
| 431 | } | 464 | } |
| 432 | case PageType::RasterizerCachedMemory: { | 465 | case PageType::RasterizerCachedMemory: { |
| 433 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | 466 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); |
| 434 | |||
| 435 | std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); | 467 | std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); |
| 436 | break; | 468 | break; |
| 437 | } | 469 | } |
| 438 | case PageType::RasterizerCachedSpecial: { | 470 | case PageType::RasterizerCachedSpecial: { |
| 439 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 471 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 440 | 472 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); | |
| 441 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | ||
| 442 | |||
| 443 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); | 473 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); |
| 444 | break; | 474 | break; |
| 445 | } | 475 | } |
| @@ -500,18 +530,13 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size | |||
| 500 | break; | 530 | break; |
| 501 | } | 531 | } |
| 502 | case PageType::RasterizerCachedMemory: { | 532 | case PageType::RasterizerCachedMemory: { |
| 503 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | 533 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); |
| 504 | copy_amount); | ||
| 505 | |||
| 506 | std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); | 534 | std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); |
| 507 | break; | 535 | break; |
| 508 | } | 536 | } |
| 509 | case PageType::RasterizerCachedSpecial: { | 537 | case PageType::RasterizerCachedSpecial: { |
| 510 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 538 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 511 | 539 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); | |
| 512 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | ||
| 513 | copy_amount); | ||
| 514 | |||
| 515 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); | 540 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); |
| 516 | break; | 541 | break; |
| 517 | } | 542 | } |
| @@ -557,18 +582,13 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { | |||
| 557 | break; | 582 | break; |
| 558 | } | 583 | } |
| 559 | case PageType::RasterizerCachedMemory: { | 584 | case PageType::RasterizerCachedMemory: { |
| 560 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | 585 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); |
| 561 | copy_amount); | ||
| 562 | |||
| 563 | std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); | 586 | std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); |
| 564 | break; | 587 | break; |
| 565 | } | 588 | } |
| 566 | case PageType::RasterizerCachedSpecial: { | 589 | case PageType::RasterizerCachedSpecial: { |
| 567 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 590 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 568 | 591 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); | |
| 569 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | ||
| 570 | copy_amount); | ||
| 571 | |||
| 572 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); | 592 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); |
| 573 | break; | 593 | break; |
| 574 | } | 594 | } |
| @@ -613,15 +633,13 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | |||
| 613 | break; | 633 | break; |
| 614 | } | 634 | } |
| 615 | case PageType::RasterizerCachedMemory: { | 635 | case PageType::RasterizerCachedMemory: { |
| 616 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | 636 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); |
| 617 | |||
| 618 | WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); | 637 | WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); |
| 619 | break; | 638 | break; |
| 620 | } | 639 | } |
| 621 | case PageType::RasterizerCachedSpecial: { | 640 | case PageType::RasterizerCachedSpecial: { |
| 622 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 641 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 623 | 642 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); | |
| 624 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | ||
| 625 | 643 | ||
| 626 | std::vector<u8> buffer(copy_amount); | 644 | std::vector<u8> buffer(copy_amount); |
| 627 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); | 645 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); |
| @@ -680,7 +698,7 @@ void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) | |||
| 680 | mmio_handler->Write64(addr, data); | 698 | mmio_handler->Write64(addr, data); |
| 681 | } | 699 | } |
| 682 | 700 | ||
| 683 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | 701 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { |
| 684 | if (addr == 0) { | 702 | if (addr == 0) { |
| 685 | return 0; | 703 | return 0; |
| 686 | } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { | 704 | } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { |
| @@ -697,12 +715,20 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) { | |||
| 697 | return addr - N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_PADDR; | 715 | return addr - N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_PADDR; |
| 698 | } | 716 | } |
| 699 | 717 | ||
| 700 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); | 718 | return boost::none; |
| 701 | // To help with debugging, set bit on address so that it's obviously invalid. | 719 | } |
| 702 | return addr | 0x80000000; | 720 | |
| 721 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | ||
| 722 | auto paddr = TryVirtualToPhysicalAddress(addr); | ||
| 723 | if (!paddr) { | ||
| 724 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); | ||
| 725 | // To help with debugging, set bit on address so that it's obviously invalid. | ||
| 726 | return addr | 0x80000000; | ||
| 727 | } | ||
| 728 | return *paddr; | ||
| 703 | } | 729 | } |
| 704 | 730 | ||
| 705 | VAddr PhysicalToVirtualAddress(const PAddr addr) { | 731 | boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) { |
| 706 | if (addr == 0) { | 732 | if (addr == 0) { |
| 707 | return 0; | 733 | return 0; |
| 708 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { | 734 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { |
| @@ -717,9 +743,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { | |||
| 717 | return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; | 743 | return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; |
| 718 | } | 744 | } |
| 719 | 745 | ||
| 720 | LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08X", addr); | 746 | return boost::none; |
| 721 | // To help with debugging, set bit on address so that it's obviously invalid. | ||
| 722 | return addr | 0x80000000; | ||
| 723 | } | 747 | } |
| 724 | 748 | ||
| 725 | } // namespace | 749 | } // namespace |
diff --git a/src/core/memory.h b/src/core/memory.h index 71fb278ad..c8c56babd 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <boost/optional.hpp> | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| 12 | namespace Memory { | 13 | namespace Memory { |
| @@ -148,15 +149,23 @@ u8* GetPointer(VAddr virtual_address); | |||
| 148 | std::string ReadCString(VAddr virtual_address, std::size_t max_length); | 149 | std::string ReadCString(VAddr virtual_address, std::size_t max_length); |
| 149 | 150 | ||
| 150 | /** | 151 | /** |
| 151 | * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical | 152 | * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical |
| 152 | * address. This should be used by services to translate addresses for use by the hardware. | 153 | * address. This should be used by services to translate addresses for use by the hardware. |
| 153 | */ | 154 | */ |
| 155 | boost::optional<PAddr> TryVirtualToPhysicalAddress(VAddr addr); | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical | ||
| 159 | * address. This should be used by services to translate addresses for use by the hardware. | ||
| 160 | * | ||
| 161 | * @deprecated Use TryVirtualToPhysicalAddress(), which reports failure. | ||
| 162 | */ | ||
| 154 | PAddr VirtualToPhysicalAddress(VAddr addr); | 163 | PAddr VirtualToPhysicalAddress(VAddr addr); |
| 155 | 164 | ||
| 156 | /** | 165 | /** |
| 157 | * Undoes a mapping performed by VirtualToPhysicalAddress(). | 166 | * Undoes a mapping performed by VirtualToPhysicalAddress(). |
| 158 | */ | 167 | */ |
| 159 | VAddr PhysicalToVirtualAddress(PAddr addr); | 168 | boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr); |
| 160 | 169 | ||
| 161 | /** | 170 | /** |
| 162 | * Gets a pointer to the memory region beginning at the specified physical address. | 171 | * Gets a pointer to the memory region beginning at the specified physical address. |
| @@ -181,6 +190,19 @@ void RasterizerFlushRegion(PAddr start, u32 size); | |||
| 181 | */ | 190 | */ |
| 182 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size); | 191 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size); |
| 183 | 192 | ||
| 193 | enum class FlushMode { | ||
| 194 | /// Write back modified surfaces to RAM | ||
| 195 | Flush, | ||
| 196 | /// Write back modified surfaces to RAM, and also remove them from the cache | ||
| 197 | FlushAndInvalidate, | ||
| 198 | }; | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Flushes and invalidates any externally cached rasterizer resources touching the given virtual | ||
| 202 | * address region. | ||
| 203 | */ | ||
| 204 | void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode); | ||
| 205 | |||
| 184 | /** | 206 | /** |
| 185 | * Dynarmic has an optimization to memory accesses when the pointer to the page exists that | 207 | * Dynarmic has an optimization to memory accesses when the pointer to the page exists that |
| 186 | * can be used by setting up the current page table as a callback. This function is used to | 208 | * can be used by setting up the current page table as a callback. This function is used to |