diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 1fac707d5..34dcb2364 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -861,12 +861,20 @@ bool GPU_HW::CompilePipelines() } else { - const u32 factor = (static_cast(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(transparency_mode) == + GPUTransparencyMode::HalfBackgroundPlusHalfForeground || + static_cast(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(transparency_mode) == GPUTransparencyMode::BackgroundMinusForeground && @@ -874,7 +882,6 @@ bool GPU_HW::CompilePipelines() static_cast(render_mode) != BatchRenderMode::OnlyOpaque) ? GPUPipeline::BlendOp::ReverseSubtract : GPUPipeline::BlendOp::Add; - plconfig.blend.constant = factor; } } diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index cb4cc11ac..da8972974 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -348,6 +348,10 @@ public: BitField write_a; BitField write_mask; BitField constant; + + BitField blend_factors; + BitField blend_ops; + u64 key; // clang-format off diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index fdd35c62e..0784779dd 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -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. diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index b2d72b8bf..66b267421 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -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 m_gl_context; std::unique_ptr m_window_framebuffer; diff --git a/src/util/opengl_pipeline.cpp b/src/util/opengl_pipeline.cpp index 4f894be17..d9048f99f 100644 --- a/src/util/opengl_pipeline.cpp +++ b/src/util/opengl_pipeline.cpp @@ -590,8 +590,12 @@ std::unique_ptr OpenGLDevice::CreatePipeline(const GPUPipeline::Gra config.blend, primitives[static_cast(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(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(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(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(bs.src_blend.GetValue())], - blend_mapping[static_cast(bs.dst_blend.GetValue())], - blend_mapping[static_cast(bs.src_alpha_blend.GetValue())], - blend_mapping[static_cast(bs.dst_alpha_blend.GetValue())]); - glBlendEquationSeparate(op_mapping[static_cast(bs.blend_op.GetValue())], - op_mapping[static_cast(bs.alpha_blend_op.GetValue())]); + if (bs.blend_factors != m_last_blend_state.blend_factors) + { + glBlendFuncSeparate(blend_mapping[static_cast(bs.src_blend.GetValue())], + blend_mapping[static_cast(bs.dst_blend.GetValue())], + blend_mapping[static_cast(bs.src_alpha_blend.GetValue())], + blend_mapping[static_cast(bs.dst_alpha_blend.GetValue())]); + } + + if (bs.blend_ops != m_last_blend_state.blend_ops) + { + glBlendEquationSeparate(op_mapping[static_cast(bs.blend_op.GetValue())], + op_mapping[static_cast(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(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();