Merge pull request #1824 from ReinUsesLisp/fbcache

gl_rasterizer: Implement a framebuffer cache
This commit is contained in:
bunnei 2018-12-06 11:56:59 -05:00 committed by GitHub
commit 9390452195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 40 deletions

View File

@ -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) {
@ -90,9 +110,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();
@ -361,6 +378,44 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
SyncClipEnabled(clip_distances); SyncClipEnabled(clip_distances);
} }
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;
@ -444,10 +499,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0); UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
// 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
@ -463,14 +518,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);
@ -485,22 +538,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) {
@ -508,22 +556,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);
} }

View File

@ -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:
@ -195,11 +196,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;
@ -214,6 +216,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;