summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-03-26 22:30:03 -0400
committerGravatar GitHub2018-03-26 22:30:03 -0400
commitb4bf099793d8e9a065769c35bb4b8e20bf107549 (patch)
tree2a9adcdcc7b3947242f3d4717302dc29425e8b0d /src
parentMerge pull request #283 from Subv/tsc (diff)
parentrenderer_opengl: Use better naming for DrawScreens and DrawSingleScreen. (diff)
downloadyuzu-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')
-rw-r--r--src/core/memory.cpp394
-rw-r--r--src/core/memory.h5
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp9
-rw-r--r--src/video_core/engines/maxwell_3d.h267
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/rasterizer_interface.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp289
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp238
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h13
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp20
-rw-r--r--src/video_core/renderer_opengl/gl_state.h2
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h50
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp32
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h4
-rw-r--r--src/video_core/video_core.cpp2
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp9
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
118template <typename T> 119/**
119boost::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 */
123static 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 */
152static u8* GetPointerFromVMA(VAddr vaddr) {
153 return GetPointerFromVMA(*Core::CurrentProcess(), vaddr);
154}
120 155
121template <typename T> 156template <typename T>
122T Read(const VAddr vaddr) { 157T 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
151template <typename T> 189template <typename T>
152bool WriteSpecial(VAddr addr, const T data);
153
154template <typename T>
155void Write(const VAddr vaddr, const T data) { 190void 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
183bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { 220bool 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
328void 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
294void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { 380void 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
347static 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
358void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 433void 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
421static 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
432void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 497void 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
476void ZeroBlock(const VAddr dest_addr, const size_t size) { 544void 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
517void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { 586void 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
562template <>
563boost::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
571template <>
572boost::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
580template <>
581boost::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
589template <>
590boost::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
598template <>
599bool 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
607template <>
608bool 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
616template <>
617bool 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
625template <>
626bool 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
634boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { 628boost::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 */
260void 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
13namespace Tegra { 16namespace Tegra {
14namespace Engines { 17namespace Engines {
@@ -174,7 +177,9 @@ void Maxwell3D::ProcessQueryGet() {
174} 177}
175 178
176void Maxwell3D::DrawArrays() { 179void 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
189void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) { 196void 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
14namespace Tegra { 14namespace Tegra {
15 15
16enum class RenderTargetFormat { 16enum 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 {
15public: 15public:
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
26using Maxwell = Tegra::Engines::Maxwell3D::Regs;
22using PixelFormat = SurfaceParams::PixelFormat; 27using PixelFormat = SurfaceParams::PixelFormat;
23using SurfaceType = SurfaceParams::SurfaceType; 28using 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
133RasterizerOpenGL::~RasterizerOpenGL() { 138RasterizerOpenGL::~RasterizerOpenGL() {
@@ -138,47 +143,235 @@ RasterizerOpenGL::~RasterizerOpenGL() {
138 } 143 }
139} 144}
140 145
141static 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
148void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { 146void 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
152void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { 157void 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
157void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) { 197void 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
162void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { 203void 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
167bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { 208bool 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
179void RasterizerOpenGL::DrawTriangles() { 220void 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
184void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} 377void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
@@ -206,17 +399,17 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
206 399
207bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { 400bool 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
213bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { 406bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
214 ASSERT_MSG(false, "Unimplemented"); 407 UNREACHABLE();
215 return true; 408 return true;
216} 409}
217 410
218bool RasterizerOpenGL::AccelerateFill(const void* config) { 411bool 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
512void 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
538void 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
319void RasterizerOpenGL::SyncClipEnabled() { 548void RasterizerOpenGL::SyncClipEnabled() {
320 ASSERT_MSG(false, "Unimplemented"); 549 UNREACHABLE();
321} 550}
322 551
323void RasterizerOpenGL::SyncClipCoef() { 552void RasterizerOpenGL::SyncClipCoef() {
324 ASSERT_MSG(false, "Unimplemented"); 553 UNREACHABLE();
325} 554}
326 555
327void RasterizerOpenGL::SyncCullMode() { 556void RasterizerOpenGL::SyncCullMode() {
328 ASSERT_MSG(false, "Unimplemented"); 557 UNREACHABLE();
329} 558}
330 559
331void RasterizerOpenGL::SyncDepthScale() { 560void RasterizerOpenGL::SyncDepthScale() {
332 ASSERT_MSG(false, "Unimplemented"); 561 UNREACHABLE();
333} 562}
334 563
335void RasterizerOpenGL::SyncDepthOffset() { 564void RasterizerOpenGL::SyncDepthOffset() {
336 ASSERT_MSG(false, "Unimplemented"); 565 UNREACHABLE();
337} 566}
338 567
339void RasterizerOpenGL::SyncBlendEnabled() { 568void RasterizerOpenGL::SyncBlendEnabled() {
340 ASSERT_MSG(false, "Unimplemented"); 569 UNREACHABLE();
341} 570}
342 571
343void RasterizerOpenGL::SyncBlendFuncs() { 572void RasterizerOpenGL::SyncBlendFuncs() {
344 ASSERT_MSG(false, "Unimplemented"); 573 UNREACHABLE();
345} 574}
346 575
347void RasterizerOpenGL::SyncBlendColor() { 576void 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:
87private: 87private:
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) {
110template <bool morton_to_gl, PixelFormat format> 113template <bool morton_to_gl, PixelFormat format>
111static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { 114static 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
166static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { 125static 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
187static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { 146static 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
292static bool FillSurface(const Surface& surface, const u8* fill_data, 251static 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
298SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { 257SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
@@ -531,7 +490,7 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64
531void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { 490void 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
1095Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { 1059Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
1096 ASSERT_MSG(false, "Unimplemented"); 1060 UNREACHABLE();
1097 return {}; 1061 return {};
1098} 1062}
1099 1063
1100SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( 1064SurfaceSurfaceRect_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
1106Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { 1158Surface 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
1350void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 1402void 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
41using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; 41using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>;
42using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; 42using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
43 43
44using PageMap = boost::icl::interval_map<u32, int>; 44using PageMap = boost::icl::interval_map<u64, int>;
45 45
46enum class ScaleMatch { 46enum 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 @@
8namespace GLShader { 8namespace GLShader {
9 9
10std::string GenerateVertexShader(const MaxwellVSConfig& config) { 10std::string GenerateVertexShader(const MaxwellVSConfig& config) {
11 UNIMPLEMENTED(); 11 UNREACHABLE();
12 return {}; 12 return {};
13} 13}
14 14
15std::string GenerateFragmentShader(const MaxwellFSConfig& config) { 15std::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
13namespace MaxwellToGL {
14
15using Maxwell = Tegra::Engines::Maxwell3D::Regs;
16
17inline 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
40inline 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)
102void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { 102void 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
300void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, 296void 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 */
337void RendererOpenGL::DrawScreens() { 333void 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;