citra-emu
/
citra
Archived
1
0
Fork 0

Memory: Add function to flush a virtual range from the rasterizer cache

This is slightly more ergonomic to use, correctly handles virtual
regions which are disjoint in physical addressing space, and checks only
regions which can be cached by the rasterizer.
This commit is contained in:
Yuri Kunde Schlesner 2017-06-21 22:48:00 -07:00
parent 6ae0086b39
commit d553135748
4 changed files with 72 additions and 47 deletions

View File

@ -475,12 +475,11 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
// TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever // TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever
// possible/likely // possible/likely
Memory::RasterizerFlushRegion( Memory::RasterizerFlushVirtualRegion(command.dma_request.source_address,
Memory::VirtualToPhysicalAddress(command.dma_request.source_address), command.dma_request.size, Memory::FlushMode::Flush);
command.dma_request.size); Memory::RasterizerFlushVirtualRegion(command.dma_request.dest_address,
Memory::RasterizerFlushAndInvalidateRegion( command.dma_request.size,
Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), Memory::FlushMode::FlushAndInvalidate);
command.dma_request.size);
// TODO(Subv): These memory accesses should not go through the application's memory mapping. // TODO(Subv): These memory accesses should not go through the application's memory mapping.
// They should go through the GSP module's memory mapping. // They should go through the GSP module's memory mapping.

View File

@ -587,8 +587,8 @@ static void StartConversion(Interface* self) {
// dst_image_size would seem to be perfect for this, but it doesn't include the gap :( // dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
u32 total_output_size = u32 total_output_size =
conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap);
Memory::RasterizerFlushAndInvalidateRegion( Memory::RasterizerFlushVirtualRegion(conversion.dst.address, total_output_size,
Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); Memory::FlushMode::FlushAndInvalidate);
HW::Y2R::PerformConversion(conversion); HW::Y2R::PerformConversion(conversion);

View File

@ -83,19 +83,13 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE,
(base + size) * PAGE_SIZE); (base + size) * PAGE_SIZE);
u32 end = base + size; RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
FlushMode::FlushAndInvalidate);
u32 end = base + size;
while (base != end) { while (base != end) {
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base);
// Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
// null here
if (current_page_table->attributes[base] == PageType::RasterizerCachedMemory ||
current_page_table->attributes[base] == PageType::RasterizerCachedSpecial) {
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(base << PAGE_BITS),
PAGE_SIZE);
}
current_page_table->attributes[base] = type; current_page_table->attributes[base] = type;
current_page_table->pointers[base] = memory; current_page_table->pointers[base] = memory;
current_page_table->cached_res_count[base] = 0; current_page_table->cached_res_count[base] = 0;
@ -189,7 +183,7 @@ T Read(const VAddr vaddr) {
ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
break; break;
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush);
T value; T value;
std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T));
@ -198,8 +192,7 @@ T Read(const VAddr vaddr) {
case PageType::Special: case PageType::Special:
return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush);
return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
} }
default: default:
@ -229,8 +222,7 @@ void Write(const VAddr vaddr, const T data) {
ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
break; break;
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate);
std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T));
break; break;
} }
@ -238,8 +230,7 @@ void Write(const VAddr vaddr, const T data) {
WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
break; break;
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate);
WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
break; break;
} }
@ -369,11 +360,48 @@ void RasterizerFlushRegion(PAddr start, u32 size) {
} }
void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) {
// Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
// null here
if (VideoCore::g_renderer != nullptr) { if (VideoCore::g_renderer != nullptr) {
VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size);
} }
} }
void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) {
// Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
// null here
if (VideoCore::g_renderer != nullptr) {
VAddr end = start + size;
auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
if (start >= region_end || end <= region_start) {
// No overlap with region
return;
}
VAddr overlap_start = std::max(start, region_start);
VAddr overlap_end = std::min(end, region_end);
PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value();
u32 overlap_size = overlap_end - overlap_start;
auto* rasterizer = VideoCore::g_renderer->Rasterizer();
switch (mode) {
case FlushMode::Flush:
rasterizer->FlushRegion(physical_start, overlap_size);
break;
case FlushMode::FlushAndInvalidate:
rasterizer->FlushAndInvalidateRegion(physical_start, overlap_size);
break;
}
};
CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END);
CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END);
CheckRegion(VRAM_VADDR, VRAM_VADDR_END);
}
}
u8 Read8(const VAddr addr) { u8 Read8(const VAddr addr) {
return Read<u8>(addr); return Read<u8>(addr);
} }
@ -420,16 +448,13 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) {
break; break;
} }
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush);
std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount);
break; break;
} }
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush);
RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount);
break; break;
} }
@ -490,18 +515,13 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size
break; break;
} }
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate);
copy_amount);
std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount);
break; break;
} }
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate);
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr),
copy_amount);
GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount);
break; break;
} }
@ -547,18 +567,13 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) {
break; break;
} }
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate);
copy_amount);
std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount);
break; break;
} }
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate);
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr),
copy_amount);
GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount);
break; break;
} }
@ -603,15 +618,13 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) {
break; break;
} }
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush);
WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount);
break; break;
} }
case PageType::RasterizerCachedSpecial: { case PageType::RasterizerCachedSpecial: {
DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); DEBUG_ASSERT(GetMMIOHandler(current_vaddr));
RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush);
RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount);
std::vector<u8> buffer(copy_amount); std::vector<u8> buffer(copy_amount);
GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size());

View File

@ -190,6 +190,19 @@ void RasterizerFlushRegion(PAddr start, u32 size);
*/ */
void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size); void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size);
enum class FlushMode {
/// Write back modified surfaces to RAM
Flush,
/// Write back modified surfaces to RAM, and also remove them from the cache
FlushAndInvalidate,
};
/**
* Flushes and invalidates any externally cached rasterizer resources touching the given virtual
* address region.
*/
void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode);
/** /**
* Dynarmic has an optimization to memory accesses when the pointer to the page exists that * Dynarmic has an optimization to memory accesses when the pointer to the page exists that
* can be used by setting up the current page table as a callback. This function is used to * can be used by setting up the current page table as a callback. This function is used to