diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 103 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 13 |
2 files changed, 66 insertions, 50 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index fdfca767a..c59f3af1b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -294,19 +294,12 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int 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); 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; if (using_depth_fb) { 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.Apply(); - 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); + if (using_color_fb) { + if (single_color_target) { + // Used when just a single color attachment is enabled, e.g. for clearing a color buffer + Surface color_surface = + res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); + glFramebufferTexture2D( + 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 (has_stencil) { + if (regs.stencil_enable) { // Attach both depth and stencil glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_surface->Texture().handle, 0); @@ -360,8 +375,9 @@ void RasterizerOpenGL::Clear() { SCOPE_EXIT({ prev_state.Apply(); }); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - bool use_color_fb = false; - bool use_depth_fb = false; + bool use_color{}; + bool use_depth{}; + bool use_stencil{}; OpenGLState clear_state; 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.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 || regs.clear_buffers.A) { - if (regs.clear_buffers.RT == 0) { - // 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); - } + use_color = true; } if (regs.clear_buffers.Z) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); - use_depth_fb = true; - clear_mask |= GL_DEPTH_BUFFER_BIT; + use_depth = true; // 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. @@ -394,33 +401,33 @@ void RasterizerOpenGL::Clear() { } if (regs.clear_buffers.S) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); - use_depth_fb = true; - clear_mask |= GL_STENCIL_BUFFER_BIT; + use_stencil = 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 return; } - if (clear_mask == 0) { - // No clear mask is enabled - return; - } - 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(); - glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], - regs.clear_color[3]); - glClearDepth(regs.clear_depth); - glClearStencil(regs.clear_stencil); + if (use_color) { + glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); + } - 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() { @@ -433,7 +440,7 @@ void RasterizerOpenGL::DrawArrays() { ScopeAcquireGLContext acquire_context{emu_window}; - ConfigureFramebuffers(true, true); + ConfigureFramebuffers(); SyncDepthTestState(); SyncStencilTestState(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index eaf31ae96..745c3dc0c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -13,6 +13,7 @@ #include <vector> #include <boost/icl/interval_map.hpp> +#include <boost/optional.hpp> #include <boost/range/iterator_range.hpp> #include <glad/glad.h> @@ -96,8 +97,16 @@ private: 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. |