HWRasterizer: Texture forwarding
This commit is contained in:
parent
621cf30b24
commit
459035a108
20 changed files with 1749 additions and 970 deletions
|
@ -15,6 +15,9 @@
|
|||
#include "core/memory_setup.h"
|
||||
#include "core/mmio.h"
|
||||
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Memory {
|
||||
|
||||
enum class PageType {
|
||||
|
@ -22,8 +25,12 @@ enum class PageType {
|
|||
Unmapped,
|
||||
/// Page is mapped to regular memory. This is the only type you can get pointers to.
|
||||
Memory,
|
||||
/// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and invalidation
|
||||
RasterizerCachedMemory,
|
||||
/// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
|
||||
Special,
|
||||
/// Page is mapped to a I/O region, but also needs to check for rasterizer cache flushing and invalidation
|
||||
RasterizerCachedSpecial,
|
||||
};
|
||||
|
||||
struct SpecialRegion {
|
||||
|
@ -57,6 +64,12 @@ struct PageTable {
|
|||
* the corresponding entry in `pointers` MUST be set to null.
|
||||
*/
|
||||
std::array<PageType, NUM_ENTRIES> attributes;
|
||||
|
||||
/**
|
||||
* Indicates the number of externally cached resources touching a page that should be
|
||||
* flushed before the memory is accessed
|
||||
*/
|
||||
std::array<u8, NUM_ENTRIES> cached_res_count;
|
||||
};
|
||||
|
||||
/// Singular page table used for the singleton process
|
||||
|
@ -72,8 +85,15 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
|
|||
while (base != end) {
|
||||
ASSERT_MSG(base < PageTable::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->pointers[base] = memory;
|
||||
current_page_table->cached_res_count[base] = 0;
|
||||
|
||||
base += 1;
|
||||
if (memory != nullptr)
|
||||
|
@ -84,6 +104,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
|
|||
void InitMemoryMap() {
|
||||
main_page_table.pointers.fill(nullptr);
|
||||
main_page_table.attributes.fill(PageType::Unmapped);
|
||||
main_page_table.cached_res_count.fill(0);
|
||||
}
|
||||
|
||||
void MapMemoryRegion(VAddr base, u32 size, u8* target) {
|
||||
|
@ -106,6 +127,28 @@ void UnmapRegion(VAddr base, u32 size) {
|
|||
MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
|
||||
* using a VMA from the current process
|
||||
*/
|
||||
static u8* GetPointerFromVMA(VAddr vaddr) {
|
||||
u8* direct_pointer = nullptr;
|
||||
|
||||
auto& vma = Kernel::g_current_process->vm_manager.FindVMA(vaddr)->second;
|
||||
switch (vma.type) {
|
||||
case Kernel::VMAType::AllocatedMemoryBlock:
|
||||
direct_pointer = vma.backing_block->data() + vma.offset;
|
||||
break;
|
||||
case Kernel::VMAType::BackingMemory:
|
||||
direct_pointer = vma.backing_memory;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return direct_pointer + (vaddr - vma.base);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should only be called for virtual addreses with attribute `PageType::Special`.
|
||||
*/
|
||||
|
@ -126,6 +169,7 @@ template <typename T>
|
|||
T Read(const VAddr vaddr) {
|
||||
const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
T value;
|
||||
std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
|
||||
return value;
|
||||
|
@ -139,8 +183,22 @@ T Read(const VAddr vaddr) {
|
|||
case PageType::Memory:
|
||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
|
||||
break;
|
||||
case PageType::RasterizerCachedMemory:
|
||||
{
|
||||
RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T));
|
||||
|
||||
T value;
|
||||
std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T));
|
||||
return value;
|
||||
}
|
||||
case PageType::Special:
|
||||
return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
|
||||
case PageType::RasterizerCachedSpecial:
|
||||
{
|
||||
RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T));
|
||||
|
||||
return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -153,6 +211,7 @@ template <typename T>
|
|||
void Write(const VAddr vaddr, const T data) {
|
||||
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
|
||||
return;
|
||||
}
|
||||
|
@ -165,9 +224,23 @@ void Write(const VAddr vaddr, const T data) {
|
|||
case PageType::Memory:
|
||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
|
||||
break;
|
||||
case PageType::RasterizerCachedMemory:
|
||||
{
|
||||
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T));
|
||||
|
||||
std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T));
|
||||
break;
|
||||
}
|
||||
case PageType::Special:
|
||||
WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
|
||||
break;
|
||||
case PageType::RasterizerCachedSpecial:
|
||||
{
|
||||
RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T));
|
||||
|
||||
WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -179,6 +252,10 @@ u8* GetPointer(const VAddr vaddr) {
|
|||
return page_pointer + (vaddr & PAGE_MASK);
|
||||
}
|
||||
|
||||
if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) {
|
||||
return GetPointerFromVMA(vaddr);
|
||||
}
|
||||
|
||||
LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -187,6 +264,69 @@ u8* GetPhysicalPointer(PAddr address) {
|
|||
return GetPointer(PhysicalToVirtualAddress(address));
|
||||
}
|
||||
|
||||
void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
|
||||
if (start == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1;
|
||||
PAddr paddr = start;
|
||||
|
||||
for (unsigned i = 0; i < num_pages; ++i) {
|
||||
VAddr vaddr = PhysicalToVirtualAddress(paddr);
|
||||
u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS];
|
||||
ASSERT_MSG(count_delta <= UINT8_MAX - res_count, "Rasterizer resource cache counter overflow!");
|
||||
ASSERT_MSG(count_delta >= -res_count, "Rasterizer resource cache counter underflow!");
|
||||
|
||||
// Switch page type to cached if now cached
|
||||
if (res_count == 0) {
|
||||
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
switch (page_type) {
|
||||
case PageType::Memory:
|
||||
page_type = PageType::RasterizerCachedMemory;
|
||||
current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
||||
break;
|
||||
case PageType::Special:
|
||||
page_type = PageType::RasterizerCachedSpecial;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
res_count += count_delta;
|
||||
|
||||
// Switch page type to uncached if now uncached
|
||||
if (res_count == 0) {
|
||||
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
switch (page_type) {
|
||||
case PageType::RasterizerCachedMemory:
|
||||
page_type = PageType::Memory;
|
||||
current_page_table->pointers[vaddr >> PAGE_BITS] = GetPointerFromVMA(vaddr & ~PAGE_MASK);
|
||||
break;
|
||||
case PageType::RasterizerCachedSpecial:
|
||||
page_type = PageType::Special;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
paddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerFlushRegion(PAddr start, u32 size) {
|
||||
if (VideoCore::g_renderer != nullptr) {
|
||||
VideoCore::g_renderer->Rasterizer()->FlushRegion(start, size);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) {
|
||||
if (VideoCore::g_renderer != nullptr) {
|
||||
VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size);
|
||||
}
|
||||
}
|
||||
|
||||
u8 Read8(const VAddr addr) {
|
||||
return Read<u8>(addr);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue