From 728116da8f791bf23480c64ded62622e2f6b5023 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 2 Jun 2026 20:26:55 +0200 Subject: [PATCH] Map renderer blend state to OpenGL --- docs/modernization/build-inventory.md | 9 ++-- docs/modernization/roadmap.md | 9 ++-- src/renderer_gl/opengl_capabilities.cpp | 27 ++++++++++ src/renderer_gl/opengl_capabilities.h | 14 ++++++ tests/renderer_gl/capabilities_tests.cpp | 63 ++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index cc872a5..32742b8 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -216,10 +216,11 @@ Known local toolchain state: queries, active-uniform count query, and matrix-uniform transpose token used by legacy `Shader` creation also live here. Renderer API blend factor/op to OpenGL token mapping is tested here with explicit support flags so `GL_ZERO` - stays distinguishable from unsupported enum values. Renderer API blend-state - color-write masks, depth compare-op to OpenGL depth-function mapping, and - aggregate renderer API depth-state to OpenGL enable/write/compare mapping are - tested here too. `Shader` no longer spells GL enum + stays distinguishable from unsupported enum values. Aggregate renderer API + blend-state to OpenGL enable/factor/equation/color-mask mapping, depth + compare-op to OpenGL depth-function mapping, and aggregate renderer API + depth-state to OpenGL enable/write/compare mapping are tested here too. + `Shader` no longer spells GL enum names directly. It also owns the PanoPainter shader uniform catalog and legacy hash mapping used by `Shader` active-uniform discovery and the uniform uniqueness check. App OpenGL initialization debug severity, debug output, GL info string, diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index c882a43..a2c62a8 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -473,10 +473,11 @@ binding catalog, shader stage tokens, compile/link status queries, active-unifor count query, and matrix-uniform transpose token also live in `pp_renderer_gl` and are consumed by legacy `Shader` creation. Renderer API blend factor/op to OpenGL token mapping also lives in `pp_renderer_gl`, with explicit support flags -so `GL_ZERO` remains distinguishable from unsupported enum values. Renderer API -blend-state color-write masks, depth compare-op to OpenGL depth-function -mapping, and aggregate renderer API depth-state to OpenGL enable/write/compare -mapping also live in `pp_renderer_gl`. Shader uniform hashing, catalog +so `GL_ZERO` remains distinguishable from unsupported enum values. Aggregate +renderer API blend-state to OpenGL enable/factor/equation/color-mask mapping, +depth compare-op to OpenGL depth-function mapping, and aggregate renderer API +depth-state to OpenGL enable/write/compare mapping also live in +`pp_renderer_gl`. Shader uniform hashing, catalog validation, active-uniform mapping, and the legacy uniform uniqueness check now delegate to `pp_renderer_gl` as well. `Shader` no longer spells GL enum names directly. App OpenGL initialization debug severity, debug output, GL info diff --git a/src/renderer_gl/opengl_capabilities.cpp b/src/renderer_gl/opengl_capabilities.cpp index d657361..0edcab9 100644 --- a/src/renderer_gl/opengl_capabilities.cpp +++ b/src/renderer_gl/opengl_capabilities.cpp @@ -813,6 +813,33 @@ OpenGlEnumMapping blend_equation_for_renderer_op(pp::renderer::BlendOp op) noexc } } +OpenGlBlendState blend_state_for_renderer_blend_state(pp::renderer::BlendState state) noexcept +{ + const auto source_color = blend_factor_for_renderer_factor(state.source_color); + const auto destination_color = blend_factor_for_renderer_factor(state.destination_color); + const auto color_op = blend_equation_for_renderer_op(state.color_op); + const auto source_alpha = blend_factor_for_renderer_factor(state.source_alpha); + const auto destination_alpha = blend_factor_for_renderer_factor(state.destination_alpha); + const auto alpha_op = blend_equation_for_renderer_op(state.alpha_op); + + return OpenGlBlendState { + .enabled = state.enabled ? gl_boolean_true : gl_boolean_false, + .source_color_factor = source_color.value, + .destination_color_factor = destination_color.value, + .color_equation = color_op.value, + .source_alpha_factor = source_alpha.value, + .destination_alpha_factor = destination_alpha.value, + .alpha_equation = alpha_op.value, + .color_write_mask = color_write_mask_for_renderer_blend_state(state), + .supported = source_color.supported + && destination_color.supported + && color_op.supported + && source_alpha.supported + && destination_alpha.supported + && alpha_op.supported, + }; +} + std::uint32_t rgba8_internal_format() noexcept { return gl_rgba8; diff --git a/src/renderer_gl/opengl_capabilities.h b/src/renderer_gl/opengl_capabilities.h index 1fac629..11a1cfa 100644 --- a/src/renderer_gl/opengl_capabilities.h +++ b/src/renderer_gl/opengl_capabilities.h @@ -46,6 +46,18 @@ struct OpenGlColorWriteMask { std::uint8_t a = 0; }; +struct OpenGlBlendState { + std::uint8_t enabled = 0; + std::uint32_t source_color_factor = 0; + std::uint32_t destination_color_factor = 0; + std::uint32_t color_equation = 0; + std::uint32_t source_alpha_factor = 0; + std::uint32_t destination_alpha_factor = 0; + std::uint32_t alpha_equation = 0; + OpenGlColorWriteMask color_write_mask; + bool supported = false; +}; + struct OpenGlDepthState { std::uint8_t test_enabled = 0; std::uint8_t write_enabled = 0; @@ -169,6 +181,8 @@ struct OpenGlWindowsWglContextConfig { pp::renderer::BlendFactor factor) noexcept; [[nodiscard]] OpenGlEnumMapping blend_equation_for_renderer_op( pp::renderer::BlendOp op) noexcept; +[[nodiscard]] OpenGlBlendState blend_state_for_renderer_blend_state( + pp::renderer::BlendState state) noexcept; [[nodiscard]] std::uint32_t rgba8_internal_format() noexcept; [[nodiscard]] std::uint32_t rgba16f_internal_format() noexcept; [[nodiscard]] std::uint32_t rgba32f_internal_format() noexcept; diff --git a/tests/renderer_gl/capabilities_tests.cpp b/tests/renderer_gl/capabilities_tests.cpp index d7c7b49..4fa6b3e 100644 --- a/tests/renderer_gl/capabilities_tests.cpp +++ b/tests/renderer_gl/capabilities_tests.cpp @@ -599,6 +599,68 @@ void maps_renderer_color_write_masks(pp::tests::Harness& h) PP_EXPECT(h, disabled_mask.a == 0U); } +void maps_renderer_blend_states(pp::tests::Harness& h) +{ + const auto disabled = pp::renderer::gl::blend_state_for_renderer_blend_state( + pp::renderer::BlendState {}); + const auto alpha_blend = pp::renderer::gl::blend_state_for_renderer_blend_state( + pp::renderer::BlendState { + .enabled = true, + .source_color = pp::renderer::BlendFactor::source_alpha, + .destination_color = pp::renderer::BlendFactor::one_minus_source_alpha, + .color_op = pp::renderer::BlendOp::add, + .source_alpha = pp::renderer::BlendFactor::one, + .destination_alpha = pp::renderer::BlendFactor::one_minus_destination_alpha, + .alpha_op = pp::renderer::BlendOp::reverse_subtract, + .write_r = true, + .write_g = false, + .write_b = true, + .write_a = false, + }); + const auto invalid_factor = pp::renderer::gl::blend_state_for_renderer_blend_state( + pp::renderer::BlendState { + .enabled = true, + .source_color = static_cast(255U), + }); + const auto invalid_op = pp::renderer::gl::blend_state_for_renderer_blend_state( + pp::renderer::BlendState { + .enabled = true, + .color_op = static_cast(255U), + }); + + PP_EXPECT(h, disabled.supported); + PP_EXPECT(h, disabled.enabled == 0U); + PP_EXPECT(h, disabled.source_color_factor == 1U); + PP_EXPECT(h, disabled.destination_color_factor == 0U); + PP_EXPECT(h, disabled.color_equation == 0x8006U); + PP_EXPECT(h, disabled.source_alpha_factor == 1U); + PP_EXPECT(h, disabled.destination_alpha_factor == 0U); + PP_EXPECT(h, disabled.alpha_equation == 0x8006U); + PP_EXPECT(h, disabled.color_write_mask.r == 1U); + PP_EXPECT(h, disabled.color_write_mask.g == 1U); + PP_EXPECT(h, disabled.color_write_mask.b == 1U); + PP_EXPECT(h, disabled.color_write_mask.a == 1U); + + PP_EXPECT(h, alpha_blend.supported); + PP_EXPECT(h, alpha_blend.enabled == 1U); + PP_EXPECT(h, alpha_blend.source_color_factor == 0x0302U); + PP_EXPECT(h, alpha_blend.destination_color_factor == 0x0303U); + PP_EXPECT(h, alpha_blend.color_equation == 0x8006U); + PP_EXPECT(h, alpha_blend.source_alpha_factor == 1U); + PP_EXPECT(h, alpha_blend.destination_alpha_factor == 0x0305U); + PP_EXPECT(h, alpha_blend.alpha_equation == 0x800BU); + PP_EXPECT(h, alpha_blend.color_write_mask.r == 1U); + PP_EXPECT(h, alpha_blend.color_write_mask.g == 0U); + PP_EXPECT(h, alpha_blend.color_write_mask.b == 1U); + PP_EXPECT(h, alpha_blend.color_write_mask.a == 0U); + + PP_EXPECT(h, !invalid_factor.supported); + PP_EXPECT(h, invalid_factor.enabled == 1U); + PP_EXPECT(h, invalid_factor.source_color_factor == 0U); + PP_EXPECT(h, !invalid_op.supported); + PP_EXPECT(h, invalid_op.color_equation == 0U); +} + void maps_renderer_depth_compare_tokens(pp::tests::Harness& h) { const auto never = pp::renderer::gl::compare_function_for_renderer_compare_op( @@ -803,6 +865,7 @@ int main() harness.run("maps_app_initialization_parameters", maps_app_initialization_parameters); harness.run("maps_renderer_blend_state_tokens", maps_renderer_blend_state_tokens); harness.run("maps_renderer_color_write_masks", maps_renderer_color_write_masks); + harness.run("maps_renderer_blend_states", maps_renderer_blend_states); harness.run("maps_renderer_depth_compare_tokens", maps_renderer_depth_compare_tokens); harness.run("maps_renderer_depth_states", maps_renderer_depth_states); harness.run("maps_windows_wgl_core_context_parameters", maps_windows_wgl_core_context_parameters);