Merge pull request #1286 from bunnei/multi-clear
gl_rasterizer: Implement clear for non-zero render targets.
This commit is contained in:
		| @@ -294,19 +294,12 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | |||||||
|         cached_pages.add({pages_interval, delta}); |         cached_pages.add({pages_interval, delta}); | ||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents) { | void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, | ||||||
|  |                                              bool preserve_contents, | ||||||
|  |                                              boost::optional<size_t> single_color_target) { | ||||||
|     MICROPROFILE_SCOPE(OpenGL_Framebuffer); |     MICROPROFILE_SCOPE(OpenGL_Framebuffer); | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|  |  | ||||||
|     const bool has_stencil = regs.stencil_enable; |  | ||||||
|     const bool write_color_fb = |  | ||||||
|         state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || |  | ||||||
|         state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; |  | ||||||
|  |  | ||||||
|     const bool write_depth_fb = |  | ||||||
|         (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || |  | ||||||
|         (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask)); |  | ||||||
|  |  | ||||||
|     Surface depth_surface; |     Surface depth_surface; | ||||||
|     if (using_depth_fb) { |     if (using_depth_fb) { | ||||||
|         depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); |         depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); | ||||||
| @@ -321,19 +314,41 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_ | |||||||
|     state.draw.draw_framebuffer = framebuffer.handle; |     state.draw.draw_framebuffer = framebuffer.handle; | ||||||
|     state.Apply(); |     state.Apply(); | ||||||
|  |  | ||||||
|     std::array<GLenum, Maxwell::NumRenderTargets> buffers; |     if (using_color_fb) { | ||||||
|     for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { |         if (single_color_target) { | ||||||
|         Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); |             // Used when just a single color attachment is enabled, e.g. for clearing a color buffer | ||||||
|         buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); |             Surface color_surface = | ||||||
|         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, |                 res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); | ||||||
|                                GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, |             glFramebufferTexture2D( | ||||||
|                                color_surface != nullptr ? color_surface->Texture().handle : 0, 0); |                 GL_DRAW_FRAMEBUFFER, | ||||||
|  |                 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, | ||||||
|  |                 color_surface != nullptr ? color_surface->Texture().handle : 0, 0); | ||||||
|  |             glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target)); | ||||||
|  |         } else { | ||||||
|  |             // Multiple color attachments are enabled | ||||||
|  |             std::array<GLenum, Maxwell::NumRenderTargets> buffers; | ||||||
|  |             for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||||
|  |                 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | ||||||
|  |                 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | ||||||
|  |                 glFramebufferTexture2D( | ||||||
|  |                     GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), | ||||||
|  |                     GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0, | ||||||
|  |                     0); | ||||||
|  |             } | ||||||
|  |             glDrawBuffers(regs.rt_control.count, buffers.data()); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         // No color attachments are enabled - zero out all of them | ||||||
|  |         for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||||
|  |             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, | ||||||
|  |                                    GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, | ||||||
|  |                                    0, 0); | ||||||
|  |         } | ||||||
|  |         glDrawBuffer(GL_NONE); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     glDrawBuffers(regs.rt_control.count, buffers.data()); |  | ||||||
|  |  | ||||||
|     if (depth_surface) { |     if (depth_surface) { | ||||||
|         if (has_stencil) { |         if (regs.stencil_enable) { | ||||||
|             // Attach both depth and stencil |             // Attach both depth and stencil | ||||||
|             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||||||
|                                    depth_surface->Texture().handle, 0); |                                    depth_surface->Texture().handle, 0); | ||||||
| @@ -360,8 +375,9 @@ void RasterizerOpenGL::Clear() { | |||||||
|     SCOPE_EXIT({ prev_state.Apply(); }); |     SCOPE_EXIT({ prev_state.Apply(); }); | ||||||
|  |  | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|     bool use_color_fb = false; |     bool use_color{}; | ||||||
|     bool use_depth_fb = false; |     bool use_depth{}; | ||||||
|  |     bool use_stencil{}; | ||||||
|  |  | ||||||
|     OpenGLState clear_state; |     OpenGLState clear_state; | ||||||
|     clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; |     clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; | ||||||
| @@ -370,22 +386,13 @@ void RasterizerOpenGL::Clear() { | |||||||
|     clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; |     clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; | ||||||
|     clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; |     clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; | ||||||
|  |  | ||||||
|     GLbitfield clear_mask{}; |  | ||||||
|     if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || |     if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || | ||||||
|         regs.clear_buffers.A) { |         regs.clear_buffers.A) { | ||||||
|         if (regs.clear_buffers.RT == 0) { |         use_color = true; | ||||||
|             // We only support clearing the first color attachment for now |  | ||||||
|             clear_mask |= GL_COLOR_BUFFER_BIT; |  | ||||||
|             use_color_fb = true; |  | ||||||
|         } else { |  | ||||||
|             // TODO(subv): Add support for the other color attachments |  | ||||||
|             LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if (regs.clear_buffers.Z) { |     if (regs.clear_buffers.Z) { | ||||||
|         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); |         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); | ||||||
|         use_depth_fb = true; |         use_depth = true; | ||||||
|         clear_mask |= GL_DEPTH_BUFFER_BIT; |  | ||||||
|  |  | ||||||
|         // Always enable the depth write when clearing the depth buffer. The depth write mask is |         // Always enable the depth write when clearing the depth buffer. The depth write mask is | ||||||
|         // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. |         // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. | ||||||
| @@ -394,33 +401,33 @@ void RasterizerOpenGL::Clear() { | |||||||
|     } |     } | ||||||
|     if (regs.clear_buffers.S) { |     if (regs.clear_buffers.S) { | ||||||
|         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); | ||||||
|         use_depth_fb = true; |         use_stencil = true; | ||||||
|         clear_mask |= GL_STENCIL_BUFFER_BIT; |  | ||||||
|         clear_state.stencil.test_enabled = true; |         clear_state.stencil.test_enabled = true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!use_color_fb && !use_depth_fb) { |     if (!use_color && !use_depth && !use_stencil) { | ||||||
|         // No color surface nor depth/stencil surface are enabled |         // No color surface nor depth/stencil surface are enabled | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (clear_mask == 0) { |  | ||||||
|         // No clear mask is enabled |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ScopeAcquireGLContext acquire_context{emu_window}; |     ScopeAcquireGLContext acquire_context{emu_window}; | ||||||
|  |  | ||||||
|     ConfigureFramebuffers(use_depth_fb, false); |     ConfigureFramebuffers(use_color, use_depth || use_stencil, false, | ||||||
|  |                           regs.clear_buffers.RT.Value()); | ||||||
|  |  | ||||||
|     clear_state.Apply(); |     clear_state.Apply(); | ||||||
|  |  | ||||||
|     glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], |     if (use_color) { | ||||||
|                  regs.clear_color[3]); |         glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); | ||||||
|     glClearDepth(regs.clear_depth); |     } | ||||||
|     glClearStencil(regs.clear_stencil); |  | ||||||
|  |  | ||||||
|     glClear(clear_mask); |     if (use_depth && use_stencil) { | ||||||
|  |         glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); | ||||||
|  |     } else if (use_depth) { | ||||||
|  |         glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); | ||||||
|  |     } else if (use_stencil) { | ||||||
|  |         glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::DrawArrays() { | void RasterizerOpenGL::DrawArrays() { | ||||||
| @@ -433,7 +440,7 @@ void RasterizerOpenGL::DrawArrays() { | |||||||
|  |  | ||||||
|     ScopeAcquireGLContext acquire_context{emu_window}; |     ScopeAcquireGLContext acquire_context{emu_window}; | ||||||
|  |  | ||||||
|     ConfigureFramebuffers(true, true); |     ConfigureFramebuffers(); | ||||||
|  |  | ||||||
|     SyncDepthTestState(); |     SyncDepthTestState(); | ||||||
|     SyncStencilTestState(); |     SyncStencilTestState(); | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| #include <boost/icl/interval_map.hpp> | #include <boost/icl/interval_map.hpp> | ||||||
|  | #include <boost/optional.hpp> | ||||||
| #include <boost/range/iterator_range.hpp> | #include <boost/range/iterator_range.hpp> | ||||||
| #include <glad/glad.h> | #include <glad/glad.h> | ||||||
|  |  | ||||||
| @@ -96,8 +97,16 @@ private: | |||||||
|         GLvec4 border_color; |         GLvec4 border_color; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     /// Configures the color and depth framebuffer states |     /** | ||||||
|     void ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents); |      * Configures the color and depth framebuffer states. | ||||||
|  |      * @param use_color_fb If true, configure color framebuffers. | ||||||
|  |      * @param using_depth_fb If true, configure the depth/stencil framebuffer. | ||||||
|  |      * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. | ||||||
|  |      * @param single_color_target Specifies if a single color buffer target should be used. | ||||||
|  |      */ | ||||||
|  |     void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, | ||||||
|  |                                bool preserve_contents = true, | ||||||
|  |                                boost::optional<size_t> single_color_target = {}); | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * Configures the current constbuffers to use for the draw command. |      * Configures the current constbuffers to use for the draw command. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user