mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	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