mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 15:39:02 -05:00 
			
		
		
		
	gl_rasterizer: Implement a framebuffer cache
This commit is contained in:
		| @@ -79,6 +79,26 @@ struct DrawParameters { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct FramebufferCacheKey { | ||||||
|  |     bool is_single_buffer = false; | ||||||
|  |     bool stencil_enable = false; | ||||||
|  |  | ||||||
|  |     std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{}; | ||||||
|  |     std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{}; | ||||||
|  |     u32 colors_count = 0; | ||||||
|  |  | ||||||
|  |     GLuint zeta = 0; | ||||||
|  |  | ||||||
|  |     auto Tie() const { | ||||||
|  |         return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count, | ||||||
|  |                         zeta); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool operator<(const FramebufferCacheKey& rhs) const { | ||||||
|  |         return Tie() < rhs.Tie(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
| RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) | ||||||
|     : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info}, |     : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info}, | ||||||
|       buffer_cache(*this, STREAM_BUFFER_SIZE) { |       buffer_cache(*this, STREAM_BUFFER_SIZE) { | ||||||
| @@ -103,9 +123,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo | |||||||
|  |  | ||||||
|     OpenGLState::ApplyDefaultState(); |     OpenGLState::ApplyDefaultState(); | ||||||
|  |  | ||||||
|     // Create render framebuffer |  | ||||||
|     framebuffer.Create(); |  | ||||||
|  |  | ||||||
|     shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |     shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | ||||||
|     state.draw.shader_program = 0; |     state.draw.shader_program = 0; | ||||||
|     state.Apply(); |     state.Apply(); | ||||||
| @@ -363,6 +380,44 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, | ||||||
|  |                                               OpenGLState& current_state) { | ||||||
|  |     const auto [entry, is_cache_miss] = framebuffer_cache.try_emplace(fbkey); | ||||||
|  |     auto& framebuffer = entry->second; | ||||||
|  |  | ||||||
|  |     if (is_cache_miss) | ||||||
|  |         framebuffer.Create(); | ||||||
|  |  | ||||||
|  |     current_state.draw.draw_framebuffer = framebuffer.handle; | ||||||
|  |     current_state.ApplyFramebufferState(); | ||||||
|  |  | ||||||
|  |     if (!is_cache_miss) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     if (fbkey.is_single_buffer) { | ||||||
|  |         if (fbkey.color_attachments[0] != GL_NONE) { | ||||||
|  |             glFramebufferTexture(GL_DRAW_FRAMEBUFFER, fbkey.color_attachments[0], fbkey.colors[0], | ||||||
|  |                                  0); | ||||||
|  |         } | ||||||
|  |         glDrawBuffer(fbkey.color_attachments[0]); | ||||||
|  |     } else { | ||||||
|  |         for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||||
|  |             if (fbkey.colors[index]) { | ||||||
|  |                 glFramebufferTexture(GL_DRAW_FRAMEBUFFER, | ||||||
|  |                                      GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), | ||||||
|  |                                      fbkey.colors[index], 0); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         glDrawBuffers(fbkey.colors_count, fbkey.color_attachments.data()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (fbkey.zeta) { | ||||||
|  |         GLenum zeta_attachment = | ||||||
|  |             fbkey.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; | ||||||
|  |         glFramebufferTexture(GL_DRAW_FRAMEBUFFER, zeta_attachment, fbkey.zeta, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|  |  | ||||||
| @@ -446,10 +501,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us | |||||||
|     ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); |     ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); | ||||||
|  |  | ||||||
|     // Bind the framebuffer surfaces |     // Bind the framebuffer surfaces | ||||||
|     current_state.draw.draw_framebuffer = framebuffer.handle; |  | ||||||
|     current_state.ApplyFramebufferState(); |  | ||||||
|     current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; |     current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; | ||||||
|  |  | ||||||
|  |     FramebufferCacheKey fbkey; | ||||||
|  |  | ||||||
|     if (using_color_fb) { |     if (using_color_fb) { | ||||||
|         if (single_color_target) { |         if (single_color_target) { | ||||||
|             // Used when just a single color attachment is enabled, e.g. for clearing a color buffer |             // Used when just a single color attachment is enabled, e.g. for clearing a color buffer | ||||||
| @@ -465,14 +520,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us | |||||||
|                 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; |                 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             glFramebufferTexture2D( |             fbkey.is_single_buffer = true; | ||||||
|                 GL_DRAW_FRAMEBUFFER, |             fbkey.color_attachments[0] = | ||||||
|                 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, |                 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); | ||||||
|                 color_surface != nullptr ? color_surface->Texture().handle : 0, 0); |             fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0; | ||||||
|             glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target)); |  | ||||||
|         } else { |         } else { | ||||||
|             // Multiple color attachments are enabled |             // Multiple color attachments are enabled | ||||||
|             std::array<GLenum, Maxwell::NumRenderTargets> buffers; |  | ||||||
|             for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { |             for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||||
|                 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); |                 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | ||||||
|  |  | ||||||
| @@ -487,22 +540,17 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us | |||||||
|                         color_surface->GetSurfaceParams().srgb_conversion; |                         color_surface->GetSurfaceParams().srgb_conversion; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); |                 fbkey.color_attachments[index] = | ||||||
|                 glFramebufferTexture2D( |                     GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | ||||||
|                     GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), |                 fbkey.colors[index] = | ||||||
|                     GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0, |                     color_surface != nullptr ? color_surface->Texture().handle : 0; | ||||||
|                     0); |  | ||||||
|             } |             } | ||||||
|             glDrawBuffers(regs.rt_control.count, buffers.data()); |             fbkey.is_single_buffer = false; | ||||||
|  |             fbkey.colors_count = regs.rt_control.count; | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         // No color attachments are enabled - zero out all of them |         // No color attachments are enabled - leave them as zero | ||||||
|         for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { |         fbkey.is_single_buffer = true; | ||||||
|             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, |  | ||||||
|                                    GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, |  | ||||||
|                                    0, 0); |  | ||||||
|         } |  | ||||||
|         glDrawBuffer(GL_NONE); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (depth_surface) { |     if (depth_surface) { | ||||||
| @@ -510,22 +558,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us | |||||||
|         // the shader doesn't actually write to it. |         // the shader doesn't actually write to it. | ||||||
|         depth_surface->MarkAsModified(true, res_cache); |         depth_surface->MarkAsModified(true, res_cache); | ||||||
|  |  | ||||||
|         if (regs.stencil_enable) { |         fbkey.zeta = depth_surface->Texture().handle; | ||||||
|             // Attach both depth and stencil |         fbkey.stencil_enable = regs.stencil_enable; | ||||||
|             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |  | ||||||
|                                    depth_surface->Texture().handle, 0); |  | ||||||
|         } else { |  | ||||||
|             // Attach depth |  | ||||||
|             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |  | ||||||
|                                    depth_surface->Texture().handle, 0); |  | ||||||
|             // Clear stencil attachment |  | ||||||
|             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // Clear both depth and stencil attachment |  | ||||||
|         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, |  | ||||||
|                                0); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     SetupCachedFramebuffer(fbkey, current_state); | ||||||
|  |  | ||||||
|     SyncViewport(current_state); |     SyncViewport(current_state); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ namespace OpenGL { | |||||||
|  |  | ||||||
| struct ScreenInfo; | struct ScreenInfo; | ||||||
| struct DrawParameters; | struct DrawParameters; | ||||||
|  | struct FramebufferCacheKey; | ||||||
|  |  | ||||||
| class RasterizerOpenGL : public VideoCore::RasterizerInterface { | class RasterizerOpenGL : public VideoCore::RasterizerInterface { | ||||||
| public: | public: | ||||||
| @@ -211,11 +212,12 @@ private: | |||||||
|              OGLVertexArray> |              OGLVertexArray> | ||||||
|         vertex_array_cache; |         vertex_array_cache; | ||||||
|  |  | ||||||
|  |     std::map<FramebufferCacheKey, OGLFramebuffer> framebuffer_cache; | ||||||
|  |  | ||||||
|     std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers; |     std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers; | ||||||
|  |  | ||||||
|     static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |     static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | ||||||
|     OGLBufferCache buffer_cache; |     OGLBufferCache buffer_cache; | ||||||
|     OGLFramebuffer framebuffer; |  | ||||||
|     PrimitiveAssembler primitive_assembler{buffer_cache}; |     PrimitiveAssembler primitive_assembler{buffer_cache}; | ||||||
|     GLint uniform_buffer_alignment; |     GLint uniform_buffer_alignment; | ||||||
|  |  | ||||||
| @@ -230,6 +232,8 @@ private: | |||||||
|  |  | ||||||
|     void SetupShaders(GLenum primitive_mode); |     void SetupShaders(GLenum primitive_mode); | ||||||
|  |  | ||||||
|  |     void SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, OpenGLState& current_state); | ||||||
|  |  | ||||||
|     enum class AccelDraw { Disabled, Arrays, Indexed }; |     enum class AccelDraw { Disabled, Arrays, Indexed }; | ||||||
|     AccelDraw accelerate_draw = AccelDraw::Disabled; |     AccelDraw accelerate_draw = AccelDraw::Disabled; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ReinUsesLisp
					ReinUsesLisp