OpenGLDevice: Cache intermediate state

This commit is contained in:
Stenzek 2023-10-08 01:47:29 +10:00
parent eb080834ad
commit ce7f6128e9
No known key found for this signature in database
5 changed files with 75 additions and 36 deletions

View file

@ -861,12 +861,20 @@ bool GPU_HW::CompilePipelines()
}
else
{
const u32 factor = (static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::HalfBackgroundPlusHalfForeground) ?
0xFF808080u :
0xFFFFFFFFu;
// TODO: This isn't entirely accurate, 127.5 versus 128.
// But if we use fbfetch on Mali, it doesn't matter.
plconfig.blend.src_blend = GPUPipeline::BlendFunc::One;
plconfig.blend.dst_blend = GPUPipeline::BlendFunc::ConstantColor;
plconfig.blend.dst_blend = GPUPipeline::BlendFunc::One;
if (static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::HalfBackgroundPlusHalfForeground ||
static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::BackgroundPlusQuarterForeground)
{
plconfig.blend.dst_blend = GPUPipeline::BlendFunc::ConstantColor;
plconfig.blend.dst_alpha_blend = GPUPipeline::BlendFunc::ConstantColor;
plconfig.blend.constant = 0x00808080u;
}
plconfig.blend.blend_op =
(static_cast<GPUTransparencyMode>(transparency_mode) ==
GPUTransparencyMode::BackgroundMinusForeground &&
@ -874,7 +882,6 @@ bool GPU_HW::CompilePipelines()
static_cast<BatchRenderMode>(render_mode) != BatchRenderMode::OnlyOpaque) ?
GPUPipeline::BlendOp::ReverseSubtract :
GPUPipeline::BlendOp::Add;
plconfig.blend.constant = factor;
}
}

View file

@ -348,6 +348,10 @@ public:
BitField<u64, bool, 27, 1> write_a;
BitField<u64, u8, 24, 4> write_mask;
BitField<u64, u32, 32, 32> constant;
BitField<u64, u16, 1, 16> blend_factors;
BitField<u64, u8, 17, 6> blend_ops;
u64 key;
// clang-format off

View file

@ -26,6 +26,8 @@ OpenGLDevice::OpenGLDevice()
std::memset(&m_last_rasterization_state, 0xFF, sizeof(m_last_rasterization_state));
std::memset(&m_last_depth_state, 0xFF, sizeof(m_last_depth_state));
std::memset(&m_last_blend_state, 0xFF, sizeof(m_last_blend_state));
m_last_blend_state.enable = false;
m_last_blend_state.constant = 0;
}
OpenGLDevice::~OpenGLDevice()
@ -425,6 +427,7 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo)
m_features.dual_source_blend =
(max_dual_source_draw_buffers > 0) &&
(GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended);
m_features.dual_source_blend = false;
#ifdef __APPLE__
// Partial texture buffer uploads appear to be broken in macOS's OpenGL driver.

View file

@ -160,6 +160,10 @@ private:
bool DiscardPipelineCache();
void ClosePipelineCache();
void ApplyRasterizationState(GPUPipeline::RasterizationState rs);
void ApplyDepthState(GPUPipeline::DepthState ds);
void ApplyBlendState(GPUPipeline::BlendState bs);
std::unique_ptr<GL::Context> m_gl_context;
std::unique_ptr<OpenGLFramebuffer> m_window_framebuffer;

View file

@ -590,8 +590,12 @@ std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::Gra
config.blend, primitives[static_cast<u8>(config.primitive)]));
}
ALWAYS_INLINE static void ApplyRasterizationState(const GPUPipeline::RasterizationState& rs)
ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyRasterizationState(GPUPipeline::RasterizationState rs)
{
if (m_last_rasterization_state == rs)
return;
// Only one thing, no need to check.
if (rs.cull_mode == GPUPipeline::CullMode::None)
{
glDisable(GL_CULL_FACE);
@ -601,9 +605,11 @@ ALWAYS_INLINE static void ApplyRasterizationState(const GPUPipeline::Rasterizati
glEnable(GL_CULL_FACE);
glCullFace((rs.cull_mode == GPUPipeline::CullMode::Front) ? GL_FRONT : GL_BACK);
}
m_last_rasterization_state = rs;
}
ALWAYS_INLINE static void ApplyDepthState(const GPUPipeline::DepthState& ds)
ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyDepthState(GPUPipeline::DepthState ds)
{
static constexpr std::array<GLenum, static_cast<u32>(GPUPipeline::DepthFunc::MaxCount)> func_mapping = {{
GL_NEVER, // Never
@ -615,13 +621,19 @@ ALWAYS_INLINE static void ApplyDepthState(const GPUPipeline::DepthState& ds)
GL_EQUAL, // Equal
}};
if (m_last_depth_state == ds)
return;
(ds.depth_test != GPUPipeline::DepthFunc::Always || ds.depth_write) ? glEnable(GL_DEPTH_TEST) :
glDisable(GL_DEPTH_TEST);
glDepthFunc(func_mapping[static_cast<u8>(ds.depth_test.GetValue())]);
glDepthMask(ds.depth_write);
if (m_last_depth_state.depth_write != ds.depth_write)
glDepthMask(ds.depth_write);
m_last_depth_state = ds;
}
ALWAYS_INLINE static void ApplyBlendState(const GPUPipeline::BlendState& bs)
ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyBlendState(GPUPipeline::BlendState bs)
{
static constexpr std::array<GLenum, static_cast<u32>(GPUPipeline::BlendFunc::MaxCount)> blend_mapping = {{
GL_ZERO, // Zero
@ -649,24 +661,44 @@ ALWAYS_INLINE static void ApplyBlendState(const GPUPipeline::BlendState& bs)
}};
// TODO: driver bugs
// TODO: rdoc and look for redundant calls
bs.enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
if (bs == m_last_blend_state)
return;
if (bs.enable != m_last_blend_state.enable)
bs.enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
if (bs.enable)
{
glBlendFuncSeparate(blend_mapping[static_cast<u8>(bs.src_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]);
glBlendEquationSeparate(op_mapping[static_cast<u8>(bs.blend_op.GetValue())],
op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]);
if (bs.blend_factors != m_last_blend_state.blend_factors)
{
glBlendFuncSeparate(blend_mapping[static_cast<u8>(bs.src_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())],
blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]);
}
if (bs.blend_ops != m_last_blend_state.blend_ops)
{
glBlendEquationSeparate(op_mapping[static_cast<u8>(bs.blend_op.GetValue())],
op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]);
}
// TODO: cache this to avoid calls?
glBlendColor(bs.GetConstantRed(), bs.GetConstantGreen(), bs.GetConstantBlue(), bs.GetConstantAlpha());
if (bs.constant != m_last_blend_state.constant)
glBlendColor(bs.GetConstantRed(), bs.GetConstantGreen(), bs.GetConstantBlue(), bs.GetConstantAlpha());
}
else
{
// Keep old values for blend options to potentially avoid calls when re-enabling.
bs.blend_factors.SetValue(m_last_blend_state.blend_factors);
bs.blend_ops.SetValue(m_last_blend_state.blend_ops);
bs.constant.SetValue(m_last_blend_state.constant);
}
glColorMask(bs.write_r, bs.write_g, bs.write_b, bs.write_a);
if (bs.write_mask != m_last_blend_state.write_mask)
glColorMask(bs.write_r, bs.write_g, bs.write_b, bs.write_a);
m_last_blend_state = bs;
}
void OpenGLDevice::SetPipeline(GPUPipeline* pipeline)
@ -677,21 +709,10 @@ void OpenGLDevice::SetPipeline(GPUPipeline* pipeline)
OpenGLPipeline* const P = static_cast<OpenGLPipeline*>(pipeline);
m_current_pipeline = P;
if (m_last_rasterization_state != P->GetRasterizationState())
{
m_last_rasterization_state = P->GetRasterizationState();
ApplyRasterizationState(m_last_rasterization_state);
}
if (m_last_depth_state != P->GetDepthState())
{
m_last_depth_state = P->GetDepthState();
ApplyDepthState(m_last_depth_state);
}
if (m_last_blend_state != P->GetBlendState())
{
m_last_blend_state = P->GetBlendState();
ApplyBlendState(m_last_blend_state);
}
ApplyRasterizationState(P->GetRasterizationState());
ApplyDepthState(P->GetDepthState());
ApplyBlendState(P->GetBlendState());
if (m_last_vao != P->GetVAO())
{
m_last_vao = P->GetVAO();