gl_framebuffer_cache: Use a hashed struct to cache framebuffers
This commit is contained in:
		| @@ -41,6 +41,8 @@ add_library(video_core STATIC | ||||
|     renderer_opengl/gl_buffer_cache.h | ||||
|     renderer_opengl/gl_device.cpp | ||||
|     renderer_opengl/gl_device.h | ||||
|     renderer_opengl/gl_framebuffer_cache.cpp | ||||
|     renderer_opengl/gl_framebuffer_cache.h | ||||
|     renderer_opengl/gl_global_cache.cpp | ||||
|     renderer_opengl/gl_global_cache.h | ||||
|     renderer_opengl/gl_rasterizer.cpp | ||||
|   | ||||
							
								
								
									
										73
									
								
								src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| // Copyright 2019 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <tuple> | ||||
|  | ||||
| #include "common/cityhash.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/renderer_opengl/gl_framebuffer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||
|  | ||||
| FramebufferCacheOpenGL::FramebufferCacheOpenGL() = default; | ||||
|  | ||||
| FramebufferCacheOpenGL::~FramebufferCacheOpenGL() = default; | ||||
|  | ||||
| GLuint FramebufferCacheOpenGL::GetFramebuffer(const FramebufferCacheKey& key) { | ||||
|     const auto [entry, is_cache_miss] = cache.try_emplace(key); | ||||
|     auto& framebuffer{entry->second}; | ||||
|     if (is_cache_miss) { | ||||
|         framebuffer = CreateFramebuffer(key); | ||||
|     } | ||||
|     return framebuffer.handle; | ||||
| } | ||||
|  | ||||
| OGLFramebuffer FramebufferCacheOpenGL::CreateFramebuffer(const FramebufferCacheKey& key) { | ||||
|     OGLFramebuffer framebuffer; | ||||
|     framebuffer.Create(); | ||||
|  | ||||
|     // TODO(Rodrigo): Use DSA here after Nvidia fixes their framebuffer DSA bugs. | ||||
|     local_state.draw.draw_framebuffer = framebuffer.handle; | ||||
|     local_state.ApplyFramebufferState(); | ||||
|  | ||||
|     if (key.is_single_buffer) { | ||||
|         if (key.color_attachments[0] != GL_NONE && key.colors[0]) { | ||||
|             key.colors[0]->Attach(key.color_attachments[0]); | ||||
|             glDrawBuffer(key.color_attachments[0]); | ||||
|         } else { | ||||
|             glDrawBuffer(GL_NONE); | ||||
|         } | ||||
|     } else { | ||||
|         for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||
|             if (key.colors[index]) { | ||||
|                 key.colors[index]->Attach(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index)); | ||||
|             } | ||||
|         } | ||||
|         glDrawBuffers(key.colors_count, key.color_attachments.data()); | ||||
|     } | ||||
|  | ||||
|     if (key.zeta) { | ||||
|         key.zeta->Attach(key.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); | ||||
|     } | ||||
|  | ||||
|     return framebuffer; | ||||
| } | ||||
|  | ||||
| std::size_t FramebufferCacheKey::Hash() const { | ||||
|     static_assert(sizeof(*this) % sizeof(u64) == 0, "Unaligned struct"); | ||||
|     return static_cast<std::size_t>( | ||||
|         Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); | ||||
| } | ||||
|  | ||||
| bool FramebufferCacheKey::operator==(const FramebufferCacheKey& rhs) const { | ||||
|     return std::tie(is_single_buffer, stencil_enable, colors_count, color_attachments, colors, | ||||
|                     zeta) == std::tie(rhs.is_single_buffer, rhs.stencil_enable, rhs.colors_count, | ||||
|                                       rhs.color_attachments, rhs.colors, rhs.zeta); | ||||
| } | ||||
|  | ||||
| } // namespace OpenGL | ||||
							
								
								
									
										68
									
								
								src/video_core/renderer_opengl/gl_framebuffer_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/video_core/renderer_opengl/gl_framebuffer_cache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // Copyright 2019 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <unordered_map> | ||||
|  | ||||
| #include <glad/glad.h> | ||||
|  | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_texture_cache.h" | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| struct alignas(sizeof(u64)) FramebufferCacheKey { | ||||
|     bool is_single_buffer = false; | ||||
|     bool stencil_enable = false; | ||||
|     u16 colors_count = 0; | ||||
|  | ||||
|     std::array<GLenum, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> color_attachments{}; | ||||
|     std::array<View, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors; | ||||
|     View zeta; | ||||
|  | ||||
|     std::size_t Hash() const; | ||||
|  | ||||
|     bool operator==(const FramebufferCacheKey& rhs) const; | ||||
|  | ||||
|     bool operator!=(const FramebufferCacheKey& rhs) const { | ||||
|         return !operator==(rhs); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace OpenGL | ||||
|  | ||||
| namespace std { | ||||
|  | ||||
| template <> | ||||
| struct hash<OpenGL::FramebufferCacheKey> { | ||||
|     std::size_t operator()(const OpenGL::FramebufferCacheKey& k) const noexcept { | ||||
|         return k.Hash(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace std | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| class FramebufferCacheOpenGL { | ||||
| public: | ||||
|     FramebufferCacheOpenGL(); | ||||
|     ~FramebufferCacheOpenGL(); | ||||
|  | ||||
|     GLuint GetFramebuffer(const FramebufferCacheKey& key); | ||||
|  | ||||
| private: | ||||
|     OGLFramebuffer CreateFramebuffer(const FramebufferCacheKey& key); | ||||
|  | ||||
|     OpenGLState local_state; | ||||
|     std::unordered_map<FramebufferCacheKey, OGLFramebuffer> cache; | ||||
| }; | ||||
|  | ||||
| } // namespace OpenGL | ||||
| @@ -78,26 +78,6 @@ struct DrawParameters { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| struct FramebufferCacheKey { | ||||
|     bool is_single_buffer = false; | ||||
|     bool stencil_enable = false; | ||||
|  | ||||
|     std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{}; | ||||
|     std::array<View, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{}; | ||||
|     u32 colors_count = 0; | ||||
|  | ||||
|     View zeta = nullptr; | ||||
|  | ||||
|     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::System& system, Core::Frontend::EmuWindow& emu_window, | ||||
|                                    ScreenInfo& info) | ||||
|     : texture_cache{system, *this}, shader_cache{*this, system, emu_window, device}, | ||||
| @@ -355,42 +335,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | ||||
|     gpu.dirty_flags.shaders = false; | ||||
| } | ||||
|  | ||||
| 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 && fbkey.colors[0]) { | ||||
|             fbkey.colors[0]->Attach(fbkey.color_attachments[0]); | ||||
|             glDrawBuffer(fbkey.color_attachments[0]); | ||||
|         } else { | ||||
|             glDrawBuffer(GL_NONE); | ||||
|         } | ||||
|     } else { | ||||
|         for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||
|             if (fbkey.colors[index]) { | ||||
|                 fbkey.colors[index]->Attach(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index)); | ||||
|             } | ||||
|         } | ||||
|         glDrawBuffers(fbkey.colors_count, fbkey.color_attachments.data()); | ||||
|     } | ||||
|  | ||||
|     if (fbkey.zeta) { | ||||
|         fbkey.zeta->Attach(fbkey.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT | ||||
|                                                 : GL_DEPTH_ATTACHMENT); | ||||
|     } | ||||
| } | ||||
|  | ||||
| std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | ||||
|     const auto& regs = system.GPU().Maxwell3D().regs; | ||||
|  | ||||
| @@ -556,7 +500,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | ||||
|                                depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; | ||||
|     } | ||||
|  | ||||
|     SetupCachedFramebuffer(fbkey, current_state); | ||||
|     current_state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(fbkey); | ||||
|     SyncViewport(current_state); | ||||
|  | ||||
|     return current_depth_stencil_usage = {static_cast<bool>(depth_surface), fbkey.stencil_enable}; | ||||
| @@ -638,6 +582,7 @@ void RasterizerOpenGL::Clear() { | ||||
|     clear_state.ApplyDepth(); | ||||
|     clear_state.ApplyStencilTest(); | ||||
|     clear_state.ApplyViewport(); | ||||
|     clear_state.ApplyFramebufferState(); | ||||
|  | ||||
|     if (use_color) { | ||||
|         glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/renderer_opengl/gl_buffer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_device.h" | ||||
| #include "video_core/renderer_opengl/gl_framebuffer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_global_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_sampler_cache.h" | ||||
| @@ -49,7 +50,6 @@ namespace OpenGL { | ||||
|  | ||||
| struct ScreenInfo; | ||||
| struct DrawParameters; | ||||
| struct FramebufferCacheKey; | ||||
|  | ||||
| class RasterizerOpenGL : public VideoCore::RasterizerInterface { | ||||
| public: | ||||
| @@ -193,6 +193,7 @@ private: | ||||
|     ShaderCacheOpenGL shader_cache; | ||||
|     GlobalRegionCacheOpenGL global_cache; | ||||
|     SamplerCacheOpenGL sampler_cache; | ||||
|     FramebufferCacheOpenGL framebuffer_cache; | ||||
|  | ||||
|     Core::System& system; | ||||
|     ScreenInfo& screen_info; | ||||
| @@ -203,7 +204,6 @@ private: | ||||
|              OGLVertexArray> | ||||
|         vertex_array_cache; | ||||
|  | ||||
|     std::map<FramebufferCacheKey, OGLFramebuffer> framebuffer_cache; | ||||
|     FramebufferConfigState current_framebuffer_config_state; | ||||
|     std::pair<bool, bool> current_depth_stencil_usage{}; | ||||
|  | ||||
| @@ -226,8 +226,6 @@ private: | ||||
|  | ||||
|     void SetupShaders(GLenum primitive_mode); | ||||
|  | ||||
|     void SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, OpenGLState& current_state); | ||||
|  | ||||
|     enum class AccelDraw { Disabled, Arrays, Indexed }; | ||||
|     AccelDraw accelerate_draw = AccelDraw::Disabled; | ||||
|  | ||||
|   | ||||
| @@ -133,7 +133,7 @@ public: | ||||
|             return {}; | ||||
|         } | ||||
|  | ||||
|         if (regs.color_mask[index].raw != 0) { | ||||
|         if (regs.color_mask[index].raw == 0) { | ||||
|             SetEmptyColorBuffer(index); | ||||
|             return {}; | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ReinUsesLisp
					ReinUsesLisp