summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-09-09 19:01:21 -0400
committerGravatar bunnei2018-09-09 22:48:28 -0400
commit49b15af05437e665088105bd4873be478ad12b4b (patch)
treed98cbf1602f965349af120395350739dc6e204d7 /src
parentMerge pull request #1258 from tgsm/fix-sdl-logging (diff)
downloadyuzu-49b15af05437e665088105bd4873be478ad12b4b.tar.gz
yuzu-49b15af05437e665088105bd4873be478ad12b4b.tar.xz
yuzu-49b15af05437e665088105bd4873be478ad12b4b.zip
gl_rasterizer: Implement multiple color attachments.
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/maxwell_3d.h22
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp114
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp68
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h11
5 files changed, 95 insertions, 132 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index f59d01738..d3be900a4 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -533,7 +533,11 @@ public:
533 u32 stencil_back_mask; 533 u32 stencil_back_mask;
534 u32 stencil_back_func_mask; 534 u32 stencil_back_func_mask;
535 535
536 INSERT_PADDING_WORDS(0x20); 536 INSERT_PADDING_WORDS(0x13);
537
538 u32 rt_separate_frag_data;
539
540 INSERT_PADDING_WORDS(0xC);
537 541
538 struct { 542 struct {
539 u32 address_high; 543 u32 address_high;
@@ -557,7 +561,22 @@ public:
557 struct { 561 struct {
558 union { 562 union {
559 BitField<0, 4, u32> count; 563 BitField<0, 4, u32> count;
564 BitField<4, 3, u32> map_0;
565 BitField<7, 3, u32> map_1;
566 BitField<10, 3, u32> map_2;
567 BitField<13, 3, u32> map_3;
568 BitField<16, 3, u32> map_4;
569 BitField<19, 3, u32> map_5;
570 BitField<22, 3, u32> map_6;
571 BitField<25, 3, u32> map_7;
560 }; 572 };
573
574 u32 GetMap(size_t index) const {
575 const std::array<u32, NumRenderTargets> maps{map_0, map_1, map_2, map_3,
576 map_4, map_5, map_6, map_7};
577 ASSERT(index < maps.size());
578 return maps[index];
579 }
561 } rt_control; 580 } rt_control;
562 581
563 INSERT_PADDING_WORDS(0x2); 582 INSERT_PADDING_WORDS(0x2);
@@ -968,6 +987,7 @@ ASSERT_REG_POSITION(clear_stencil, 0x368);
968ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 987ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
969ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 988ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
970ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); 989ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
990ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
971ASSERT_REG_POSITION(zeta, 0x3F8); 991ASSERT_REG_POSITION(zeta, 0x3F8);
972ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 992ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
973ASSERT_REG_POSITION(rt_control, 0x487); 993ASSERT_REG_POSITION(rt_control, 0x487);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e6d6917fa..c7e2c877c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -294,17 +294,10 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
294 cached_pages.add({pages_interval, delta}); 294 cached_pages.add({pages_interval, delta});
295} 295}
296 296
297std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, 297void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents) {
298 bool using_depth_fb,
299 bool preserve_contents) {
300 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 298 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
301 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 299 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
302 300
303 if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) {
304 LOG_ERROR(HW_GPU, "RenderTargetFormat is not configured");
305 using_color_fb = false;
306 }
307
308 const bool has_stencil = regs.stencil_enable; 301 const bool has_stencil = regs.stencil_enable;
309 const bool write_color_fb = 302 const bool write_color_fb =
310 state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || 303 state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
@@ -314,41 +307,52 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
314 (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || 307 (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
315 (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask)); 308 (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask));
316 309
317 Surface color_surface;
318 Surface depth_surface; 310 Surface depth_surface;
319 MathUtil::Rectangle<u32> surfaces_rect; 311 if (using_depth_fb) {
320 std::tie(color_surface, depth_surface, surfaces_rect) = 312 depth_surface = res_cache.GetDepthBufferSurface(preserve_contents);
321 res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, preserve_contents); 313 }
322 314
323 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 315 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be
324 const MathUtil::Rectangle<u32> draw_rect{ 316 // used to enable multiple render targets. However, it is left unset on all games that I have
325 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, 317 // tested.
326 surfaces_rect.left, surfaces_rect.right)), // Left 318 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
327 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top,
328 surfaces_rect.bottom, surfaces_rect.top)), // Top
329 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right,
330 surfaces_rect.left, surfaces_rect.right)), // Right
331 static_cast<u32>(
332 std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom,
333 surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
334 319
335 // Bind the framebuffer surfaces 320 // Bind the framebuffer surfaces
336 BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); 321 state.draw.draw_framebuffer = framebuffer.handle;
322 state.Apply();
337 323
338 SyncViewport(surfaces_rect); 324 std::array<GLenum, Maxwell::NumRenderTargets> buffers;
325 for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
326 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
327 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
328 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
329 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
330 color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
331 }
339 332
340 // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable 333 glDrawBuffers(regs.rt_control.count, buffers.data());
341 // scissor test to prevent drawing outside of the framebuffer region 334
342 state.scissor.enabled = true; 335 if (depth_surface) {
343 state.scissor.x = draw_rect.left; 336 if (has_stencil) {
344 state.scissor.y = draw_rect.bottom; 337 // Attach both depth and stencil
345 state.scissor.width = draw_rect.GetWidth(); 338 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
346 state.scissor.height = draw_rect.GetHeight(); 339 depth_surface->Texture().handle, 0);
347 state.Apply(); 340 } else {
341 // Attach depth
342 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
343 depth_surface->Texture().handle, 0);
344 // Clear stencil attachment
345 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
346 }
347 } else {
348 // Clear both depth and stencil attachment
349 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
350 0);
351 }
352
353 SyncViewport();
348 354
349 // Only return the surface to be marked as dirty if writing to it is enabled. 355 state.Apply();
350 return std::make_pair(write_color_fb ? color_surface : nullptr,
351 write_depth_fb ? depth_surface : nullptr);
352} 356}
353 357
354void RasterizerOpenGL::Clear() { 358void RasterizerOpenGL::Clear() {
@@ -407,8 +411,7 @@ void RasterizerOpenGL::Clear() {
407 411
408 ScopeAcquireGLContext acquire_context{emu_window}; 412 ScopeAcquireGLContext acquire_context{emu_window};
409 413
410 auto [dirty_color_surface, dirty_depth_surface] = 414 ConfigureFramebuffers(use_depth_fb, false);
411 ConfigureFramebuffers(use_color_fb, use_depth_fb, false);
412 415
413 clear_state.Apply(); 416 clear_state.Apply();
414 417
@@ -430,8 +433,7 @@ void RasterizerOpenGL::DrawArrays() {
430 433
431 ScopeAcquireGLContext acquire_context{emu_window}; 434 ScopeAcquireGLContext acquire_context{emu_window};
432 435
433 const auto [dirty_color_surface, dirty_depth_surface] = 436 ConfigureFramebuffers(true, true);
434 ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
435 437
436 SyncDepthTestState(); 438 SyncDepthTestState();
437 SyncStencilTestState(); 439 SyncStencilTestState();
@@ -729,38 +731,12 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
729 return current_unit + static_cast<u32>(entries.size()); 731 return current_unit + static_cast<u32>(entries.size());
730} 732}
731 733
732void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, 734void RasterizerOpenGL::SyncViewport() {
733 const Surface& depth_surface, bool has_stencil) {
734 state.draw.draw_framebuffer = framebuffer.handle;
735 state.Apply();
736
737 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
738 color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
739 if (depth_surface != nullptr) {
740 if (has_stencil) {
741 // attach both depth and stencil
742 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
743 depth_surface->Texture().handle, 0);
744 } else {
745 // attach depth
746 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
747 depth_surface->Texture().handle, 0);
748 // clear stencil attachment
749 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
750 }
751 } else {
752 // clear both depth and stencil attachment
753 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
754 0);
755 }
756}
757
758void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect) {
759 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 735 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
760 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 736 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
761 737
762 state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left; 738 state.viewport.x = viewport_rect.left;
763 state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom; 739 state.viewport.y = viewport_rect.bottom;
764 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 740 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
765 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 741 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
766} 742}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index c6bb1516b..3d62cc196 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -97,14 +97,8 @@ private:
97 GLvec4 border_color; 97 GLvec4 border_color;
98 }; 98 };
99 99
100 /// Configures the color and depth framebuffer states and returns the dirty <Color, Depth> 100 /// Configures the color and depth framebuffer states
101 /// surfaces if writing was enabled. 101 void ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents);
102 std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
103 bool preserve_contents);
104
105 /// Binds the framebuffer color and depth surface
106 void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
107 bool has_stencil);
108 102
109 /* 103 /*
110 * Configures the current constbuffers to use for the draw command. 104 * Configures the current constbuffers to use for the draw command.
@@ -127,7 +121,7 @@ private:
127 u32 current_unit); 121 u32 current_unit);
128 122
129 /// Syncs the viewport to match the guest state 123 /// Syncs the viewport to match the guest state
130 void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect); 124 void SyncViewport();
131 125
132 /// Syncs the clip enabled status to match the guest state 126 /// Syncs the clip enabled status to match the guest state
133 void SyncClipEnabled(); 127 void SyncClipEnabled();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index fa730b9e6..20a8e1cda 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -61,8 +61,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
61 return params; 61 return params;
62} 62}
63 63
64/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer( 64/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(size_t index) {
65 const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config) { 65 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]};
66 SurfaceParams params{}; 66 SurfaceParams params{};
67 params.addr = TryGetCpuAddr(config.Address()); 67 params.addr = TryGetCpuAddr(config.Address());
68 params.is_tiled = true; 68 params.is_tiled = true;
@@ -708,62 +708,34 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
708 return GetSurface(SurfaceParams::CreateForTexture(config)); 708 return GetSurface(SurfaceParams::CreateForTexture(config));
709} 709}
710 710
711SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb, 711Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) {
712 bool using_depth_fb, 712 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
713 bool preserve_contents) { 713 if (!regs.zeta.Address() || !regs.zeta_enable) {
714 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 714 return {};
715 }
715 716
716 // TODO(bunnei): This is hard corded to use just the first render buffer 717 SurfaceParams depth_params{SurfaceParams::CreateForDepthBuffer(
717 LOG_TRACE(Render_OpenGL, "hard-coded for render target 0!"); 718 regs.zeta_width, regs.zeta_height, regs.zeta.Address(), regs.zeta.format)};
718 719
719 // get color and depth surfaces 720 return GetSurface(depth_params, preserve_contents);
720 SurfaceParams color_params{}; 721}
721 SurfaceParams depth_params{};
722 722
723 if (using_color_fb) { 723Surface RasterizerCacheOpenGL::GetColorBufferSurface(size_t index, bool preserve_contents) {
724 color_params = SurfaceParams::CreateForFramebuffer(regs.rt[0]); 724 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
725 }
726 725
727 if (using_depth_fb) { 726 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
728 depth_params = SurfaceParams::CreateForDepthBuffer(regs.zeta_width, regs.zeta_height,
729 regs.zeta.Address(), regs.zeta.format);
730 }
731 727
732 MathUtil::Rectangle<u32> color_rect{}; 728 if (index >= regs.rt_control.count) {
733 Surface color_surface; 729 return {};
734 if (using_color_fb) {
735 color_surface = GetSurface(color_params, preserve_contents);
736 if (color_surface) {
737 color_rect = color_surface->GetSurfaceParams().GetRect();
738 }
739 } 730 }
740 731
741 MathUtil::Rectangle<u32> depth_rect{}; 732 if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
742 Surface depth_surface; 733 return {};
743 if (using_depth_fb) {
744 depth_surface = GetSurface(depth_params, preserve_contents);
745 if (depth_surface) {
746 depth_rect = depth_surface->GetSurfaceParams().GetRect();
747 }
748 } 734 }
749 735
750 MathUtil::Rectangle<u32> fb_rect{}; 736 const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)};
751 if (color_surface && depth_surface) {
752 fb_rect = color_rect;
753 // Color and Depth surfaces must have the same dimensions and offsets
754 if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top ||
755 color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) {
756 color_surface = GetSurface(color_params);
757 depth_surface = GetSurface(depth_params);
758 fb_rect = color_surface->GetSurfaceParams().GetRect();
759 }
760 } else if (color_surface) {
761 fb_rect = color_rect;
762 } else if (depth_surface) {
763 fb_rect = depth_rect;
764 }
765 737
766 return std::make_tuple(color_surface, depth_surface, fb_rect); 738 return GetSurface(color_params, preserve_contents);
767} 739}
768 740
769void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { 741void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 8312b2c7a..e215f260f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -669,8 +669,7 @@ struct SurfaceParams {
669 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); 669 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
670 670
671 /// Creates SurfaceParams from a framebuffer configuration 671 /// Creates SurfaceParams from a framebuffer configuration
672 static SurfaceParams CreateForFramebuffer( 672 static SurfaceParams CreateForFramebuffer(size_t index);
673 const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config);
674 673
675 /// Creates SurfaceParams for a depth buffer configuration 674 /// Creates SurfaceParams for a depth buffer configuration
676 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height, 675 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height,
@@ -774,9 +773,11 @@ public:
774 /// Get a surface based on the texture configuration 773 /// Get a surface based on the texture configuration
775 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); 774 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
776 775
777 /// Get the color and depth surfaces based on the framebuffer configuration 776 /// Get the depth surface based on the framebuffer configuration
778 SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, 777 Surface GetDepthBufferSurface(bool preserve_contents);
779 bool preserve_contents); 778
779 /// Get the color surface based on the framebuffer configuration and the specified render target
780 Surface GetColorBufferSurface(size_t index, bool preserve_contents);
780 781
781 /// Flushes the surface to Switch memory 782 /// Flushes the surface to Switch memory
782 void FlushSurface(const Surface& surface); 783 void FlushSurface(const Surface& surface);