From 647dd81992ea3806bbb6e6c1650649ea2946a80b Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 2 Jun 2026 18:28:25 +0200 Subject: [PATCH] Map renderer sampler tokens to OpenGL --- docs/modernization/build-inventory.md | 4 ++- docs/modernization/roadmap.md | 4 ++- src/renderer_gl/opengl_capabilities.cpp | 29 ++++++++++++++++++ src/renderer_gl/opengl_capabilities.h | 4 +++ tests/renderer_gl/capabilities_tests.cpp | 38 ++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index d7f237e..70c6860 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -207,7 +207,9 @@ Known local toolchain state: the legacy mesh draw path, plus the PanoPainter cube-face to OpenGL texture-target mapping used by `TextureCube`. It also owns and validates sampler wrap S/T/R, min/mag filter, and desktop - border-color parameter mapping used by legacy `Sampler`. The PanoPainter + border-color parameter mapping used by legacy `Sampler`, plus renderer API + sampler filter/address-mode to OpenGL token mapping including mirrored-repeat. + The PanoPainter shader attribute binding catalog, shader stage tokens, compile/link status queries, active-uniform count query, and matrix-uniform transpose token used by legacy `Shader` creation also live here. Renderer API blend factor/op to diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index d74151f..cd840be 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -464,7 +464,9 @@ OpenGL texture-target mapping used by `TextureCube` also lives in framebuffer diagnostic, framebuffer blit, render-target setup, clear-state, 2D/cube texture setup, mesh draw-mode, and cube-face texture-target interpretation to that backend library. Sampler wrap, min/mag filter, and desktop border-color parameter -mapping for legacy `Sampler` also lives in `pp_renderer_gl`. The PanoPainter shader attribute +mapping for legacy `Sampler` also lives in `pp_renderer_gl`. Renderer API sampler +filter/address-mode to OpenGL token mapping, including mirrored-repeat, is also +tested there. The PanoPainter shader attribute binding catalog, shader stage tokens, compile/link status queries, active-uniform 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 diff --git a/src/renderer_gl/opengl_capabilities.cpp b/src/renderer_gl/opengl_capabilities.cpp index 915e417..43b0239 100644 --- a/src/renderer_gl/opengl_capabilities.cpp +++ b/src/renderer_gl/opengl_capabilities.cpp @@ -124,6 +124,7 @@ constexpr std::uint32_t gl_texture_wrap_t = 0x2803U; constexpr std::uint32_t gl_texture_wrap_r = 0x8072U; constexpr std::uint32_t gl_texture_border_color = 0x1004U; constexpr std::uint32_t gl_repeat = 0x2901U; +constexpr std::uint32_t gl_mirrored_repeat = 0x8370U; constexpr std::uint32_t gl_clamp_to_border = 0x812DU; constexpr std::uint32_t gl_clamp_to_edge = 0x812FU; constexpr std::uint32_t gl_texture0 = 0x84C0U; @@ -820,6 +821,34 @@ std::uint32_t clamp_to_border_texture_wrap() noexcept return gl_clamp_to_border; } +OpenGlEnumMapping sampler_filter_for_renderer_filter(pp::renderer::SamplerFilter filter) noexcept +{ + switch (filter) { + case pp::renderer::SamplerFilter::nearest: + return OpenGlEnumMapping { .value = gl_nearest, .supported = true }; + case pp::renderer::SamplerFilter::linear: + return OpenGlEnumMapping { .value = gl_linear, .supported = true }; + default: + return OpenGlEnumMapping {}; + } +} + +OpenGlEnumMapping sampler_address_mode_for_renderer_mode(pp::renderer::SamplerAddressMode mode) noexcept +{ + switch (mode) { + case pp::renderer::SamplerAddressMode::clamp_to_edge: + return OpenGlEnumMapping { .value = gl_clamp_to_edge, .supported = true }; + case pp::renderer::SamplerAddressMode::repeat: + return OpenGlEnumMapping { .value = gl_repeat, .supported = true }; + case pp::renderer::SamplerAddressMode::mirrored_repeat: + return OpenGlEnumMapping { .value = gl_mirrored_repeat, .supported = true }; + case pp::renderer::SamplerAddressMode::clamp_to_border: + return OpenGlEnumMapping { .value = gl_clamp_to_border, .supported = true }; + default: + return OpenGlEnumMapping {}; + } +} + std::uint32_t active_texture_unit(std::uint32_t unit_index) noexcept { return gl_texture0 + unit_index; diff --git a/src/renderer_gl/opengl_capabilities.h b/src/renderer_gl/opengl_capabilities.h index b844637..7ed704f 100644 --- a/src/renderer_gl/opengl_capabilities.h +++ b/src/renderer_gl/opengl_capabilities.h @@ -159,6 +159,10 @@ struct OpenGlWindowsWglContextConfig { [[nodiscard]] std::uint32_t repeat_texture_wrap() noexcept; [[nodiscard]] std::uint32_t clamp_to_edge_texture_wrap() noexcept; [[nodiscard]] std::uint32_t clamp_to_border_texture_wrap() noexcept; +[[nodiscard]] OpenGlEnumMapping sampler_filter_for_renderer_filter( + pp::renderer::SamplerFilter filter) noexcept; +[[nodiscard]] OpenGlEnumMapping sampler_address_mode_for_renderer_mode( + pp::renderer::SamplerAddressMode mode) noexcept; [[nodiscard]] std::uint32_t active_texture_unit(std::uint32_t unit_index) noexcept; [[nodiscard]] std::uint32_t texture_cube_map_target() noexcept; [[nodiscard]] std::uint32_t cube_map_allocation_face_texture_target(std::uint32_t face_index) noexcept; diff --git a/tests/renderer_gl/capabilities_tests.cpp b/tests/renderer_gl/capabilities_tests.cpp index 8c0f2df..27f4f38 100644 --- a/tests/renderer_gl/capabilities_tests.cpp +++ b/tests/renderer_gl/capabilities_tests.cpp @@ -370,6 +370,43 @@ void maps_sampler_parameters(pp::tests::Harness& h) PP_EXPECT(h, pp::renderer::gl::sampler_border_color_parameter_name() == 0x1004U); } +void maps_renderer_sampler_tokens(pp::tests::Harness& h) +{ + const auto nearest = pp::renderer::gl::sampler_filter_for_renderer_filter( + pp::renderer::SamplerFilter::nearest); + const auto linear = pp::renderer::gl::sampler_filter_for_renderer_filter( + pp::renderer::SamplerFilter::linear); + const auto invalid_filter = pp::renderer::gl::sampler_filter_for_renderer_filter( + static_cast(255U)); + const auto clamp_to_edge = pp::renderer::gl::sampler_address_mode_for_renderer_mode( + pp::renderer::SamplerAddressMode::clamp_to_edge); + const auto repeat = pp::renderer::gl::sampler_address_mode_for_renderer_mode( + pp::renderer::SamplerAddressMode::repeat); + const auto mirrored_repeat = pp::renderer::gl::sampler_address_mode_for_renderer_mode( + pp::renderer::SamplerAddressMode::mirrored_repeat); + const auto clamp_to_border = pp::renderer::gl::sampler_address_mode_for_renderer_mode( + pp::renderer::SamplerAddressMode::clamp_to_border); + const auto invalid_mode = pp::renderer::gl::sampler_address_mode_for_renderer_mode( + static_cast(255U)); + + PP_EXPECT(h, nearest.supported); + PP_EXPECT(h, nearest.value == 0x2600U); + PP_EXPECT(h, linear.supported); + PP_EXPECT(h, linear.value == 0x2601U); + PP_EXPECT(h, !invalid_filter.supported); + PP_EXPECT(h, invalid_filter.value == 0U); + PP_EXPECT(h, clamp_to_edge.supported); + PP_EXPECT(h, clamp_to_edge.value == 0x812FU); + PP_EXPECT(h, repeat.supported); + PP_EXPECT(h, repeat.value == 0x2901U); + PP_EXPECT(h, mirrored_repeat.supported); + PP_EXPECT(h, mirrored_repeat.value == 0x8370U); + PP_EXPECT(h, clamp_to_border.supported); + PP_EXPECT(h, clamp_to_border.value == 0x812DU); + PP_EXPECT(h, !invalid_mode.supported); + PP_EXPECT(h, invalid_mode.value == 0U); +} + void exposes_shader_attribute_binding_catalog(pp::tests::Harness& h) { const auto bindings = pp::renderer::gl::panopainter_shader_attribute_bindings(); @@ -654,6 +691,7 @@ int main() harness.run("maps_panopainter_cube_faces_to_texture_targets", maps_panopainter_cube_faces_to_texture_targets); harness.run("exposes_default_render_target_texture_parameters", exposes_default_render_target_texture_parameters); harness.run("maps_sampler_parameters", maps_sampler_parameters); + harness.run("maps_renderer_sampler_tokens", maps_renderer_sampler_tokens); harness.run("exposes_shader_attribute_binding_catalog", exposes_shader_attribute_binding_catalog); harness.run("maps_app_initialization_parameters", maps_app_initialization_parameters); harness.run("maps_renderer_blend_state_tokens", maps_renderer_blend_state_tokens);