diff options
| author | 2016-04-16 18:57:57 -0400 | |
|---|---|---|
| committer | 2016-04-21 17:27:56 -0400 | |
| commit | 22f3a7e94ce0e325a8c3dfeb0814c4b82a42649d (patch) | |
| tree | fb0dc58288063f755eda7bc0f8cfb7e9573e397d /src/core/memory.cpp | |
| parent | Config: Add scaled resolution option (diff) | |
| download | yuzu-22f3a7e94ce0e325a8c3dfeb0814c4b82a42649d.tar.gz yuzu-22f3a7e94ce0e325a8c3dfeb0814c4b82a42649d.tar.xz yuzu-22f3a7e94ce0e325a8c3dfeb0814c4b82a42649d.zip | |
HWRasterizer: Texture forwarding
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 7de5bd15d..ee9b69f81 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -15,6 +15,9 @@ | |||
| 15 | #include "core/memory_setup.h" | 15 | #include "core/memory_setup.h" |
| 16 | #include "core/mmio.h" | 16 | #include "core/mmio.h" |
| 17 | 17 | ||
| 18 | #include "video_core/renderer_base.h" | ||
| 19 | #include "video_core/video_core.h" | ||
| 20 | |||
| 18 | namespace Memory { | 21 | namespace Memory { |
| 19 | 22 | ||
| 20 | enum class PageType { | 23 | enum class PageType { |
| @@ -22,8 +25,12 @@ enum class PageType { | |||
| 22 | Unmapped, | 25 | Unmapped, |
| 23 | /// Page is mapped to regular memory. This is the only type you can get pointers to. | 26 | /// Page is mapped to regular memory. This is the only type you can get pointers to. |
| 24 | Memory, | 27 | Memory, |
| 28 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and invalidation | ||
| 29 | RasterizerCachedMemory, | ||
| 25 | /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. | 30 | /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. |
| 26 | Special, | 31 | Special, |
| 32 | /// Page is mapped to a I/O region, but also needs to check for rasterizer cache flushing and invalidation | ||
| 33 | RasterizerCachedSpecial, | ||
| 27 | }; | 34 | }; |
| 28 | 35 | ||
| 29 | struct SpecialRegion { | 36 | struct SpecialRegion { |
| @@ -57,6 +64,12 @@ struct PageTable { | |||
| 57 | * the corresponding entry in `pointers` MUST be set to null. | 64 | * the corresponding entry in `pointers` MUST be set to null. |
| 58 | */ | 65 | */ |
| 59 | std::array<PageType, NUM_ENTRIES> attributes; | 66 | std::array<PageType, NUM_ENTRIES> attributes; |
| 67 | |||
| 68 | /** | ||
| 69 | * Indicates the number of externally cached resources touching a page that should be | ||
| 70 | * flushed before the memory is accessed | ||
| 71 | */ | ||
| 72 | std::array<u8, NUM_ENTRIES> cached_res_count; | ||
| 60 | }; | 73 | }; |
| 61 | 74 | ||
| 62 | /// Singular page table used for the singleton process | 75 | /// Singular page table used for the singleton process |
| @@ -72,8 +85,15 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 72 | while (base != end) { | 85 | while (base != end) { |
| 73 | ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); | 86 | ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); |
| 74 | 87 | ||
| 88 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be null here | ||
| 89 | if (current_page_table->attributes[base] == PageType::RasterizerCachedMemory || | ||
| 90 | current_page_table->attributes[base] == PageType::RasterizerCachedSpecial) { | ||
| 91 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(base << PAGE_BITS), PAGE_SIZE); | ||
| 92 | } | ||
| 93 | |||
| 75 | current_page_table->attributes[base] = type; | 94 | current_page_table->attributes[base] = type; |
| 76 | current_page_table->pointers[base] = memory; | 95 | current_page_table->pointers[base] = memory; |
| 96 | current_page_table->cached_res_count[base] = 0; | ||
| 77 | 97 | ||
| 78 | base += 1; | 98 | base += 1; |
| 79 | if (memory != nullptr) | 99 | if (memory != nullptr) |
| @@ -84,6 +104,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 84 | void InitMemoryMap() { | 104 | void InitMemoryMap() { |
| 85 | main_page_table.pointers.fill(nullptr); | 105 | main_page_table.pointers.fill(nullptr); |
| 86 | main_page_table.attributes.fill(PageType::Unmapped); | 106 | main_page_table.attributes.fill(PageType::Unmapped); |
| 107 | main_page_table.cached_res_count.fill(0); | ||
| 87 | } | 108 | } |
| 88 | 109 | ||
| 89 | void MapMemoryRegion(VAddr base, u32 size, u8* target) { | 110 | void MapMemoryRegion(VAddr base, u32 size, u8* target) { |
| @@ -107,6 +128,28 @@ void UnmapRegion(VAddr base, u32 size) { | |||
| 107 | } | 128 | } |
| 108 | 129 | ||
| 109 | /** | 130 | /** |
| 131 | * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) | ||
| 132 | * using a VMA from the current process | ||
| 133 | */ | ||
| 134 | static u8* GetPointerFromVMA(VAddr vaddr) { | ||
| 135 | u8* direct_pointer = nullptr; | ||
| 136 | |||
| 137 | auto& vma = Kernel::g_current_process->vm_manager.FindVMA(vaddr)->second; | ||
| 138 | switch (vma.type) { | ||
| 139 | case Kernel::VMAType::AllocatedMemoryBlock: | ||
| 140 | direct_pointer = vma.backing_block->data() + vma.offset; | ||
| 141 | break; | ||
| 142 | case Kernel::VMAType::BackingMemory: | ||
| 143 | direct_pointer = vma.backing_memory; | ||
| 144 | break; | ||
| 145 | default: | ||
| 146 | UNREACHABLE(); | ||
| 147 | } | ||
| 148 | |||
| 149 | return direct_pointer + (vaddr - vma.base); | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 110 | * This function should only be called for virtual addreses with attribute `PageType::Special`. | 153 | * This function should only be called for virtual addreses with attribute `PageType::Special`. |
| 111 | */ | 154 | */ |
| 112 | static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { | 155 | static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { |
| @@ -126,6 +169,7 @@ template <typename T> | |||
| 126 | T Read(const VAddr vaddr) { | 169 | T Read(const VAddr vaddr) { |
| 127 | const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 170 | const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
| 128 | if (page_pointer) { | 171 | if (page_pointer) { |
| 172 | // NOTE: Avoid adding any extra logic to this fast-path block | ||
| 129 | T value; | 173 | T value; |
| 130 | std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); | 174 | std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); |
| 131 | return value; | 175 | return value; |
| @@ -139,8 +183,22 @@ T Read(const VAddr vaddr) { | |||
| 139 | case PageType::Memory: | 183 | case PageType::Memory: |
| 140 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 184 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 141 | break; | 185 | break; |
| 186 | case PageType::RasterizerCachedMemory: | ||
| 187 | { | ||
| 188 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | ||
| 189 | |||
| 190 | T value; | ||
| 191 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); | ||
| 192 | return value; | ||
| 193 | } | ||
| 142 | case PageType::Special: | 194 | case PageType::Special: |
| 143 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | 195 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); |
| 196 | case PageType::RasterizerCachedSpecial: | ||
| 197 | { | ||
| 198 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | ||
| 199 | |||
| 200 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | ||
| 201 | } | ||
| 144 | default: | 202 | default: |
| 145 | UNREACHABLE(); | 203 | UNREACHABLE(); |
| 146 | } | 204 | } |
| @@ -153,6 +211,7 @@ template <typename T> | |||
| 153 | void Write(const VAddr vaddr, const T data) { | 211 | void Write(const VAddr vaddr, const T data) { |
| 154 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 212 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
| 155 | if (page_pointer) { | 213 | if (page_pointer) { |
| 214 | // NOTE: Avoid adding any extra logic to this fast-path block | ||
| 156 | std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); | 215 | std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); |
| 157 | return; | 216 | return; |
| 158 | } | 217 | } |
| @@ -165,9 +224,23 @@ void Write(const VAddr vaddr, const T data) { | |||
| 165 | case PageType::Memory: | 224 | case PageType::Memory: |
| 166 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 225 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 167 | break; | 226 | break; |
| 227 | case PageType::RasterizerCachedMemory: | ||
| 228 | { | ||
| 229 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | ||
| 230 | |||
| 231 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); | ||
| 232 | break; | ||
| 233 | } | ||
| 168 | case PageType::Special: | 234 | case PageType::Special: |
| 169 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | 235 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); |
| 170 | break; | 236 | break; |
| 237 | case PageType::RasterizerCachedSpecial: | ||
| 238 | { | ||
| 239 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | ||
| 240 | |||
| 241 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | ||
| 242 | break; | ||
| 243 | } | ||
| 171 | default: | 244 | default: |
| 172 | UNREACHABLE(); | 245 | UNREACHABLE(); |
| 173 | } | 246 | } |
| @@ -179,6 +252,10 @@ u8* GetPointer(const VAddr vaddr) { | |||
| 179 | return page_pointer + (vaddr & PAGE_MASK); | 252 | return page_pointer + (vaddr & PAGE_MASK); |
| 180 | } | 253 | } |
| 181 | 254 | ||
| 255 | if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) { | ||
| 256 | return GetPointerFromVMA(vaddr); | ||
| 257 | } | ||
| 258 | |||
| 182 | LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); | 259 | LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); |
| 183 | return nullptr; | 260 | return nullptr; |
| 184 | } | 261 | } |
| @@ -187,6 +264,69 @@ u8* GetPhysicalPointer(PAddr address) { | |||
| 187 | return GetPointer(PhysicalToVirtualAddress(address)); | 264 | return GetPointer(PhysicalToVirtualAddress(address)); |
| 188 | } | 265 | } |
| 189 | 266 | ||
| 267 | void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | ||
| 268 | if (start == 0) { | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; | ||
| 273 | PAddr paddr = start; | ||
| 274 | |||
| 275 | for (unsigned i = 0; i < num_pages; ++i) { | ||
| 276 | VAddr vaddr = PhysicalToVirtualAddress(paddr); | ||
| 277 | u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; | ||
| 278 | ASSERT_MSG(count_delta <= UINT8_MAX - res_count, "Rasterizer resource cache counter overflow!"); | ||
| 279 | ASSERT_MSG(count_delta >= -res_count, "Rasterizer resource cache counter underflow!"); | ||
| 280 | |||
| 281 | // Switch page type to cached if now cached | ||
| 282 | if (res_count == 0) { | ||
| 283 | PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 284 | switch (page_type) { | ||
| 285 | case PageType::Memory: | ||
| 286 | page_type = PageType::RasterizerCachedMemory; | ||
| 287 | current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; | ||
| 288 | break; | ||
| 289 | case PageType::Special: | ||
| 290 | page_type = PageType::RasterizerCachedSpecial; | ||
| 291 | break; | ||
| 292 | default: | ||
| 293 | UNREACHABLE(); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | res_count += count_delta; | ||
| 298 | |||
| 299 | // Switch page type to uncached if now uncached | ||
| 300 | if (res_count == 0) { | ||
| 301 | PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 302 | switch (page_type) { | ||
| 303 | case PageType::RasterizerCachedMemory: | ||
| 304 | page_type = PageType::Memory; | ||
| 305 | current_page_table->pointers[vaddr >> PAGE_BITS] = GetPointerFromVMA(vaddr & ~PAGE_MASK); | ||
| 306 | break; | ||
| 307 | case PageType::RasterizerCachedSpecial: | ||
| 308 | page_type = PageType::Special; | ||
| 309 | break; | ||
| 310 | default: | ||
| 311 | UNREACHABLE(); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | paddr += PAGE_SIZE; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | void RasterizerFlushRegion(PAddr start, u32 size) { | ||
| 319 | if (VideoCore::g_renderer != nullptr) { | ||
| 320 | VideoCore::g_renderer->Rasterizer()->FlushRegion(start, size); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { | ||
| 325 | if (VideoCore::g_renderer != nullptr) { | ||
| 326 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 190 | u8 Read8(const VAddr addr) { | 330 | u8 Read8(const VAddr addr) { |
| 191 | return Read<u8>(addr); | 331 | return Read<u8>(addr); |
| 192 | } | 332 | } |