diff options
| author | 2018-03-26 22:30:03 -0400 | |
|---|---|---|
| committer | 2018-03-26 22:30:03 -0400 | |
| commit | b4bf099793d8e9a065769c35bb4b8e20bf107549 (patch) | |
| tree | 2a9adcdcc7b3947242f3d4717302dc29425e8b0d /src | |
| parent | Merge pull request #283 from Subv/tsc (diff) | |
| parent | renderer_opengl: Use better naming for DrawScreens and DrawSingleScreen. (diff) | |
| download | yuzu-b4bf099793d8e9a065769c35bb4b8e20bf107549.tar.gz yuzu-b4bf099793d8e9a065769c35bb4b8e20bf107549.tar.xz yuzu-b4bf099793d8e9a065769c35bb4b8e20bf107549.zip | |
Merge pull request #279 from bunnei/tegra-progress-3
Tegra progress 3
Diffstat (limited to 'src')
20 files changed, 913 insertions, 446 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index d6469dd3d..291bf066f 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/hle/kernel/memory.h" | 16 | #include "core/hle/kernel/memory.h" |
| 17 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/lock.h" | ||
| 18 | #include "core/memory.h" | 19 | #include "core/memory.h" |
| 19 | #include "core/memory_setup.h" | 20 | #include "core/memory_setup.h" |
| 20 | #include "video_core/renderer_base.h" | 21 | #include "video_core/renderer_base.h" |
| @@ -115,91 +116,120 @@ static std::set<MemoryHookPointer> GetSpecialHandlers(VAddr vaddr, u64 size) { | |||
| 115 | return GetSpecialHandlers(page_table, vaddr, size); | 116 | return GetSpecialHandlers(page_table, vaddr, size); |
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | template <typename T> | 119 | /** |
| 119 | boost::optional<T> ReadSpecial(VAddr addr); | 120 | * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) |
| 121 | * using a VMA from the current process | ||
| 122 | */ | ||
| 123 | static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { | ||
| 124 | u8* direct_pointer = nullptr; | ||
| 125 | |||
| 126 | auto& vm_manager = process.vm_manager; | ||
| 127 | |||
| 128 | auto it = vm_manager.FindVMA(vaddr); | ||
| 129 | ASSERT(it != vm_manager.vma_map.end()); | ||
| 130 | |||
| 131 | auto& vma = it->second; | ||
| 132 | switch (vma.type) { | ||
| 133 | case Kernel::VMAType::AllocatedMemoryBlock: | ||
| 134 | direct_pointer = vma.backing_block->data() + vma.offset; | ||
| 135 | break; | ||
| 136 | case Kernel::VMAType::BackingMemory: | ||
| 137 | direct_pointer = vma.backing_memory; | ||
| 138 | break; | ||
| 139 | case Kernel::VMAType::Free: | ||
| 140 | return nullptr; | ||
| 141 | default: | ||
| 142 | UNREACHABLE(); | ||
| 143 | } | ||
| 144 | |||
| 145 | return direct_pointer + (vaddr - vma.base); | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) | ||
| 150 | * using a VMA from the current process. | ||
| 151 | */ | ||
| 152 | static u8* GetPointerFromVMA(VAddr vaddr) { | ||
| 153 | return GetPointerFromVMA(*Core::CurrentProcess(), vaddr); | ||
| 154 | } | ||
| 120 | 155 | ||
| 121 | template <typename T> | 156 | template <typename T> |
| 122 | T Read(const VAddr vaddr) { | 157 | T Read(const VAddr vaddr) { |
| 123 | if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { | 158 | const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
| 124 | LOG_ERROR(HW_Memory, "Read%lu after page table @ 0x%016" PRIX64, sizeof(T) * 8, vaddr); | 159 | if (page_pointer) { |
| 125 | return 0; | 160 | // NOTE: Avoid adding any extra logic to this fast-path block |
| 161 | T value; | ||
| 162 | std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); | ||
| 163 | return value; | ||
| 126 | } | 164 | } |
| 127 | 165 | ||
| 128 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 166 | // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state |
| 167 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 168 | |||
| 169 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 129 | switch (type) { | 170 | switch (type) { |
| 130 | case PageType::Unmapped: | 171 | case PageType::Unmapped: |
| 131 | LOG_ERROR(HW_Memory, "unmapped Read%zu @ 0x%016" PRIX64, sizeof(T) * 8, vaddr); | 172 | LOG_ERROR(HW_Memory, "unmapped Read%lu @ 0x%08X", sizeof(T) * 8, vaddr); |
| 132 | return 0; | 173 | return 0; |
| 133 | case PageType::Special: { | 174 | case PageType::Memory: |
| 134 | if (auto result = ReadSpecial<T>(vaddr)) | 175 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 135 | return *result; | 176 | break; |
| 136 | [[fallthrough]]; | 177 | case PageType::RasterizerCachedMemory: { |
| 137 | } | 178 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| 138 | case PageType::Memory: { | ||
| 139 | const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | ||
| 140 | ASSERT_MSG(page_pointer, "Mapped memory page without a pointer @ %016" PRIX64, vaddr); | ||
| 141 | 179 | ||
| 142 | T value; | 180 | T value; |
| 143 | std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); | 181 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); |
| 144 | return value; | 182 | return value; |
| 145 | } | 183 | } |
| 184 | default: | ||
| 185 | UNREACHABLE(); | ||
| 146 | } | 186 | } |
| 147 | UNREACHABLE(); | ||
| 148 | return 0; | ||
| 149 | } | 187 | } |
| 150 | 188 | ||
| 151 | template <typename T> | 189 | template <typename T> |
| 152 | bool WriteSpecial(VAddr addr, const T data); | ||
| 153 | |||
| 154 | template <typename T> | ||
| 155 | void Write(const VAddr vaddr, const T data) { | 190 | void Write(const VAddr vaddr, const T data) { |
| 156 | if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { | 191 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
| 157 | LOG_ERROR(HW_Memory, "Write%lu after page table 0x%08X @ 0x%016" PRIX64, sizeof(data) * 8, | 192 | if (page_pointer) { |
| 158 | (u32)data, vaddr); | 193 | // NOTE: Avoid adding any extra logic to this fast-path block |
| 194 | std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); | ||
| 159 | return; | 195 | return; |
| 160 | } | 196 | } |
| 161 | 197 | ||
| 162 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 198 | // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state |
| 199 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 200 | |||
| 201 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 163 | switch (type) { | 202 | switch (type) { |
| 164 | case PageType::Unmapped: | 203 | case PageType::Unmapped: |
| 165 | LOG_ERROR(HW_Memory, "unmapped Write%zu 0x%08X @ 0x%016" PRIX64, sizeof(data) * 8, | 204 | LOG_ERROR(HW_Memory, "unmapped Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, |
| 166 | static_cast<u32>(data), vaddr); | 205 | vaddr); |
| 167 | return; | ||
| 168 | case PageType::Special: { | ||
| 169 | if (WriteSpecial<T>(vaddr, data)) | ||
| 170 | return; | ||
| 171 | [[fallthrough]]; | ||
| 172 | } | ||
| 173 | case PageType::Memory: { | ||
| 174 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | ||
| 175 | ASSERT_MSG(page_pointer, "Mapped memory page without a pointer @ %016" PRIX64, vaddr); | ||
| 176 | std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); | ||
| 177 | return; | 206 | return; |
| 207 | case PageType::Memory: | ||
| 208 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | ||
| 209 | break; | ||
| 210 | case PageType::RasterizerCachedMemory: { | ||
| 211 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate); | ||
| 212 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); | ||
| 213 | break; | ||
| 178 | } | 214 | } |
| 215 | default: | ||
| 216 | UNREACHABLE(); | ||
| 179 | } | 217 | } |
| 180 | UNREACHABLE(); | ||
| 181 | } | 218 | } |
| 182 | 219 | ||
| 183 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | 220 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { |
| 184 | auto& page_table = process.vm_manager.page_table; | 221 | auto& page_table = process.vm_manager.page_table; |
| 185 | 222 | ||
| 186 | if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) | 223 | const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; |
| 187 | return false; | 224 | if (page_pointer) |
| 225 | return true; | ||
| 188 | 226 | ||
| 189 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 227 | if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) |
| 190 | switch (type) { | ||
| 191 | case PageType::Unmapped: | ||
| 192 | return false; | ||
| 193 | case PageType::Memory: | ||
| 194 | return true; | 228 | return true; |
| 195 | case PageType::Special: { | 229 | |
| 196 | for (auto handler : GetSpecialHandlers(page_table, vaddr, 1)) | 230 | if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special) |
| 197 | if (auto result = handler->IsValidAddress(vaddr)) | 231 | return false; |
| 198 | return *result; | 232 | |
| 199 | return current_page_table->pointers[vaddr >> PAGE_BITS] != nullptr; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | UNREACHABLE(); | ||
| 203 | return false; | 233 | return false; |
| 204 | } | 234 | } |
| 205 | 235 | ||
| @@ -217,7 +247,11 @@ u8* GetPointer(const VAddr vaddr) { | |||
| 217 | return page_pointer + (vaddr & PAGE_MASK); | 247 | return page_pointer + (vaddr & PAGE_MASK); |
| 218 | } | 248 | } |
| 219 | 249 | ||
| 220 | LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%016" PRIx64, vaddr); | 250 | if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) { |
| 251 | return GetPointerFromVMA(vaddr); | ||
| 252 | } | ||
| 253 | |||
| 254 | LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); | ||
| 221 | return nullptr; | 255 | return nullptr; |
| 222 | } | 256 | } |
| 223 | 257 | ||
| @@ -291,6 +325,58 @@ u8* GetPhysicalPointer(PAddr address) { | |||
| 291 | return target_pointer; | 325 | return target_pointer; |
| 292 | } | 326 | } |
| 293 | 327 | ||
| 328 | void RasterizerMarkRegionCached(VAddr start, u64 size, bool cached) { | ||
| 329 | if (start == 0) { | ||
| 330 | return; | ||
| 331 | } | ||
| 332 | |||
| 333 | u64 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; | ||
| 334 | VAddr vaddr = start; | ||
| 335 | |||
| 336 | for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { | ||
| 337 | PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 338 | |||
| 339 | if (cached) { | ||
| 340 | // Switch page type to cached if now cached | ||
| 341 | switch (page_type) { | ||
| 342 | case PageType::Unmapped: | ||
| 343 | // It is not necessary for a process to have this region mapped into its address | ||
| 344 | // space, for example, a system module need not have a VRAM mapping. | ||
| 345 | break; | ||
| 346 | case PageType::Memory: | ||
| 347 | page_type = PageType::RasterizerCachedMemory; | ||
| 348 | current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; | ||
| 349 | break; | ||
| 350 | default: | ||
| 351 | UNREACHABLE(); | ||
| 352 | } | ||
| 353 | } else { | ||
| 354 | // Switch page type to uncached if now uncached | ||
| 355 | switch (page_type) { | ||
| 356 | case PageType::Unmapped: | ||
| 357 | // It is not necessary for a process to have this region mapped into its address | ||
| 358 | // space, for example, a system module need not have a VRAM mapping. | ||
| 359 | break; | ||
| 360 | case PageType::RasterizerCachedMemory: { | ||
| 361 | u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); | ||
| 362 | if (pointer == nullptr) { | ||
| 363 | // It's possible that this function has been called while updating the pagetable | ||
| 364 | // after unmapping a VMA. In that case the underlying VMA will no longer exist, | ||
| 365 | // and we should just leave the pagetable entry blank. | ||
| 366 | page_type = PageType::Unmapped; | ||
| 367 | } else { | ||
| 368 | page_type = PageType::Memory; | ||
| 369 | current_page_table->pointers[vaddr >> PAGE_BITS] = pointer; | ||
| 370 | } | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | default: | ||
| 374 | UNREACHABLE(); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 294 | void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | 380 | void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { |
| 295 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | 381 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be |
| 296 | // null here | 382 | // null here |
| @@ -344,17 +430,6 @@ u64 Read64(const VAddr addr) { | |||
| 344 | return Read<u64_le>(addr); | 430 | return Read<u64_le>(addr); |
| 345 | } | 431 | } |
| 346 | 432 | ||
| 347 | static bool ReadSpecialBlock(const Kernel::Process& process, const VAddr src_addr, | ||
| 348 | void* dest_buffer, const size_t size) { | ||
| 349 | auto& page_table = process.vm_manager.page_table; | ||
| 350 | for (const auto& handler : GetSpecialHandlers(page_table, src_addr, size)) { | ||
| 351 | if (handler->ReadBlock(src_addr, dest_buffer, size)) { | ||
| 352 | return true; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | return false; | ||
| 356 | } | ||
| 357 | |||
| 358 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | 433 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, |
| 359 | const size_t size) { | 434 | const size_t size) { |
| 360 | auto& page_table = process.vm_manager.page_table; | 435 | auto& page_table = process.vm_manager.page_table; |
| @@ -364,21 +439,16 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 364 | size_t page_offset = src_addr & PAGE_MASK; | 439 | size_t page_offset = src_addr & PAGE_MASK; |
| 365 | 440 | ||
| 366 | while (remaining_size > 0) { | 441 | while (remaining_size > 0) { |
| 367 | const size_t copy_amount = std::min<size_t>(PAGE_SIZE - page_offset, remaining_size); | 442 | const size_t copy_amount = |
| 443 | std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 368 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 444 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 369 | 445 | ||
| 370 | switch (page_table.attributes[page_index]) { | 446 | switch (page_table.attributes[page_index]) { |
| 371 | case PageType::Unmapped: | 447 | case PageType::Unmapped: { |
| 372 | LOG_ERROR(HW_Memory, | 448 | LOG_ERROR(HW_Memory, "unmapped ReadBlock @ 0x%08X (start address = 0x%08X, size = %zu)", |
| 373 | "unmapped ReadBlock @ 0x%016" PRIX64 " (start address = 0x%" PRIx64 | ||
| 374 | ", size = %zu)", | ||
| 375 | current_vaddr, src_addr, size); | 449 | current_vaddr, src_addr, size); |
| 376 | std::memset(dest_buffer, 0, copy_amount); | 450 | std::memset(dest_buffer, 0, copy_amount); |
| 377 | break; | 451 | break; |
| 378 | case PageType::Special: { | ||
| 379 | if (ReadSpecialBlock(process, current_vaddr, dest_buffer, copy_amount)) | ||
| 380 | break; | ||
| 381 | [[fallthrough]]; | ||
| 382 | } | 452 | } |
| 383 | case PageType::Memory: { | 453 | case PageType::Memory: { |
| 384 | DEBUG_ASSERT(page_table.pointers[page_index]); | 454 | DEBUG_ASSERT(page_table.pointers[page_index]); |
| @@ -387,6 +457,12 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 387 | std::memcpy(dest_buffer, src_ptr, copy_amount); | 457 | std::memcpy(dest_buffer, src_ptr, copy_amount); |
| 388 | break; | 458 | break; |
| 389 | } | 459 | } |
| 460 | case PageType::RasterizerCachedMemory: { | ||
| 461 | RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||
| 462 | FlushMode::Flush); | ||
| 463 | std::memcpy(dest_buffer, GetPointerFromVMA(process, current_vaddr), copy_amount); | ||
| 464 | break; | ||
| 465 | } | ||
| 390 | default: | 466 | default: |
| 391 | UNREACHABLE(); | 467 | UNREACHABLE(); |
| 392 | } | 468 | } |
| @@ -418,17 +494,6 @@ void Write64(const VAddr addr, const u64 data) { | |||
| 418 | Write<u64_le>(addr, data); | 494 | Write<u64_le>(addr, data); |
| 419 | } | 495 | } |
| 420 | 496 | ||
| 421 | static bool WriteSpecialBlock(const Kernel::Process& process, const VAddr dest_addr, | ||
| 422 | const void* src_buffer, const size_t size) { | ||
| 423 | auto& page_table = process.vm_manager.page_table; | ||
| 424 | for (const auto& handler : GetSpecialHandlers(page_table, dest_addr, size)) { | ||
| 425 | if (handler->WriteBlock(dest_addr, src_buffer, size)) { | ||
| 426 | return true; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | return false; | ||
| 430 | } | ||
| 431 | |||
| 432 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 497 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, |
| 433 | const size_t size) { | 498 | const size_t size) { |
| 434 | auto& page_table = process.vm_manager.page_table; | 499 | auto& page_table = process.vm_manager.page_table; |
| @@ -437,20 +502,17 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 437 | size_t page_offset = dest_addr & PAGE_MASK; | 502 | size_t page_offset = dest_addr & PAGE_MASK; |
| 438 | 503 | ||
| 439 | while (remaining_size > 0) { | 504 | while (remaining_size > 0) { |
| 440 | const size_t copy_amount = std::min<size_t>(PAGE_SIZE - page_offset, remaining_size); | 505 | const size_t copy_amount = |
| 506 | std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 441 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 507 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 442 | 508 | ||
| 443 | switch (page_table.attributes[page_index]) { | 509 | switch (page_table.attributes[page_index]) { |
| 444 | case PageType::Unmapped: | 510 | case PageType::Unmapped: { |
| 445 | LOG_ERROR(HW_Memory, | 511 | LOG_ERROR(HW_Memory, |
| 446 | "unmapped WriteBlock @ 0x%016" PRIX64 " (start address = 0x%016" PRIX64 | 512 | "unmapped WriteBlock @ 0x%08X (start address = 0x%08X, size = %zu)", |
| 447 | ", size = %zu)", | ||
| 448 | current_vaddr, dest_addr, size); | 513 | current_vaddr, dest_addr, size); |
| 449 | break; | 514 | break; |
| 450 | case PageType::Special: | 515 | } |
| 451 | if (WriteSpecialBlock(process, current_vaddr, src_buffer, copy_amount)) | ||
| 452 | break; | ||
| 453 | [[fallthrough]]; | ||
| 454 | case PageType::Memory: { | 516 | case PageType::Memory: { |
| 455 | DEBUG_ASSERT(page_table.pointers[page_index]); | 517 | DEBUG_ASSERT(page_table.pointers[page_index]); |
| 456 | 518 | ||
| @@ -458,6 +520,12 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 458 | std::memcpy(dest_ptr, src_buffer, copy_amount); | 520 | std::memcpy(dest_ptr, src_buffer, copy_amount); |
| 459 | break; | 521 | break; |
| 460 | } | 522 | } |
| 523 | case PageType::RasterizerCachedMemory: { | ||
| 524 | RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||
| 525 | FlushMode::Invalidate); | ||
| 526 | std::memcpy(GetPointerFromVMA(process, current_vaddr), src_buffer, copy_amount); | ||
| 527 | break; | ||
| 528 | } | ||
| 461 | default: | 529 | default: |
| 462 | UNREACHABLE(); | 530 | UNREACHABLE(); |
| 463 | } | 531 | } |
| @@ -473,9 +541,8 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size | |||
| 473 | WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); | 541 | WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); |
| 474 | } | 542 | } |
| 475 | 543 | ||
| 476 | void ZeroBlock(const VAddr dest_addr, const size_t size) { | 544 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size_t size) { |
| 477 | const auto& process = *Core::CurrentProcess(); | 545 | auto& page_table = process.vm_manager.page_table; |
| 478 | |||
| 479 | size_t remaining_size = size; | 546 | size_t remaining_size = size; |
| 480 | size_t page_index = dest_addr >> PAGE_BITS; | 547 | size_t page_index = dest_addr >> PAGE_BITS; |
| 481 | size_t page_offset = dest_addr & PAGE_MASK; | 548 | size_t page_offset = dest_addr & PAGE_MASK; |
| @@ -483,27 +550,29 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { | |||
| 483 | static const std::array<u8, PAGE_SIZE> zeros = {}; | 550 | static const std::array<u8, PAGE_SIZE> zeros = {}; |
| 484 | 551 | ||
| 485 | while (remaining_size > 0) { | 552 | while (remaining_size > 0) { |
| 486 | const size_t copy_amount = std::min<size_t>(PAGE_SIZE - page_offset, remaining_size); | 553 | const size_t copy_amount = |
| 554 | std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 487 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 555 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 488 | 556 | ||
| 489 | switch (current_page_table->attributes[page_index]) { | 557 | switch (page_table.attributes[page_index]) { |
| 490 | case PageType::Unmapped: | 558 | case PageType::Unmapped: { |
| 491 | LOG_ERROR(HW_Memory, | 559 | LOG_ERROR(HW_Memory, "unmapped ZeroBlock @ 0x%08X (start address = 0x%08X, size = %zu)", |
| 492 | "unmapped ZeroBlock @ 0x%016" PRIX64 " (start address = 0x%016" PRIX64 | ||
| 493 | ", size = %zu)", | ||
| 494 | current_vaddr, dest_addr, size); | 560 | current_vaddr, dest_addr, size); |
| 495 | break; | 561 | break; |
| 496 | case PageType::Special: | 562 | } |
| 497 | if (WriteSpecialBlock(process, current_vaddr, zeros.data(), copy_amount)) | ||
| 498 | break; | ||
| 499 | [[fallthrough]]; | ||
| 500 | case PageType::Memory: { | 563 | case PageType::Memory: { |
| 501 | DEBUG_ASSERT(current_page_table->pointers[page_index]); | 564 | DEBUG_ASSERT(page_table.pointers[page_index]); |
| 502 | 565 | ||
| 503 | u8* dest_ptr = current_page_table->pointers[page_index] + page_offset; | 566 | u8* dest_ptr = page_table.pointers[page_index] + page_offset; |
| 504 | std::memset(dest_ptr, 0, copy_amount); | 567 | std::memset(dest_ptr, 0, copy_amount); |
| 505 | break; | 568 | break; |
| 506 | } | 569 | } |
| 570 | case PageType::RasterizerCachedMemory: { | ||
| 571 | RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||
| 572 | FlushMode::Invalidate); | ||
| 573 | std::memset(GetPointerFromVMA(process, current_vaddr), 0, copy_amount); | ||
| 574 | break; | ||
| 575 | } | ||
| 507 | default: | 576 | default: |
| 508 | UNREACHABLE(); | 577 | UNREACHABLE(); |
| 509 | } | 578 | } |
| @@ -514,37 +583,34 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { | |||
| 514 | } | 583 | } |
| 515 | } | 584 | } |
| 516 | 585 | ||
| 517 | void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | 586 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, const size_t size) { |
| 518 | const auto& process = *Core::CurrentProcess(); | 587 | auto& page_table = process.vm_manager.page_table; |
| 519 | |||
| 520 | size_t remaining_size = size; | 588 | size_t remaining_size = size; |
| 521 | size_t page_index = src_addr >> PAGE_BITS; | 589 | size_t page_index = src_addr >> PAGE_BITS; |
| 522 | size_t page_offset = src_addr & PAGE_MASK; | 590 | size_t page_offset = src_addr & PAGE_MASK; |
| 523 | 591 | ||
| 524 | while (remaining_size > 0) { | 592 | while (remaining_size > 0) { |
| 525 | const size_t copy_amount = std::min<size_t>(PAGE_SIZE - page_offset, remaining_size); | 593 | const size_t copy_amount = |
| 594 | std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); | ||
| 526 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 595 | const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 527 | 596 | ||
| 528 | switch (current_page_table->attributes[page_index]) { | 597 | switch (page_table.attributes[page_index]) { |
| 529 | case PageType::Unmapped: | 598 | case PageType::Unmapped: { |
| 530 | LOG_ERROR(HW_Memory, | 599 | LOG_ERROR(HW_Memory, "unmapped CopyBlock @ 0x%08X (start address = 0x%08X, size = %zu)", |
| 531 | "unmapped CopyBlock @ 0x%016" PRIX64 " (start address = 0x%016" PRIX64 | ||
| 532 | ", size = %zu)", | ||
| 533 | current_vaddr, src_addr, size); | 600 | current_vaddr, src_addr, size); |
| 534 | ZeroBlock(dest_addr, copy_amount); | 601 | ZeroBlock(process, dest_addr, copy_amount); |
| 535 | break; | 602 | break; |
| 536 | case PageType::Special: { | ||
| 537 | std::vector<u8> buffer(copy_amount); | ||
| 538 | if (ReadSpecialBlock(process, current_vaddr, buffer.data(), buffer.size())) { | ||
| 539 | WriteBlock(dest_addr, buffer.data(), buffer.size()); | ||
| 540 | break; | ||
| 541 | } | ||
| 542 | [[fallthrough]]; | ||
| 543 | } | 603 | } |
| 544 | case PageType::Memory: { | 604 | case PageType::Memory: { |
| 545 | DEBUG_ASSERT(current_page_table->pointers[page_index]); | 605 | DEBUG_ASSERT(page_table.pointers[page_index]); |
| 546 | const u8* src_ptr = current_page_table->pointers[page_index] + page_offset; | 606 | const u8* src_ptr = page_table.pointers[page_index] + page_offset; |
| 547 | WriteBlock(dest_addr, src_ptr, copy_amount); | 607 | WriteBlock(process, dest_addr, src_ptr, copy_amount); |
| 608 | break; | ||
| 609 | } | ||
| 610 | case PageType::RasterizerCachedMemory: { | ||
| 611 | RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||
| 612 | FlushMode::Flush); | ||
| 613 | WriteBlock(process, dest_addr, GetPointerFromVMA(process, current_vaddr), copy_amount); | ||
| 548 | break; | 614 | break; |
| 549 | } | 615 | } |
| 550 | default: | 616 | default: |
| @@ -559,78 +625,6 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | |||
| 559 | } | 625 | } |
| 560 | } | 626 | } |
| 561 | 627 | ||
| 562 | template <> | ||
| 563 | boost::optional<u8> ReadSpecial<u8>(VAddr addr) { | ||
| 564 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 565 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) | ||
| 566 | if (auto result = handler->Read8(addr)) | ||
| 567 | return *result; | ||
| 568 | return {}; | ||
| 569 | } | ||
| 570 | |||
| 571 | template <> | ||
| 572 | boost::optional<u16> ReadSpecial<u16>(VAddr addr) { | ||
| 573 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 574 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) | ||
| 575 | if (auto result = handler->Read16(addr)) | ||
| 576 | return *result; | ||
| 577 | return {}; | ||
| 578 | } | ||
| 579 | |||
| 580 | template <> | ||
| 581 | boost::optional<u32> ReadSpecial<u32>(VAddr addr) { | ||
| 582 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 583 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) | ||
| 584 | if (auto result = handler->Read32(addr)) | ||
| 585 | return *result; | ||
| 586 | return {}; | ||
| 587 | } | ||
| 588 | |||
| 589 | template <> | ||
| 590 | boost::optional<u64> ReadSpecial<u64>(VAddr addr) { | ||
| 591 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 592 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) | ||
| 593 | if (auto result = handler->Read64(addr)) | ||
| 594 | return *result; | ||
| 595 | return {}; | ||
| 596 | } | ||
| 597 | |||
| 598 | template <> | ||
| 599 | bool WriteSpecial<u8>(VAddr addr, const u8 data) { | ||
| 600 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 601 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) | ||
| 602 | if (handler->Write8(addr, data)) | ||
| 603 | return true; | ||
| 604 | return false; | ||
| 605 | } | ||
| 606 | |||
| 607 | template <> | ||
| 608 | bool WriteSpecial<u16>(VAddr addr, const u16 data) { | ||
| 609 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 610 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) | ||
| 611 | if (handler->Write16(addr, data)) | ||
| 612 | return true; | ||
| 613 | return false; | ||
| 614 | } | ||
| 615 | |||
| 616 | template <> | ||
| 617 | bool WriteSpecial<u32>(VAddr addr, const u32 data) { | ||
| 618 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 619 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) | ||
| 620 | if (handler->Write32(addr, data)) | ||
| 621 | return true; | ||
| 622 | return false; | ||
| 623 | } | ||
| 624 | |||
| 625 | template <> | ||
| 626 | bool WriteSpecial<u64>(VAddr addr, const u64 data) { | ||
| 627 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; | ||
| 628 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) | ||
| 629 | if (handler->Write64(addr, data)) | ||
| 630 | return true; | ||
| 631 | return false; | ||
| 632 | } | ||
| 633 | |||
| 634 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { | 628 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { |
| 635 | if (addr == 0) { | 629 | if (addr == 0) { |
| 636 | return 0; | 630 | return 0; |
diff --git a/src/core/memory.h b/src/core/memory.h index 4b9c482fe..413a7b4e8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -255,6 +255,11 @@ enum class FlushMode { | |||
| 255 | }; | 255 | }; |
| 256 | 256 | ||
| 257 | /** | 257 | /** |
| 258 | * Mark each page touching the region as cached. | ||
| 259 | */ | ||
| 260 | void RasterizerMarkRegionCached(VAddr start, u64 size, bool cached); | ||
| 261 | |||
| 262 | /** | ||
| 258 | * Flushes and invalidates any externally cached rasterizer resources touching the given virtual | 263 | * Flushes and invalidates any externally cached rasterizer resources touching the given virtual |
| 259 | * address region. | 264 | * address region. |
| 260 | */ | 265 | */ |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3dab81769..841f27d7f 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -31,6 +31,7 @@ add_library(video_core STATIC | |||
| 31 | renderer_opengl/gl_state.h | 31 | renderer_opengl/gl_state.h |
| 32 | renderer_opengl/gl_stream_buffer.cpp | 32 | renderer_opengl/gl_stream_buffer.cpp |
| 33 | renderer_opengl/gl_stream_buffer.h | 33 | renderer_opengl/gl_stream_buffer.h |
| 34 | renderer_opengl/maxwell_to_gl.h | ||
| 34 | renderer_opengl/renderer_opengl.cpp | 35 | renderer_opengl/renderer_opengl.cpp |
| 35 | renderer_opengl/renderer_opengl.h | 36 | renderer_opengl/renderer_opengl.h |
| 36 | textures/decoders.cpp | 37 | textures/decoders.cpp |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 088d4357e..5359d21a2 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -7,8 +7,11 @@ | |||
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "video_core/debug_utils/debug_utils.h" | 8 | #include "video_core/debug_utils/debug_utils.h" |
| 9 | #include "video_core/engines/maxwell_3d.h" | 9 | #include "video_core/engines/maxwell_3d.h" |
| 10 | #include "video_core/rasterizer_interface.h" | ||
| 11 | #include "video_core/renderer_base.h" | ||
| 10 | #include "video_core/textures/decoders.h" | 12 | #include "video_core/textures/decoders.h" |
| 11 | #include "video_core/textures/texture.h" | 13 | #include "video_core/textures/texture.h" |
| 14 | #include "video_core/video_core.h" | ||
| 12 | 15 | ||
| 13 | namespace Tegra { | 16 | namespace Tegra { |
| 14 | namespace Engines { | 17 | namespace Engines { |
| @@ -174,7 +177,9 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 174 | } | 177 | } |
| 175 | 178 | ||
| 176 | void Maxwell3D::DrawArrays() { | 179 | void Maxwell3D::DrawArrays() { |
| 177 | LOG_WARNING(HW_GPU, "Game requested a DrawArrays, ignoring"); | 180 | LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(), |
| 181 | regs.vertex_buffer.count); | ||
| 182 | |||
| 178 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); | 183 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); |
| 179 | 184 | ||
| 180 | if (debug_context) { | 185 | if (debug_context) { |
| @@ -184,6 +189,8 @@ void Maxwell3D::DrawArrays() { | |||
| 184 | if (debug_context) { | 189 | if (debug_context) { |
| 185 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); | 190 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); |
| 186 | } | 191 | } |
| 192 | |||
| 193 | VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/); | ||
| 187 | } | 194 | } |
| 188 | 195 | ||
| 189 | void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) { | 196 | void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) { |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 8e2d888e7..3066bc606 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include "common/bit_field.h" | 11 | #include "common/bit_field.h" |
| 12 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/math_util.h" | ||
| 15 | #include "video_core/gpu.h" | ||
| 14 | #include "video_core/memory_manager.h" | 16 | #include "video_core/memory_manager.h" |
| 15 | #include "video_core/textures/texture.h" | 17 | #include "video_core/textures/texture.h" |
| 16 | 18 | ||
| @@ -59,88 +61,173 @@ public: | |||
| 59 | Fragment = 4, | 61 | Fragment = 4, |
| 60 | }; | 62 | }; |
| 61 | 63 | ||
| 62 | enum class VertexSize : u32 { | 64 | struct VertexAttribute { |
| 63 | Size_32_32_32_32 = 0x01, | 65 | enum class Size : u32 { |
| 64 | Size_32_32_32 = 0x02, | 66 | Size_32_32_32_32 = 0x01, |
| 65 | Size_16_16_16_16 = 0x03, | 67 | Size_32_32_32 = 0x02, |
| 66 | Size_32_32 = 0x04, | 68 | Size_16_16_16_16 = 0x03, |
| 67 | Size_16_16_16 = 0x05, | 69 | Size_32_32 = 0x04, |
| 68 | Size_8_8_8_8 = 0x0a, | 70 | Size_16_16_16 = 0x05, |
| 69 | Size_16_16 = 0x0f, | 71 | Size_8_8_8_8 = 0x0a, |
| 70 | Size_32 = 0x12, | 72 | Size_16_16 = 0x0f, |
| 71 | Size_8_8_8 = 0x13, | 73 | Size_32 = 0x12, |
| 72 | Size_8_8 = 0x18, | 74 | Size_8_8_8 = 0x13, |
| 73 | Size_16 = 0x1b, | 75 | Size_8_8 = 0x18, |
| 74 | Size_8 = 0x1d, | 76 | Size_16 = 0x1b, |
| 75 | Size_10_10_10_2 = 0x30, | 77 | Size_8 = 0x1d, |
| 76 | Size_11_11_10 = 0x31, | 78 | Size_10_10_10_2 = 0x30, |
| 77 | }; | 79 | Size_11_11_10 = 0x31, |
| 80 | }; | ||
| 78 | 81 | ||
| 79 | static std::string VertexSizeToString(VertexSize vertex_size) { | 82 | enum class Type : u32 { |
| 80 | switch (vertex_size) { | 83 | SignedNorm = 1, |
| 81 | case VertexSize::Size_32_32_32_32: | 84 | UnsignedNorm = 2, |
| 82 | return "32_32_32_32"; | 85 | SignedInt = 3, |
| 83 | case VertexSize::Size_32_32_32: | 86 | UnsignedInt = 4, |
| 84 | return "32_32_32"; | 87 | UnsignedScaled = 5, |
| 85 | case VertexSize::Size_16_16_16_16: | 88 | SignedScaled = 6, |
| 86 | return "16_16_16_16"; | 89 | Float = 7, |
| 87 | case VertexSize::Size_32_32: | 90 | }; |
| 88 | return "32_32"; | 91 | |
| 89 | case VertexSize::Size_16_16_16: | 92 | union { |
| 90 | return "16_16_16"; | 93 | BitField<0, 5, u32> buffer; |
| 91 | case VertexSize::Size_8_8_8_8: | 94 | BitField<6, 1, u32> constant; |
| 92 | return "8_8_8_8"; | 95 | BitField<7, 14, u32> offset; |
| 93 | case VertexSize::Size_16_16: | 96 | BitField<21, 6, Size> size; |
| 94 | return "16_16"; | 97 | BitField<27, 3, Type> type; |
| 95 | case VertexSize::Size_32: | 98 | BitField<31, 1, u32> bgra; |
| 96 | return "32"; | 99 | }; |
| 97 | case VertexSize::Size_8_8_8: | 100 | |
| 98 | return "8_8_8"; | 101 | u32 ComponentCount() const { |
| 99 | case VertexSize::Size_8_8: | 102 | switch (size) { |
| 100 | return "8_8"; | 103 | case Size::Size_32_32_32_32: |
| 101 | case VertexSize::Size_16: | 104 | return 4; |
| 102 | return "16"; | 105 | case Size::Size_32_32_32: |
| 103 | case VertexSize::Size_8: | 106 | return 3; |
| 104 | return "8"; | 107 | case Size::Size_16_16_16_16: |
| 105 | case VertexSize::Size_10_10_10_2: | 108 | return 4; |
| 106 | return "10_10_10_2"; | 109 | case Size::Size_32_32: |
| 107 | case VertexSize::Size_11_11_10: | 110 | return 2; |
| 108 | return "11_11_10"; | 111 | case Size::Size_16_16_16: |
| 112 | return 3; | ||
| 113 | case Size::Size_8_8_8_8: | ||
| 114 | return 4; | ||
| 115 | case Size::Size_16_16: | ||
| 116 | return 2; | ||
| 117 | case Size::Size_32: | ||
| 118 | return 1; | ||
| 119 | case Size::Size_8_8_8: | ||
| 120 | return 3; | ||
| 121 | case Size::Size_8_8: | ||
| 122 | return 2; | ||
| 123 | case Size::Size_16: | ||
| 124 | return 1; | ||
| 125 | case Size::Size_8: | ||
| 126 | return 1; | ||
| 127 | case Size::Size_10_10_10_2: | ||
| 128 | return 4; | ||
| 129 | case Size::Size_11_11_10: | ||
| 130 | return 3; | ||
| 131 | default: | ||
| 132 | UNREACHABLE(); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | u32 SizeInBytes() const { | ||
| 137 | switch (size) { | ||
| 138 | case Size::Size_32_32_32_32: | ||
| 139 | return 16; | ||
| 140 | case Size::Size_32_32_32: | ||
| 141 | return 12; | ||
| 142 | case Size::Size_16_16_16_16: | ||
| 143 | return 8; | ||
| 144 | case Size::Size_32_32: | ||
| 145 | return 8; | ||
| 146 | case Size::Size_16_16_16: | ||
| 147 | return 6; | ||
| 148 | case Size::Size_8_8_8_8: | ||
| 149 | return 4; | ||
| 150 | case Size::Size_16_16: | ||
| 151 | return 4; | ||
| 152 | case Size::Size_32: | ||
| 153 | return 4; | ||
| 154 | case Size::Size_8_8_8: | ||
| 155 | return 3; | ||
| 156 | case Size::Size_8_8: | ||
| 157 | return 2; | ||
| 158 | case Size::Size_16: | ||
| 159 | return 2; | ||
| 160 | case Size::Size_8: | ||
| 161 | return 1; | ||
| 162 | case Size::Size_10_10_10_2: | ||
| 163 | return 4; | ||
| 164 | case Size::Size_11_11_10: | ||
| 165 | return 4; | ||
| 166 | default: | ||
| 167 | UNREACHABLE(); | ||
| 168 | } | ||
| 109 | } | 169 | } |
| 110 | UNIMPLEMENTED(); | ||
| 111 | return {}; | ||
| 112 | } | ||
| 113 | |||
| 114 | enum class VertexType : u32 { | ||
| 115 | SignedNorm = 1, | ||
| 116 | UnsignedNorm = 2, | ||
| 117 | SignedInt = 3, | ||
| 118 | UnsignedInt = 4, | ||
| 119 | UnsignedScaled = 5, | ||
| 120 | SignedScaled = 6, | ||
| 121 | Float = 7, | ||
| 122 | }; | ||
| 123 | 170 | ||
| 124 | static std::string VertexTypeToString(VertexType vertex_type) { | 171 | std::string SizeString() const { |
| 125 | switch (vertex_type) { | 172 | switch (size) { |
| 126 | case VertexType::SignedNorm: | 173 | case Size::Size_32_32_32_32: |
| 127 | return "SignedNorm"; | 174 | return "32_32_32_32"; |
| 128 | case VertexType::UnsignedNorm: | 175 | case Size::Size_32_32_32: |
| 129 | return "UnsignedNorm"; | 176 | return "32_32_32"; |
| 130 | case VertexType::SignedInt: | 177 | case Size::Size_16_16_16_16: |
| 131 | return "SignedInt"; | 178 | return "16_16_16_16"; |
| 132 | case VertexType::UnsignedInt: | 179 | case Size::Size_32_32: |
| 133 | return "UnsignedInt"; | 180 | return "32_32"; |
| 134 | case VertexType::UnsignedScaled: | 181 | case Size::Size_16_16_16: |
| 135 | return "UnsignedScaled"; | 182 | return "16_16_16"; |
| 136 | case VertexType::SignedScaled: | 183 | case Size::Size_8_8_8_8: |
| 137 | return "SignedScaled"; | 184 | return "8_8_8_8"; |
| 138 | case VertexType::Float: | 185 | case Size::Size_16_16: |
| 139 | return "Float"; | 186 | return "16_16"; |
| 187 | case Size::Size_32: | ||
| 188 | return "32"; | ||
| 189 | case Size::Size_8_8_8: | ||
| 190 | return "8_8_8"; | ||
| 191 | case Size::Size_8_8: | ||
| 192 | return "8_8"; | ||
| 193 | case Size::Size_16: | ||
| 194 | return "16"; | ||
| 195 | case Size::Size_8: | ||
| 196 | return "8"; | ||
| 197 | case Size::Size_10_10_10_2: | ||
| 198 | return "10_10_10_2"; | ||
| 199 | case Size::Size_11_11_10: | ||
| 200 | return "11_11_10"; | ||
| 201 | } | ||
| 202 | UNREACHABLE(); | ||
| 203 | return {}; | ||
| 140 | } | 204 | } |
| 141 | UNIMPLEMENTED(); | 205 | |
| 142 | return {}; | 206 | std::string TypeString() const { |
| 143 | } | 207 | switch (type) { |
| 208 | case Type::SignedNorm: | ||
| 209 | return "SNORM"; | ||
| 210 | case Type::UnsignedNorm: | ||
| 211 | return "UNORM"; | ||
| 212 | case Type::SignedInt: | ||
| 213 | return "SINT"; | ||
| 214 | case Type::UnsignedInt: | ||
| 215 | return "UINT"; | ||
| 216 | case Type::UnsignedScaled: | ||
| 217 | return "USCALED"; | ||
| 218 | case Type::SignedScaled: | ||
| 219 | return "SSCALED"; | ||
| 220 | case Type::Float: | ||
| 221 | return "FLOAT"; | ||
| 222 | } | ||
| 223 | UNREACHABLE(); | ||
| 224 | return {}; | ||
| 225 | } | ||
| 226 | |||
| 227 | bool IsNormalized() const { | ||
| 228 | return (type == Type::SignedNorm) || (type == Type::UnsignedNorm); | ||
| 229 | } | ||
| 230 | }; | ||
| 144 | 231 | ||
| 145 | enum class PrimitiveTopology : u32 { | 232 | enum class PrimitiveTopology : u32 { |
| 146 | Points = 0x0, | 233 | Points = 0x0, |
| @@ -167,9 +254,9 @@ public: | |||
| 167 | struct { | 254 | struct { |
| 168 | u32 address_high; | 255 | u32 address_high; |
| 169 | u32 address_low; | 256 | u32 address_low; |
| 170 | u32 horiz; | 257 | u32 width; |
| 171 | u32 vert; | 258 | u32 height; |
| 172 | u32 format; | 259 | Tegra::RenderTargetFormat format; |
| 173 | u32 block_dimensions; | 260 | u32 block_dimensions; |
| 174 | u32 array_mode; | 261 | u32 array_mode; |
| 175 | u32 layer_stride; | 262 | u32 layer_stride; |
| @@ -195,6 +282,15 @@ public: | |||
| 195 | }; | 282 | }; |
| 196 | float depth_range_near; | 283 | float depth_range_near; |
| 197 | float depth_range_far; | 284 | float depth_range_far; |
| 285 | |||
| 286 | MathUtil::Rectangle<s32> GetRect() const { | ||
| 287 | return { | ||
| 288 | static_cast<s32>(x), // left | ||
| 289 | static_cast<s32>(y + height), // top | ||
| 290 | static_cast<s32>(x + width), // right | ||
| 291 | static_cast<s32>(y) // bottom | ||
| 292 | }; | ||
| 293 | }; | ||
| 198 | } viewport[NumViewports]; | 294 | } viewport[NumViewports]; |
| 199 | 295 | ||
| 200 | INSERT_PADDING_WORDS(0x1D); | 296 | INSERT_PADDING_WORDS(0x1D); |
| @@ -221,14 +317,7 @@ public: | |||
| 221 | 317 | ||
| 222 | INSERT_PADDING_WORDS(0x5B); | 318 | INSERT_PADDING_WORDS(0x5B); |
| 223 | 319 | ||
| 224 | union { | 320 | VertexAttribute vertex_attrib_format[NumVertexAttributes]; |
| 225 | BitField<0, 5, u32> buffer; | ||
| 226 | BitField<6, 1, u32> constant; | ||
| 227 | BitField<7, 14, u32> offset; | ||
| 228 | BitField<21, 6, VertexSize> size; | ||
| 229 | BitField<27, 3, VertexType> type; | ||
| 230 | BitField<31, 1, u32> bgra; | ||
| 231 | } vertex_attrib_format[NumVertexAttributes]; | ||
| 232 | 321 | ||
| 233 | INSERT_PADDING_WORDS(0xF); | 322 | INSERT_PADDING_WORDS(0xF); |
| 234 | 323 | ||
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 8183b12e9..71a8661b4 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -13,7 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | namespace Tegra { | 14 | namespace Tegra { |
| 15 | 15 | ||
| 16 | enum class RenderTargetFormat { | 16 | enum class RenderTargetFormat : u32 { |
| 17 | NONE = 0x0, | ||
| 17 | RGBA8_UNORM = 0xD5, | 18 | RGBA8_UNORM = 0xD5, |
| 18 | }; | 19 | }; |
| 19 | 20 | ||
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index a493e1d60..8239f9aad 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -15,8 +15,8 @@ class RasterizerInterface { | |||
| 15 | public: | 15 | public: |
| 16 | virtual ~RasterizerInterface() {} | 16 | virtual ~RasterizerInterface() {} |
| 17 | 17 | ||
| 18 | /// Draw the current batch of triangles | 18 | /// Draw the current batch of vertex arrays |
| 19 | virtual void DrawTriangles() = 0; | 19 | virtual void DrawArrays() = 0; |
| 20 | 20 | ||
| 21 | /// Notify rasterizer that the specified Maxwell register has been changed | 21 | /// Notify rasterizer that the specified Maxwell register has been changed |
| 22 | virtual void NotifyMaxwellRegisterChanged(u32 id) = 0; | 22 | virtual void NotifyMaxwellRegisterChanged(u32 id) = 0; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 286491b73..911890f16 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -14,11 +14,16 @@ | |||
| 14 | #include "common/microprofile.h" | 14 | #include "common/microprofile.h" |
| 15 | #include "common/scope_exit.h" | 15 | #include "common/scope_exit.h" |
| 16 | #include "common/vector_math.h" | 16 | #include "common/vector_math.h" |
| 17 | #include "core/core.h" | ||
| 18 | #include "core/hle/kernel/process.h" | ||
| 17 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| 20 | #include "video_core/engines/maxwell_3d.h" | ||
| 18 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 21 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 19 | #include "video_core/renderer_opengl/gl_shader_gen.h" | 22 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 23 | #include "video_core/renderer_opengl/maxwell_to_gl.h" | ||
| 20 | #include "video_core/renderer_opengl/renderer_opengl.h" | 24 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 21 | 25 | ||
| 26 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 22 | using PixelFormat = SurfaceParams::PixelFormat; | 27 | using PixelFormat = SurfaceParams::PixelFormat; |
| 23 | using SurfaceType = SurfaceParams::SurfaceType; | 28 | using SurfaceType = SurfaceParams::SurfaceType; |
| 24 | 29 | ||
| @@ -120,14 +125,14 @@ RasterizerOpenGL::RasterizerOpenGL() { | |||
| 120 | glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY); | 125 | glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY); |
| 121 | glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle); | 126 | glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle); |
| 122 | } else { | 127 | } else { |
| 123 | ASSERT_MSG(false, "Unimplemented"); | 128 | UNREACHABLE(); |
| 124 | } | 129 | } |
| 125 | 130 | ||
| 126 | accelerate_draw = AccelDraw::Disabled; | 131 | accelerate_draw = AccelDraw::Disabled; |
| 127 | 132 | ||
| 128 | glEnable(GL_BLEND); | 133 | glEnable(GL_BLEND); |
| 129 | 134 | ||
| 130 | LOG_WARNING(HW_GPU, "Sync fixed function OpenGL state here when ready"); | 135 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); |
| 131 | } | 136 | } |
| 132 | 137 | ||
| 133 | RasterizerOpenGL::~RasterizerOpenGL() { | 138 | RasterizerOpenGL::~RasterizerOpenGL() { |
| @@ -138,47 +143,235 @@ RasterizerOpenGL::~RasterizerOpenGL() { | |||
| 138 | } | 143 | } |
| 139 | } | 144 | } |
| 140 | 145 | ||
| 141 | static constexpr std::array<GLenum, 4> vs_attrib_types{ | ||
| 142 | GL_BYTE, // VertexAttributeFormat::BYTE | ||
| 143 | GL_UNSIGNED_BYTE, // VertexAttributeFormat::UBYTE | ||
| 144 | GL_SHORT, // VertexAttributeFormat::SHORT | ||
| 145 | GL_FLOAT // VertexAttributeFormat::FLOAT | ||
| 146 | }; | ||
| 147 | |||
| 148 | void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { | 146 | void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { |
| 149 | UNIMPLEMENTED(); | 147 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 148 | |||
| 149 | if (is_indexed) { | ||
| 150 | UNREACHABLE(); | ||
| 151 | } | ||
| 152 | |||
| 153 | // TODO(bunnei): Add support for 1+ vertex arrays | ||
| 154 | vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride; | ||
| 150 | } | 155 | } |
| 151 | 156 | ||
| 152 | void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { | 157 | void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { |
| 153 | MICROPROFILE_SCOPE(OpenGL_VAO); | 158 | MICROPROFILE_SCOPE(OpenGL_VAO); |
| 154 | UNIMPLEMENTED(); | 159 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 160 | const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; | ||
| 161 | |||
| 162 | state.draw.vertex_array = hw_vao.handle; | ||
| 163 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 164 | state.Apply(); | ||
| 165 | |||
| 166 | // TODO(bunnei): Add support for 1+ vertex arrays | ||
| 167 | const auto& vertex_array{regs.vertex_array[0]}; | ||
| 168 | ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?"); | ||
| 169 | ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!"); | ||
| 170 | for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) { | ||
| 171 | ASSERT_MSG(!regs.vertex_array[index].enable, "vertex array %d is unimplemented!", index); | ||
| 172 | } | ||
| 173 | |||
| 174 | // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. | ||
| 175 | // Enables the first 16 vertex attributes always, as we don't know which ones are actually used | ||
| 176 | // until shader time. Note, Tegra technically supports 32, but we're cappinig this to 16 for now | ||
| 177 | // to avoid OpenGL errors. | ||
| 178 | for (unsigned index = 0; index < 16; ++index) { | ||
| 179 | auto& attrib = regs.vertex_attrib_format[index]; | ||
| 180 | glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), | ||
| 181 | attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride, | ||
| 182 | reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset)); | ||
| 183 | glEnableVertexAttribArray(index); | ||
| 184 | hw_vao_enabled_attributes[index] = true; | ||
| 185 | } | ||
| 186 | |||
| 187 | // Copy vertex array data | ||
| 188 | const u32 data_size{vertex_array.stride * regs.vertex_buffer.count}; | ||
| 189 | const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())}; | ||
| 190 | res_cache.FlushRegion(data_addr, data_size, nullptr); | ||
| 191 | Memory::ReadBlock(data_addr, array_ptr, data_size); | ||
| 192 | |||
| 193 | array_ptr += data_size; | ||
| 194 | buffer_offset += data_size; | ||
| 155 | } | 195 | } |
| 156 | 196 | ||
| 157 | void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) { | 197 | void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) { |
| 158 | MICROPROFILE_SCOPE(OpenGL_VS); | 198 | MICROPROFILE_SCOPE(OpenGL_VS); |
| 159 | UNIMPLEMENTED(); | 199 | LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader."); |
| 200 | glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_shader->shader.handle); | ||
| 160 | } | 201 | } |
| 161 | 202 | ||
| 162 | void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { | 203 | void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { |
| 163 | MICROPROFILE_SCOPE(OpenGL_FS); | 204 | MICROPROFILE_SCOPE(OpenGL_FS); |
| 164 | ASSERT_MSG(false, "Unimplemented"); | 205 | UNREACHABLE(); |
| 165 | } | 206 | } |
| 166 | 207 | ||
| 167 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | 208 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { |
| 168 | if (!has_ARB_separate_shader_objects) { | 209 | if (!has_ARB_separate_shader_objects) { |
| 169 | ASSERT_MSG(false, "Unimplemented"); | 210 | UNREACHABLE(); |
| 170 | return false; | 211 | return false; |
| 171 | } | 212 | } |
| 172 | 213 | ||
| 173 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; | 214 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; |
| 174 | DrawTriangles(); | 215 | DrawArrays(); |
| 175 | 216 | ||
| 176 | return true; | 217 | return true; |
| 177 | } | 218 | } |
| 178 | 219 | ||
| 179 | void RasterizerOpenGL::DrawTriangles() { | 220 | void RasterizerOpenGL::DrawArrays() { |
| 221 | if (accelerate_draw == AccelDraw::Disabled) | ||
| 222 | return; | ||
| 223 | |||
| 180 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 224 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 181 | UNIMPLEMENTED(); | 225 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 226 | |||
| 227 | // TODO(bunnei): Implement these | ||
| 228 | const bool has_stencil = false; | ||
| 229 | const bool using_color_fb = true; | ||
| 230 | const bool using_depth_fb = false; | ||
| 231 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()}; | ||
| 232 | |||
| 233 | const bool write_color_fb = | ||
| 234 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || | ||
| 235 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; | ||
| 236 | |||
| 237 | const bool write_depth_fb = | ||
| 238 | (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || | ||
| 239 | (has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0); | ||
| 240 | |||
| 241 | Surface color_surface; | ||
| 242 | Surface depth_surface; | ||
| 243 | MathUtil::Rectangle<u32> surfaces_rect; | ||
| 244 | std::tie(color_surface, depth_surface, surfaces_rect) = | ||
| 245 | res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect); | ||
| 246 | |||
| 247 | const u16 res_scale = color_surface != nullptr | ||
| 248 | ? color_surface->res_scale | ||
| 249 | : (depth_surface == nullptr ? 1u : depth_surface->res_scale); | ||
| 250 | |||
| 251 | MathUtil::Rectangle<u32> draw_rect{ | ||
| 252 | static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) + | ||
| 253 | viewport_rect.left * res_scale, | ||
| 254 | surfaces_rect.left, surfaces_rect.right)), // Left | ||
| 255 | static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + | ||
| 256 | viewport_rect.top * res_scale, | ||
| 257 | surfaces_rect.bottom, surfaces_rect.top)), // Top | ||
| 258 | static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) + | ||
| 259 | viewport_rect.right * res_scale, | ||
| 260 | surfaces_rect.left, surfaces_rect.right)), // Right | ||
| 261 | static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + | ||
| 262 | viewport_rect.bottom * res_scale, | ||
| 263 | surfaces_rect.bottom, surfaces_rect.top))}; // Bottom | ||
| 264 | |||
| 265 | // Bind the framebuffer surfaces | ||
| 266 | BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); | ||
| 267 | |||
| 268 | // Sync the viewport | ||
| 269 | SyncViewport(surfaces_rect, res_scale); | ||
| 270 | |||
| 271 | // TODO(bunnei): Sync framebuffer_scale uniform here | ||
| 272 | // TODO(bunnei): Sync scissorbox uniform(s) here | ||
| 273 | // TODO(bunnei): Sync and bind the texture surfaces | ||
| 274 | |||
| 275 | // Sync and bind the shader | ||
| 276 | if (shader_dirty) { | ||
| 277 | SetShader(); | ||
| 278 | shader_dirty = false; | ||
| 279 | } | ||
| 280 | |||
| 281 | // Sync the uniform data | ||
| 282 | if (uniform_block_data.dirty) { | ||
| 283 | glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformData), &uniform_block_data.data); | ||
| 284 | uniform_block_data.dirty = false; | ||
| 285 | } | ||
| 286 | |||
| 287 | // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable | ||
| 288 | // scissor test to prevent drawing outside of the framebuffer region | ||
| 289 | state.scissor.enabled = true; | ||
| 290 | state.scissor.x = draw_rect.left; | ||
| 291 | state.scissor.y = draw_rect.bottom; | ||
| 292 | state.scissor.width = draw_rect.GetWidth(); | ||
| 293 | state.scissor.height = draw_rect.GetHeight(); | ||
| 294 | state.Apply(); | ||
| 295 | |||
| 296 | // Draw the vertex batch | ||
| 297 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | ||
| 298 | AnalyzeVertexArray(is_indexed); | ||
| 299 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 300 | state.Apply(); | ||
| 301 | |||
| 302 | size_t buffer_size = static_cast<size_t>(vs_input_size); | ||
| 303 | if (is_indexed) { | ||
| 304 | UNREACHABLE(); | ||
| 305 | } | ||
| 306 | buffer_size += sizeof(VSUniformData); | ||
| 307 | |||
| 308 | size_t ptr_pos = 0; | ||
| 309 | u8* buffer_ptr; | ||
| 310 | GLintptr buffer_offset; | ||
| 311 | std::tie(buffer_ptr, buffer_offset) = | ||
| 312 | stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4); | ||
| 313 | |||
| 314 | SetupVertexArray(buffer_ptr, buffer_offset); | ||
| 315 | ptr_pos += vs_input_size; | ||
| 316 | |||
| 317 | GLintptr index_buffer_offset = 0; | ||
| 318 | if (is_indexed) { | ||
| 319 | UNREACHABLE(); | ||
| 320 | } | ||
| 321 | |||
| 322 | SetupVertexShader(reinterpret_cast<VSUniformData*>(&buffer_ptr[ptr_pos]), | ||
| 323 | buffer_offset + static_cast<GLintptr>(ptr_pos)); | ||
| 324 | const GLintptr vs_ubo_offset = buffer_offset + static_cast<GLintptr>(ptr_pos); | ||
| 325 | ptr_pos += sizeof(VSUniformData); | ||
| 326 | |||
| 327 | stream_buffer->Unmap(); | ||
| 328 | |||
| 329 | const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { | ||
| 330 | if (has_ARB_direct_state_access) { | ||
| 331 | glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size); | ||
| 332 | } else { | ||
| 333 | glBindBuffer(GL_COPY_WRITE_BUFFER, handle); | ||
| 334 | glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size); | ||
| 335 | } | ||
| 336 | }; | ||
| 337 | |||
| 338 | copy_buffer(vs_uniform_buffer.handle, vs_ubo_offset, sizeof(VSUniformData)); | ||
| 339 | |||
| 340 | glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current_shader->shader.handle); | ||
| 341 | |||
| 342 | if (is_indexed) { | ||
| 343 | UNREACHABLE(); | ||
| 344 | } else { | ||
| 345 | glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0, | ||
| 346 | regs.vertex_buffer.count); | ||
| 347 | } | ||
| 348 | |||
| 349 | // Disable scissor test | ||
| 350 | state.scissor.enabled = false; | ||
| 351 | |||
| 352 | accelerate_draw = AccelDraw::Disabled; | ||
| 353 | |||
| 354 | // Unbind textures for potential future use as framebuffer attachments | ||
| 355 | for (auto& texture_unit : state.texture_units) { | ||
| 356 | texture_unit.texture_2d = 0; | ||
| 357 | } | ||
| 358 | state.Apply(); | ||
| 359 | |||
| 360 | // Mark framebuffer surfaces as dirty | ||
| 361 | MathUtil::Rectangle<u32> draw_rect_unscaled{ | ||
| 362 | draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale, | ||
| 363 | draw_rect.bottom / res_scale}; | ||
| 364 | |||
| 365 | if (color_surface != nullptr && write_color_fb) { | ||
| 366 | auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled); | ||
| 367 | res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval), | ||
| 368 | color_surface); | ||
| 369 | } | ||
| 370 | if (depth_surface != nullptr && write_depth_fb) { | ||
| 371 | auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled); | ||
| 372 | res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval), | ||
| 373 | depth_surface); | ||
| 374 | } | ||
| 182 | } | 375 | } |
| 183 | 376 | ||
| 184 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} | 377 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} |
| @@ -206,17 +399,17 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { | |||
| 206 | 399 | ||
| 207 | bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { | 400 | bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { |
| 208 | MICROPROFILE_SCOPE(OpenGL_Blits); | 401 | MICROPROFILE_SCOPE(OpenGL_Blits); |
| 209 | ASSERT_MSG(false, "Unimplemented"); | 402 | UNREACHABLE(); |
| 210 | return true; | 403 | return true; |
| 211 | } | 404 | } |
| 212 | 405 | ||
| 213 | bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { | 406 | bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { |
| 214 | ASSERT_MSG(false, "Unimplemented"); | 407 | UNREACHABLE(); |
| 215 | return true; | 408 | return true; |
| 216 | } | 409 | } |
| 217 | 410 | ||
| 218 | bool RasterizerOpenGL::AccelerateFill(const void* config) { | 411 | bool RasterizerOpenGL::AccelerateFill(const void* config) { |
| 219 | ASSERT_MSG(false, "Unimplemented"); | 412 | UNREACHABLE(); |
| 220 | return true; | 413 | return true; |
| 221 | } | 414 | } |
| 222 | 415 | ||
| @@ -297,14 +490,14 @@ void main() { | |||
| 297 | return; | 490 | return; |
| 298 | } | 491 | } |
| 299 | 492 | ||
| 300 | LOG_ERROR(HW_GPU, "Emulated shaders are not supported! Using a passthrough shader."); | 493 | LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader."); |
| 301 | 494 | ||
| 302 | current_shader = &test_shader; | 495 | current_shader = &test_shader; |
| 303 | if (has_ARB_separate_shader_objects) { | 496 | if (has_ARB_separate_shader_objects) { |
| 304 | test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true); | 497 | test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true); |
| 305 | glActiveShaderProgram(pipeline.handle, test_shader.shader.handle); | 498 | glActiveShaderProgram(pipeline.handle, test_shader.shader.handle); |
| 306 | } else { | 499 | } else { |
| 307 | ASSERT_MSG(false, "Unimplemented"); | 500 | UNREACHABLE(); |
| 308 | } | 501 | } |
| 309 | 502 | ||
| 310 | state.draw.shader_program = test_shader.shader.handle; | 503 | state.draw.shader_program = test_shader.shader.handle; |
| @@ -316,34 +509,70 @@ void main() { | |||
| 316 | } | 509 | } |
| 317 | } | 510 | } |
| 318 | 511 | ||
| 512 | void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | ||
| 513 | const Surface& depth_surface, bool has_stencil) { | ||
| 514 | state.draw.draw_framebuffer = framebuffer.handle; | ||
| 515 | state.Apply(); | ||
| 516 | |||
| 517 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||
| 518 | color_surface != nullptr ? color_surface->texture.handle : 0, 0); | ||
| 519 | if (depth_surface != nullptr) { | ||
| 520 | if (has_stencil) { | ||
| 521 | // attach both depth and stencil | ||
| 522 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 523 | depth_surface->texture.handle, 0); | ||
| 524 | } else { | ||
| 525 | // attach depth | ||
| 526 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||
| 527 | depth_surface->texture.handle, 0); | ||
| 528 | // clear stencil attachment | ||
| 529 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | ||
| 530 | } | ||
| 531 | } else { | ||
| 532 | // clear both depth and stencil attachment | ||
| 533 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | ||
| 534 | 0); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) { | ||
| 539 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | ||
| 540 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()}; | ||
| 541 | |||
| 542 | state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale; | ||
| 543 | state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale; | ||
| 544 | state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth() * res_scale); | ||
| 545 | state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight() * res_scale); | ||
| 546 | } | ||
| 547 | |||
| 319 | void RasterizerOpenGL::SyncClipEnabled() { | 548 | void RasterizerOpenGL::SyncClipEnabled() { |
| 320 | ASSERT_MSG(false, "Unimplemented"); | 549 | UNREACHABLE(); |
| 321 | } | 550 | } |
| 322 | 551 | ||
| 323 | void RasterizerOpenGL::SyncClipCoef() { | 552 | void RasterizerOpenGL::SyncClipCoef() { |
| 324 | ASSERT_MSG(false, "Unimplemented"); | 553 | UNREACHABLE(); |
| 325 | } | 554 | } |
| 326 | 555 | ||
| 327 | void RasterizerOpenGL::SyncCullMode() { | 556 | void RasterizerOpenGL::SyncCullMode() { |
| 328 | ASSERT_MSG(false, "Unimplemented"); | 557 | UNREACHABLE(); |
| 329 | } | 558 | } |
| 330 | 559 | ||
| 331 | void RasterizerOpenGL::SyncDepthScale() { | 560 | void RasterizerOpenGL::SyncDepthScale() { |
| 332 | ASSERT_MSG(false, "Unimplemented"); | 561 | UNREACHABLE(); |
| 333 | } | 562 | } |
| 334 | 563 | ||
| 335 | void RasterizerOpenGL::SyncDepthOffset() { | 564 | void RasterizerOpenGL::SyncDepthOffset() { |
| 336 | ASSERT_MSG(false, "Unimplemented"); | 565 | UNREACHABLE(); |
| 337 | } | 566 | } |
| 338 | 567 | ||
| 339 | void RasterizerOpenGL::SyncBlendEnabled() { | 568 | void RasterizerOpenGL::SyncBlendEnabled() { |
| 340 | ASSERT_MSG(false, "Unimplemented"); | 569 | UNREACHABLE(); |
| 341 | } | 570 | } |
| 342 | 571 | ||
| 343 | void RasterizerOpenGL::SyncBlendFuncs() { | 572 | void RasterizerOpenGL::SyncBlendFuncs() { |
| 344 | ASSERT_MSG(false, "Unimplemented"); | 573 | UNREACHABLE(); |
| 345 | } | 574 | } |
| 346 | 575 | ||
| 347 | void RasterizerOpenGL::SyncBlendColor() { | 576 | void RasterizerOpenGL::SyncBlendColor() { |
| 348 | ASSERT_MSG(false, "Unimplemented"); | 577 | UNREACHABLE(); |
| 349 | } | 578 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b387f383b..fd53e94cd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -29,7 +29,7 @@ public: | |||
| 29 | RasterizerOpenGL(); | 29 | RasterizerOpenGL(); |
| 30 | ~RasterizerOpenGL() override; | 30 | ~RasterizerOpenGL() override; |
| 31 | 31 | ||
| 32 | void DrawTriangles() override; | 32 | void DrawArrays() override; |
| 33 | void NotifyMaxwellRegisterChanged(u32 id) override; | 33 | void NotifyMaxwellRegisterChanged(u32 id) override; |
| 34 | void FlushAll() override; | 34 | void FlushAll() override; |
| 35 | void FlushRegion(VAddr addr, u64 size) override; | 35 | void FlushRegion(VAddr addr, u64 size) override; |
| @@ -87,6 +87,13 @@ public: | |||
| 87 | private: | 87 | private: |
| 88 | struct SamplerInfo {}; | 88 | struct SamplerInfo {}; |
| 89 | 89 | ||
| 90 | /// Binds the framebuffer color and depth surface | ||
| 91 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, | ||
| 92 | bool has_stencil); | ||
| 93 | |||
| 94 | /// Syncs the viewport to match the guest state | ||
| 95 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); | ||
| 96 | |||
| 90 | /// Syncs the clip enabled status to match the guest state | 97 | /// Syncs the clip enabled status to match the guest state |
| 91 | void SyncClipEnabled(); | 98 | void SyncClipEnabled(); |
| 92 | 99 | ||
| @@ -139,7 +146,7 @@ private: | |||
| 139 | OGLVertexArray hw_vao; | 146 | OGLVertexArray hw_vao; |
| 140 | std::array<bool, 16> hw_vao_enabled_attributes; | 147 | std::array<bool, 16> hw_vao_enabled_attributes; |
| 141 | 148 | ||
| 142 | std::array<SamplerInfo, 3> texture_samplers; | 149 | std::array<SamplerInfo, 32> texture_samplers; |
| 143 | static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024; | 150 | static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024; |
| 144 | std::unique_ptr<OGLStreamBuffer> vertex_buffer; | 151 | std::unique_ptr<OGLStreamBuffer> vertex_buffer; |
| 145 | OGLBuffer uniform_buffer; | 152 | OGLBuffer uniform_buffer; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 78fa7c051..2ffbd3bab 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -21,10 +21,13 @@ | |||
| 21 | #include "common/microprofile.h" | 21 | #include "common/microprofile.h" |
| 22 | #include "common/scope_exit.h" | 22 | #include "common/scope_exit.h" |
| 23 | #include "common/vector_math.h" | 23 | #include "common/vector_math.h" |
| 24 | #include "core/core.h" | ||
| 24 | #include "core/frontend/emu_window.h" | 25 | #include "core/frontend/emu_window.h" |
| 26 | #include "core/hle/kernel/process.h" | ||
| 25 | #include "core/hle/kernel/vm_manager.h" | 27 | #include "core/hle/kernel/vm_manager.h" |
| 26 | #include "core/memory.h" | 28 | #include "core/memory.h" |
| 27 | #include "core/settings.h" | 29 | #include "core/settings.h" |
| 30 | #include "video_core/engines/maxwell_3d.h" | ||
| 28 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 31 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 29 | #include "video_core/renderer_opengl/gl_state.h" | 32 | #include "video_core/renderer_opengl/gl_state.h" |
| 30 | #include "video_core/utils.h" | 33 | #include "video_core/utils.h" |
| @@ -110,65 +113,26 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { | |||
| 110 | template <bool morton_to_gl, PixelFormat format> | 113 | template <bool morton_to_gl, PixelFormat format> |
| 111 | static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { | 114 | static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { |
| 112 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; | 115 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; |
| 113 | constexpr u32 tile_size = bytes_per_pixel * 64; | ||
| 114 | |||
| 115 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | 116 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); |
| 116 | static_assert(gl_bytes_per_pixel >= bytes_per_pixel, ""); | ||
| 117 | gl_buffer += gl_bytes_per_pixel - bytes_per_pixel; | ||
| 118 | |||
| 119 | const VAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size); | ||
| 120 | const VAddr aligned_start = base + Common::AlignUp(start - base, tile_size); | ||
| 121 | const VAddr aligned_end = base + Common::AlignDown(end - base, tile_size); | ||
| 122 | |||
| 123 | ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end)); | ||
| 124 | |||
| 125 | const u64 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel; | ||
| 126 | u32 x = static_cast<u32>((begin_pixel_index % (stride * 8)) / 8); | ||
| 127 | u32 y = static_cast<u32>((begin_pixel_index / (stride * 8)) * 8); | ||
| 128 | |||
| 129 | gl_buffer += ((height - 8 - y) * stride + x) * gl_bytes_per_pixel; | ||
| 130 | |||
| 131 | auto glbuf_next_tile = [&] { | ||
| 132 | x = (x + 8) % stride; | ||
| 133 | gl_buffer += 8 * gl_bytes_per_pixel; | ||
| 134 | if (!x) { | ||
| 135 | y += 8; | ||
| 136 | gl_buffer -= stride * 9 * gl_bytes_per_pixel; | ||
| 137 | } | ||
| 138 | }; | ||
| 139 | |||
| 140 | u8* tile_buffer = Memory::GetPointer(start); | ||
| 141 | |||
| 142 | if (start < aligned_start && !morton_to_gl) { | ||
| 143 | std::array<u8, tile_size> tmp_buf; | ||
| 144 | MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | ||
| 145 | std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start], | ||
| 146 | std::min(aligned_start, end) - start); | ||
| 147 | |||
| 148 | tile_buffer += aligned_start - start; | ||
| 149 | glbuf_next_tile(); | ||
| 150 | } | ||
| 151 | |||
| 152 | const u8* const buffer_end = tile_buffer + aligned_end - aligned_start; | ||
| 153 | while (tile_buffer < buffer_end) { | ||
| 154 | MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer); | ||
| 155 | tile_buffer += tile_size; | ||
| 156 | glbuf_next_tile(); | ||
| 157 | } | ||
| 158 | 117 | ||
| 159 | if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) { | 118 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the |
| 160 | std::array<u8, tile_size> tmp_buf; | 119 | // configuration for this and perform more generic un/swizzle |
| 161 | MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | 120 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); |
| 162 | std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end); | 121 | VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, |
| 163 | } | 122 | Memory::GetPointer(base), gl_buffer, morton_to_gl); |
| 164 | } | 123 | } |
| 165 | 124 | ||
| 166 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { | 125 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { |
| 167 | MortonCopy<true, PixelFormat::RGBA8>, // 0 | 126 | MortonCopy<true, PixelFormat::RGBA8>, |
| 168 | MortonCopy<true, PixelFormat::RGB8>, // 1 | 127 | nullptr, |
| 169 | MortonCopy<true, PixelFormat::RGB5A1>, // 2 | 128 | nullptr, |
| 170 | MortonCopy<true, PixelFormat::RGB565>, // 3 | 129 | nullptr, |
| 171 | MortonCopy<true, PixelFormat::RGBA4>, // 4 | 130 | nullptr, |
| 131 | nullptr, | ||
| 132 | nullptr, | ||
| 133 | nullptr, | ||
| 134 | nullptr, | ||
| 135 | nullptr, | ||
| 172 | nullptr, | 136 | nullptr, |
| 173 | nullptr, | 137 | nullptr, |
| 174 | nullptr, | 138 | nullptr, |
| @@ -177,19 +141,19 @@ static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> mo | |||
| 177 | nullptr, | 141 | nullptr, |
| 178 | nullptr, | 142 | nullptr, |
| 179 | nullptr, | 143 | nullptr, |
| 180 | nullptr, // 5 - 13 | ||
| 181 | MortonCopy<true, PixelFormat::D16>, // 14 | ||
| 182 | nullptr, // 15 | ||
| 183 | MortonCopy<true, PixelFormat::D24>, // 16 | ||
| 184 | MortonCopy<true, PixelFormat::D24S8> // 17 | ||
| 185 | }; | 144 | }; |
| 186 | 145 | ||
| 187 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { | 146 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { |
| 188 | MortonCopy<false, PixelFormat::RGBA8>, // 0 | 147 | MortonCopy<false, PixelFormat::RGBA8>, |
| 189 | MortonCopy<false, PixelFormat::RGB8>, // 1 | 148 | nullptr, |
| 190 | MortonCopy<false, PixelFormat::RGB5A1>, // 2 | 149 | nullptr, |
| 191 | MortonCopy<false, PixelFormat::RGB565>, // 3 | 150 | nullptr, |
| 192 | MortonCopy<false, PixelFormat::RGBA4>, // 4 | 151 | nullptr, |
| 152 | nullptr, | ||
| 153 | nullptr, | ||
| 154 | nullptr, | ||
| 155 | nullptr, | ||
| 156 | nullptr, | ||
| 193 | nullptr, | 157 | nullptr, |
| 194 | nullptr, | 158 | nullptr, |
| 195 | nullptr, | 159 | nullptr, |
| @@ -198,11 +162,6 @@ static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl | |||
| 198 | nullptr, | 162 | nullptr, |
| 199 | nullptr, | 163 | nullptr, |
| 200 | nullptr, | 164 | nullptr, |
| 201 | nullptr, // 5 - 13 | ||
| 202 | MortonCopy<false, PixelFormat::D16>, // 14 | ||
| 203 | nullptr, // 15 | ||
| 204 | MortonCopy<false, PixelFormat::D24>, // 16 | ||
| 205 | MortonCopy<false, PixelFormat::D24S8> // 17 | ||
| 206 | }; | 165 | }; |
| 207 | 166 | ||
| 208 | // Allocate an uninitialized texture of appropriate size and format for the surface | 167 | // Allocate an uninitialized texture of appropriate size and format for the surface |
| @@ -291,8 +250,8 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec | |||
| 291 | 250 | ||
| 292 | static bool FillSurface(const Surface& surface, const u8* fill_data, | 251 | static bool FillSurface(const Surface& surface, const u8* fill_data, |
| 293 | const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) { | 252 | const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) { |
| 294 | ASSERT_MSG(false, "Unimplemented"); | 253 | UNREACHABLE(); |
| 295 | return true; | 254 | return {}; |
| 296 | } | 255 | } |
| 297 | 256 | ||
| 298 | SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { | 257 | SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { |
| @@ -531,7 +490,7 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64 | |||
| 531 | void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { | 490 | void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { |
| 532 | ASSERT(type != SurfaceType::Fill); | 491 | ASSERT(type != SurfaceType::Fill); |
| 533 | 492 | ||
| 534 | u8* texture_src_data = Memory::GetPointer(addr); | 493 | u8* const texture_src_data = Memory::GetPointer(addr); |
| 535 | if (texture_src_data == nullptr) | 494 | if (texture_src_data == nullptr) |
| 536 | return; | 495 | return; |
| 537 | 496 | ||
| @@ -548,11 +507,16 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { | |||
| 548 | if (!is_tiled) { | 507 | if (!is_tiled) { |
| 549 | ASSERT(type == SurfaceType::Color); | 508 | ASSERT(type == SurfaceType::Color); |
| 550 | const u32 bytes_per_pixel{GetFormatBpp() >> 3}; | 509 | const u32 bytes_per_pixel{GetFormatBpp() >> 3}; |
| 510 | |||
| 511 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check | ||
| 512 | // the configuration for this and perform more generic un/swizzle | ||
| 513 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); | ||
| 551 | VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4, | 514 | VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4, |
| 552 | texture_src_data + start_offset, &gl_buffer[start_offset], | 515 | texture_src_data + start_offset, &gl_buffer[start_offset], |
| 553 | true); | 516 | true); |
| 554 | } else { | 517 | } else { |
| 555 | ASSERT_MSG(false, "Unimplemented"); | 518 | morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr, |
| 519 | load_start, load_end); | ||
| 556 | } | 520 | } |
| 557 | } | 521 | } |
| 558 | 522 | ||
| @@ -1093,18 +1057,106 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& | |||
| 1093 | } | 1057 | } |
| 1094 | 1058 | ||
| 1095 | Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { | 1059 | Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { |
| 1096 | ASSERT_MSG(false, "Unimplemented"); | 1060 | UNREACHABLE(); |
| 1097 | return {}; | 1061 | return {}; |
| 1098 | } | 1062 | } |
| 1099 | 1063 | ||
| 1100 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | 1064 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( |
| 1101 | bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) { | 1065 | bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) { |
| 1102 | UNIMPLEMENTED(); | 1066 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 1103 | return {}; | 1067 | const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager; |
| 1068 | const auto& config = regs.rt[0]; | ||
| 1069 | |||
| 1070 | // TODO(bunnei): This is hard corded to use just the first render buffer | ||
| 1071 | LOG_WARNING(Render_OpenGL, "hard-coded for render target 0!"); | ||
| 1072 | |||
| 1073 | // update resolution_scale_factor and reset cache if changed | ||
| 1074 | // TODO (bunnei): This code was ported as-is from Citra, and is technically not thread-safe. We | ||
| 1075 | // need to fix this before making the renderer multi-threaded. | ||
| 1076 | static u16 resolution_scale_factor = GetResolutionScaleFactor(); | ||
| 1077 | if (resolution_scale_factor != GetResolutionScaleFactor()) { | ||
| 1078 | resolution_scale_factor = GetResolutionScaleFactor(); | ||
| 1079 | FlushAll(); | ||
| 1080 | while (!surface_cache.empty()) | ||
| 1081 | UnregisterSurface(*surface_cache.begin()->second.begin()); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | MathUtil::Rectangle<u32> viewport_clamped{ | ||
| 1085 | static_cast<u32>(MathUtil::Clamp(viewport.left, 0, static_cast<s32>(config.width))), | ||
| 1086 | static_cast<u32>(MathUtil::Clamp(viewport.top, 0, static_cast<s32>(config.height))), | ||
| 1087 | static_cast<u32>(MathUtil::Clamp(viewport.right, 0, static_cast<s32>(config.width))), | ||
| 1088 | static_cast<u32>(MathUtil::Clamp(viewport.bottom, 0, static_cast<s32>(config.height)))}; | ||
| 1089 | |||
| 1090 | // get color and depth surfaces | ||
| 1091 | SurfaceParams color_params; | ||
| 1092 | color_params.is_tiled = true; | ||
| 1093 | color_params.res_scale = resolution_scale_factor; | ||
| 1094 | color_params.width = config.width; | ||
| 1095 | color_params.height = config.height; | ||
| 1096 | SurfaceParams depth_params = color_params; | ||
| 1097 | |||
| 1098 | color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address()); | ||
| 1099 | color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format); | ||
| 1100 | color_params.UpdateParams(); | ||
| 1101 | |||
| 1102 | ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented"); | ||
| 1103 | // depth_params.addr = config.GetDepthBufferPhysicalAddress(); | ||
| 1104 | // depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(config.depth_format); | ||
| 1105 | // depth_params.UpdateParams(); | ||
| 1106 | |||
| 1107 | auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped); | ||
| 1108 | auto depth_vp_interval = depth_params.GetSubRectInterval(viewport_clamped); | ||
| 1109 | |||
| 1110 | // Make sure that framebuffers don't overlap if both color and depth are being used | ||
| 1111 | if (using_color_fb && using_depth_fb && | ||
| 1112 | boost::icl::length(color_vp_interval & depth_vp_interval)) { | ||
| 1113 | LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " | ||
| 1114 | "overlapping framebuffers not supported!"); | ||
| 1115 | using_depth_fb = false; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | MathUtil::Rectangle<u32> color_rect{}; | ||
| 1119 | Surface color_surface = nullptr; | ||
| 1120 | if (using_color_fb) | ||
| 1121 | std::tie(color_surface, color_rect) = | ||
| 1122 | GetSurfaceSubRect(color_params, ScaleMatch::Exact, false); | ||
| 1123 | |||
| 1124 | MathUtil::Rectangle<u32> depth_rect{}; | ||
| 1125 | Surface depth_surface = nullptr; | ||
| 1126 | if (using_depth_fb) | ||
| 1127 | std::tie(depth_surface, depth_rect) = | ||
| 1128 | GetSurfaceSubRect(depth_params, ScaleMatch::Exact, false); | ||
| 1129 | |||
| 1130 | MathUtil::Rectangle<u32> fb_rect{}; | ||
| 1131 | if (color_surface != nullptr && depth_surface != nullptr) { | ||
| 1132 | fb_rect = color_rect; | ||
| 1133 | // Color and Depth surfaces must have the same dimensions and offsets | ||
| 1134 | if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top || | ||
| 1135 | color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) { | ||
| 1136 | color_surface = GetSurface(color_params, ScaleMatch::Exact, false); | ||
| 1137 | depth_surface = GetSurface(depth_params, ScaleMatch::Exact, false); | ||
| 1138 | fb_rect = color_surface->GetScaledRect(); | ||
| 1139 | } | ||
| 1140 | } else if (color_surface != nullptr) { | ||
| 1141 | fb_rect = color_rect; | ||
| 1142 | } else if (depth_surface != nullptr) { | ||
| 1143 | fb_rect = depth_rect; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | if (color_surface != nullptr) { | ||
| 1147 | ValidateSurface(color_surface, boost::icl::first(color_vp_interval), | ||
| 1148 | boost::icl::length(color_vp_interval)); | ||
| 1149 | } | ||
| 1150 | if (depth_surface != nullptr) { | ||
| 1151 | ValidateSurface(depth_surface, boost::icl::first(depth_vp_interval), | ||
| 1152 | boost::icl::length(depth_vp_interval)); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | return std::make_tuple(color_surface, depth_surface, fb_rect); | ||
| 1104 | } | 1156 | } |
| 1105 | 1157 | ||
| 1106 | Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { | 1158 | Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { |
| 1107 | ASSERT_MSG(false, "Unimplemented"); | 1159 | UNREACHABLE(); |
| 1108 | return {}; | 1160 | return {}; |
| 1109 | } | 1161 | } |
| 1110 | 1162 | ||
| @@ -1348,5 +1400,33 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { | |||
| 1348 | } | 1400 | } |
| 1349 | 1401 | ||
| 1350 | void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | 1402 | void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { |
| 1351 | // ASSERT_MSG(false, "Unimplemented"); | 1403 | const u64 num_pages = |
| 1404 | ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; | ||
| 1405 | const u64 page_start = addr >> Memory::PAGE_BITS; | ||
| 1406 | const u64 page_end = page_start + num_pages; | ||
| 1407 | |||
| 1408 | // Interval maps will erase segments if count reaches 0, so if delta is negative we have to | ||
| 1409 | // subtract after iterating | ||
| 1410 | const auto pages_interval = PageMap::interval_type::right_open(page_start, page_end); | ||
| 1411 | if (delta > 0) | ||
| 1412 | cached_pages.add({pages_interval, delta}); | ||
| 1413 | |||
| 1414 | for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) { | ||
| 1415 | const auto interval = pair.first & pages_interval; | ||
| 1416 | const int count = pair.second; | ||
| 1417 | |||
| 1418 | const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; | ||
| 1419 | const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; | ||
| 1420 | const u64 interval_size = interval_end_addr - interval_start_addr; | ||
| 1421 | |||
| 1422 | if (delta > 0 && count == delta) | ||
| 1423 | Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true); | ||
| 1424 | else if (delta < 0 && count == -delta) | ||
| 1425 | Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false); | ||
| 1426 | else | ||
| 1427 | ASSERT(count >= 0); | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | if (delta < 0) | ||
| 1431 | cached_pages.add({pages_interval, delta}); | ||
| 1352 | } | 1432 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 14f3cdc38..1f660d30c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -41,7 +41,7 @@ static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval | |||
| 41 | using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; | 41 | using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; |
| 42 | using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; | 42 | using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; |
| 43 | 43 | ||
| 44 | using PageMap = boost::icl::interval_map<u32, int>; | 44 | using PageMap = boost::icl::interval_map<u64, int>; |
| 45 | 45 | ||
| 46 | enum class ScaleMatch { | 46 | enum class ScaleMatch { |
| 47 | Exact, // only accept same res scale | 47 | Exact, // only accept same res scale |
| @@ -116,6 +116,15 @@ struct SurfaceParams { | |||
| 116 | return GetFormatBpp(pixel_format); | 116 | return GetFormatBpp(pixel_format); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { | ||
| 120 | switch (format) { | ||
| 121 | case Tegra::RenderTargetFormat::RGBA8_UNORM: | ||
| 122 | return PixelFormat::RGBA8; | ||
| 123 | default: | ||
| 124 | UNREACHABLE(); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 119 | static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { | 128 | static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { |
| 120 | switch (format) { | 129 | switch (format) { |
| 121 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: | 130 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: |
| @@ -308,7 +317,7 @@ public: | |||
| 308 | 317 | ||
| 309 | /// Get the color and depth surfaces based on the framebuffer configuration | 318 | /// Get the color and depth surfaces based on the framebuffer configuration |
| 310 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | 319 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, |
| 311 | const MathUtil::Rectangle<s32>& viewport_rect); | 320 | const MathUtil::Rectangle<s32>& viewport); |
| 312 | 321 | ||
| 313 | /// Get a surface that matches the fill config | 322 | /// Get a surface that matches the fill config |
| 314 | Surface GetFillSurface(const void* config); | 323 | Surface GetFillSurface(const void* config); |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 0e0ef18cc..564ea8f9e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {} | 26 | sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {} |
| 27 | 27 | ||
| 28 | std::string Decompile() { | 28 | std::string Decompile() { |
| 29 | UNIMPLEMENTED(); | 29 | UNREACHABLE(); |
| 30 | return {}; | 30 | return {}; |
| 31 | } | 31 | } |
| 32 | 32 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index f242bce1d..8f3c98800 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -8,12 +8,12 @@ | |||
| 8 | namespace GLShader { | 8 | namespace GLShader { |
| 9 | 9 | ||
| 10 | std::string GenerateVertexShader(const MaxwellVSConfig& config) { | 10 | std::string GenerateVertexShader(const MaxwellVSConfig& config) { |
| 11 | UNIMPLEMENTED(); | 11 | UNREACHABLE(); |
| 12 | return {}; | 12 | return {}; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | std::string GenerateFragmentShader(const MaxwellFSConfig& config) { | 15 | std::string GenerateFragmentShader(const MaxwellFSConfig& config) { |
| 16 | UNIMPLEMENTED(); | 16 | UNREACHABLE(); |
| 17 | return {}; | 17 | return {}; |
| 18 | } | 18 | } |
| 19 | 19 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index a3ba16761..a6c6204d5 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -38,8 +38,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, | |||
| 38 | if (result == GL_TRUE) { | 38 | if (result == GL_TRUE) { |
| 39 | LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]); | 39 | LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]); |
| 40 | } else { | 40 | } else { |
| 41 | LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", | 41 | LOG_CRITICAL(Render_OpenGL, "Error compiling vertex shader:\n%s", |
| 42 | &vertex_shader_error[0]); | 42 | &vertex_shader_error[0]); |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| @@ -62,8 +62,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, | |||
| 62 | if (result == GL_TRUE) { | 62 | if (result == GL_TRUE) { |
| 63 | LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]); | 63 | LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]); |
| 64 | } else { | 64 | } else { |
| 65 | LOG_ERROR(Render_OpenGL, "Error compiling geometry shader:\n%s", | 65 | LOG_CRITICAL(Render_OpenGL, "Error compiling geometry shader:\n%s", |
| 66 | &geometry_shader_error[0]); | 66 | &geometry_shader_error[0]); |
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| @@ -86,8 +86,8 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, | |||
| 86 | if (result == GL_TRUE) { | 86 | if (result == GL_TRUE) { |
| 87 | LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); | 87 | LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); |
| 88 | } else { | 88 | } else { |
| 89 | LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", | 89 | LOG_CRITICAL(Render_OpenGL, "Error compiling fragment shader:\n%s", |
| 90 | &fragment_shader_error[0]); | 90 | &fragment_shader_error[0]); |
| 91 | } | 91 | } |
| 92 | } | 92 | } |
| 93 | } | 93 | } |
| @@ -128,20 +128,20 @@ GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, | |||
| 128 | if (result == GL_TRUE) { | 128 | if (result == GL_TRUE) { |
| 129 | LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]); | 129 | LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]); |
| 130 | } else { | 130 | } else { |
| 131 | LOG_ERROR(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]); | 131 | LOG_CRITICAL(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]); |
| 132 | } | 132 | } |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | // If the program linking failed at least one of the shaders was probably bad | 135 | // If the program linking failed at least one of the shaders was probably bad |
| 136 | if (result == GL_FALSE) { | 136 | if (result == GL_FALSE) { |
| 137 | if (vertex_shader) { | 137 | if (vertex_shader) { |
| 138 | LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader); | 138 | LOG_CRITICAL(Render_OpenGL, "Vertex shader:\n%s", vertex_shader); |
| 139 | } | 139 | } |
| 140 | if (geometry_shader) { | 140 | if (geometry_shader) { |
| 141 | LOG_ERROR(Render_OpenGL, "Geometry shader:\n%s", geometry_shader); | 141 | LOG_CRITICAL(Render_OpenGL, "Geometry shader:\n%s", geometry_shader); |
| 142 | } | 142 | } |
| 143 | if (fragment_shader) { | 143 | if (fragment_shader) { |
| 144 | LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader); | 144 | LOG_CRITICAL(Render_OpenGL, "Fragment shader:\n%s", fragment_shader); |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | ASSERT_MSG(result == GL_TRUE, "Shader not linked"); | 147 | ASSERT_MSG(result == GL_TRUE, "Shader not linked"); |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 940575dfa..c1f4efc8c 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -85,7 +85,7 @@ public: | |||
| 85 | struct { | 85 | struct { |
| 86 | GLuint texture_2d; // GL_TEXTURE_BINDING_2D | 86 | GLuint texture_2d; // GL_TEXTURE_BINDING_2D |
| 87 | GLuint sampler; // GL_SAMPLER_BINDING | 87 | GLuint sampler; // GL_SAMPLER_BINDING |
| 88 | } texture_units[3]; | 88 | } texture_units[32]; |
| 89 | 89 | ||
| 90 | struct { | 90 | struct { |
| 91 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | 91 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h new file mode 100644 index 000000000..d847317ac --- /dev/null +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <glad/glad.h> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/engines/maxwell_3d.h" | ||
| 12 | |||
| 13 | namespace MaxwellToGL { | ||
| 14 | |||
| 15 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 16 | |||
| 17 | inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | ||
| 18 | switch (attrib.type) { | ||
| 19 | case Maxwell::VertexAttribute::Type::UnsignedNorm: { | ||
| 20 | |||
| 21 | switch (attrib.size) { | ||
| 22 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 23 | return GL_UNSIGNED_BYTE; | ||
| 24 | } | ||
| 25 | |||
| 26 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str()); | ||
| 27 | UNREACHABLE(); | ||
| 28 | return {}; | ||
| 29 | } | ||
| 30 | |||
| 31 | case Maxwell::VertexAttribute::Type::Float: | ||
| 32 | return GL_FLOAT; | ||
| 33 | } | ||
| 34 | |||
| 35 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str()); | ||
| 36 | UNREACHABLE(); | ||
| 37 | return {}; | ||
| 38 | } | ||
| 39 | |||
| 40 | inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | ||
| 41 | switch (topology) { | ||
| 42 | case Maxwell::PrimitiveTopology::TriangleStrip: | ||
| 43 | return GL_TRIANGLE_STRIP; | ||
| 44 | } | ||
| 45 | LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology); | ||
| 46 | UNREACHABLE(); | ||
| 47 | return {}; | ||
| 48 | } | ||
| 49 | |||
| 50 | } // namespace MaxwellToGL | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 1a24855d7..78b50b227 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -100,6 +100,8 @@ RendererOpenGL::~RendererOpenGL() = default; | |||
| 100 | 100 | ||
| 101 | /// Swap buffers (render frame) | 101 | /// Swap buffers (render frame) |
| 102 | void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { | 102 | void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { |
| 103 | Core::System::GetInstance().perf_stats.EndSystemFrame(); | ||
| 104 | |||
| 103 | // Maintain the rasterizer's state as a priority | 105 | // Maintain the rasterizer's state as a priority |
| 104 | OpenGLState prev_state = OpenGLState::GetCurState(); | 106 | OpenGLState prev_state = OpenGLState::GetCurState(); |
| 105 | state.Apply(); | 107 | state.Apply(); |
| @@ -114,20 +116,19 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig& | |||
| 114 | // performance problem. | 116 | // performance problem. |
| 115 | ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | 117 | ConfigureFramebufferTexture(screen_info.texture, *framebuffer); |
| 116 | } | 118 | } |
| 119 | |||
| 120 | // Load the framebuffer from memory, draw it to the screen, and swap buffers | ||
| 117 | LoadFBToScreenInfo(*framebuffer, screen_info); | 121 | LoadFBToScreenInfo(*framebuffer, screen_info); |
| 122 | DrawScreen(); | ||
| 123 | render_window->SwapBuffers(); | ||
| 118 | } | 124 | } |
| 119 | 125 | ||
| 120 | DrawScreens(); | ||
| 121 | |||
| 122 | Core::System::GetInstance().perf_stats.EndSystemFrame(); | ||
| 123 | |||
| 124 | // Swap buffers | ||
| 125 | render_window->PollEvents(); | 126 | render_window->PollEvents(); |
| 126 | render_window->SwapBuffers(); | ||
| 127 | 127 | ||
| 128 | Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); | 128 | Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); |
| 129 | Core::System::GetInstance().perf_stats.BeginSystemFrame(); | 129 | Core::System::GetInstance().perf_stats.BeginSystemFrame(); |
| 130 | 130 | ||
| 131 | // Restore the rasterizer state | ||
| 131 | prev_state.Apply(); | 132 | prev_state.Apply(); |
| 132 | RefreshRasterizerSetting(); | 133 | RefreshRasterizerSetting(); |
| 133 | } | 134 | } |
| @@ -141,11 +142,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||
| 141 | const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; | 142 | const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; |
| 142 | const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; | 143 | const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; |
| 143 | 144 | ||
| 144 | // TODO(bunnei): The framebuffer region should only be invalidated if it is written to, not | ||
| 145 | // every frame. When we find the right place for this, the below line can be removed. | ||
| 146 | Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, | ||
| 147 | Memory::FlushMode::Invalidate); | ||
| 148 | |||
| 149 | // Framebuffer orientation handling | 145 | // Framebuffer orientation handling |
| 150 | framebuffer_transform_flags = framebuffer.transform_flags; | 146 | framebuffer_transform_flags = framebuffer.transform_flags; |
| 151 | 147 | ||
| @@ -283,7 +279,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
| 283 | gl_framebuffer_data.resize(texture.width * texture.height * 4); | 279 | gl_framebuffer_data.resize(texture.width * texture.height * 4); |
| 284 | break; | 280 | break; |
| 285 | default: | 281 | default: |
| 286 | UNIMPLEMENTED(); | 282 | UNREACHABLE(); |
| 287 | } | 283 | } |
| 288 | 284 | ||
| 289 | state.texture_units[0].texture_2d = texture.resource.handle; | 285 | state.texture_units[0].texture_2d = texture.resource.handle; |
| @@ -297,8 +293,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | |||
| 297 | state.Apply(); | 293 | state.Apply(); |
| 298 | } | 294 | } |
| 299 | 295 | ||
| 300 | void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, | 296 | void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, |
| 301 | float h) { | 297 | float h) { |
| 302 | const auto& texcoords = screen_info.display_texcoords; | 298 | const auto& texcoords = screen_info.display_texcoords; |
| 303 | auto left = texcoords.left; | 299 | auto left = texcoords.left; |
| 304 | auto right = texcoords.right; | 300 | auto right = texcoords.right; |
| @@ -309,7 +305,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl | |||
| 309 | right = texcoords.left; | 305 | right = texcoords.left; |
| 310 | } else { | 306 | } else { |
| 311 | // Other transformations are unsupported | 307 | // Other transformations are unsupported |
| 312 | LOG_CRITICAL(HW_GPU, "unsupported framebuffer_transform_flags=%d", | 308 | LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags=%d", |
| 313 | framebuffer_transform_flags); | 309 | framebuffer_transform_flags); |
| 314 | UNIMPLEMENTED(); | 310 | UNIMPLEMENTED(); |
| 315 | } | 311 | } |
| @@ -334,7 +330,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl | |||
| 334 | /** | 330 | /** |
| 335 | * Draws the emulated screens to the emulator window. | 331 | * Draws the emulated screens to the emulator window. |
| 336 | */ | 332 | */ |
| 337 | void RendererOpenGL::DrawScreens() { | 333 | void RendererOpenGL::DrawScreen() { |
| 338 | const auto& layout = render_window->GetFramebufferLayout(); | 334 | const auto& layout = render_window->GetFramebufferLayout(); |
| 339 | const auto& screen = layout.screen; | 335 | const auto& screen = layout.screen; |
| 340 | 336 | ||
| @@ -350,8 +346,8 @@ void RendererOpenGL::DrawScreens() { | |||
| 350 | glActiveTexture(GL_TEXTURE0); | 346 | glActiveTexture(GL_TEXTURE0); |
| 351 | glUniform1i(uniform_color_texture, 0); | 347 | glUniform1i(uniform_color_texture, 0); |
| 352 | 348 | ||
| 353 | DrawSingleScreen(screen_info, (float)screen.left, (float)screen.top, (float)screen.GetWidth(), | 349 | DrawScreenTriangles(screen_info, (float)screen.left, (float)screen.top, |
| 354 | (float)screen.GetHeight()); | 350 | (float)screen.GetWidth(), (float)screen.GetHeight()); |
| 355 | 351 | ||
| 356 | m_current_frame++; | 352 | m_current_frame++; |
| 357 | } | 353 | } |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 29516baf4..fffd0f9f4 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -55,8 +55,8 @@ private: | |||
| 55 | void InitOpenGLObjects(); | 55 | void InitOpenGLObjects(); |
| 56 | void ConfigureFramebufferTexture(TextureInfo& texture, | 56 | void ConfigureFramebufferTexture(TextureInfo& texture, |
| 57 | const Tegra::FramebufferConfig& framebuffer); | 57 | const Tegra::FramebufferConfig& framebuffer); |
| 58 | void DrawScreens(); | 58 | void DrawScreen(); |
| 59 | void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); | 59 | void DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, float h); |
| 60 | void UpdateFramerate(); | 60 | void UpdateFramerate(); |
| 61 | 61 | ||
| 62 | // Loads framebuffer from emulated memory into the display information structure | 62 | // Loads framebuffer from emulated memory into the display information structure |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 864691baa..289140f31 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -26,7 +26,7 @@ bool Init(EmuWindow* emu_window) { | |||
| 26 | if (g_renderer->Init()) { | 26 | if (g_renderer->Init()) { |
| 27 | LOG_DEBUG(Render, "initialized OK"); | 27 | LOG_DEBUG(Render, "initialized OK"); |
| 28 | } else { | 28 | } else { |
| 29 | LOG_ERROR(Render, "initialization failed !"); | 29 | LOG_CRITICAL(Render, "initialization failed !"); |
| 30 | return false; | 30 | return false; |
| 31 | } | 31 | } |
| 32 | return true; | 32 | return true; |
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 8e6509adc..1e4844b57 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp | |||
| @@ -339,11 +339,10 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 339 | static_cast<size_t>(Source::RenderTarget0)]; | 339 | static_cast<size_t>(Source::RenderTarget0)]; |
| 340 | 340 | ||
| 341 | surface_address = rt.Address(); | 341 | surface_address = rt.Address(); |
| 342 | surface_width = rt.horiz; | 342 | surface_width = rt.width; |
| 343 | surface_height = rt.vert; | 343 | surface_height = rt.height; |
| 344 | if (rt.format != 0) { | 344 | if (rt.format != Tegra::RenderTargetFormat::NONE) { |
| 345 | surface_format = | 345 | surface_format = ConvertToTextureFormat(rt.format); |
| 346 | ConvertToTextureFormat(static_cast<Tegra::RenderTargetFormat>(rt.format)); | ||
| 347 | } | 346 | } |
| 348 | 347 | ||
| 349 | break; | 348 | break; |