diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 74a9eb0..37647ed 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -209,6 +209,11 @@ Known local toolchain state: defaults, viewport/clear-state queries, blend/depth/scissor state, color clear masks, active texture units, fallback 2D texture unbind targets, copy targets, and RGBA8 render-target formats. + Canvas resource setup also consumes backend-owned stroke-buffer + RGBA8/RGBA16F/RGBA32F formats, flood-fill texture upload format/type, + brush/stencil/mix sampler filters and wraps, and image channel-count texture + formats for cube-strip imports. Clamp-to-border sampler wrap is now part of + the backend capability catalog and test coverage. - `windows-msvc-vcpkg-headless` validates manifest install/configure/build/test for the current headless component matrix; see DEBT-0007 for remaining app and platform triplet migration. diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 2bf2011..96958db 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -753,6 +753,11 @@ Results: viewport/clear/blend/depth/scissor state, color clears, active texture units, fallback 2D texture unbinds, copy targets, and RGBA8 render-target formats through the renderer GL backend mapping. +- Canvas resource setup now routes stroke-buffer RGBA8/RGBA16F/RGBA32F + formats, flood-fill texture upload format/type, brush/stencil/mix sampler + filters and wraps, and cube-strip import channel formats through the renderer + GL backend mapping. The clamp-to-border sampler wrap is now cataloged and + tested in `pp_renderer_gl`. - Known remaining warnings: legacy project/vendor diagnostics, Visual Studio vcpkg-manifest warning, `LNK4099` missing libyuv PDBs, and `LNK4098` runtime library conflict from retained vendor binaries. diff --git a/src/canvas.cpp b/src/canvas.cpp index 6804bf5..acd1c5c 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -4,8 +4,10 @@ #include "app.h" #include "texture.h" #include "node_progress_bar.h" +#include "renderer_gl/opengl_capabilities.h" #include #include +#include #include #ifdef __APPLE__ @@ -15,6 +17,69 @@ void webgl_sync(); #endif +namespace { + +GLint current_canvas_stroke_internal_format() +{ + if (ShaderManager::ext_float32_linear) + return static_cast(pp::renderer::gl::rgba32f_internal_format()); + if (ShaderManager::ext_float16) + return static_cast(pp::renderer::gl::rgba16f_internal_format()); + return static_cast(pp::renderer::gl::rgba8_internal_format()); +} + +GLint rgba8_internal_format() +{ + return static_cast(pp::renderer::gl::rgba8_internal_format()); +} + +GLenum texture_2d_target() +{ + return static_cast(pp::renderer::gl::texture_2d_target()); +} + +GLenum rgba_pixel_format() +{ + return static_cast(pp::renderer::gl::rgba_pixel_format()); +} + +GLenum unsigned_byte_component_type() +{ + return static_cast(pp::renderer::gl::unsigned_byte_component_type()); +} + +GLint texture_filter_linear() +{ + return static_cast(pp::renderer::gl::linear_texture_filter()); +} + +GLint texture_filter_linear_mipmap_linear() +{ + return static_cast(pp::renderer::gl::linear_mipmap_linear_texture_filter()); +} + +GLint texture_filter_nearest() +{ + return static_cast(pp::renderer::gl::nearest_texture_filter()); +} + +GLint texture_wrap_repeat() +{ + return static_cast(pp::renderer::gl::repeat_texture_wrap()); +} + +GLint texture_wrap_clamp_to_border() +{ + return static_cast(pp::renderer::gl::clamp_to_border_texture_wrap()); +} + +pp::renderer::gl::OpenGlPixelFormat texture_format_for_image_channels(int channel_count) +{ + return pp::renderer::gl::texture_format_for_channel_count(static_cast(channel_count)); +} + +} + Canvas* Canvas::I; std::vector Canvas::modes[] = { @@ -1571,8 +1636,8 @@ void Canvas::FloodData::apply() App::I->render_task([&] { rtt.bindTexture(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(), - GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get()); + glTexSubImage2D(texture_2d_target(), 0, 0, 0, rtt.getWidth(), rtt.getHeight(), + rgba_pixel_format(), unsigned_byte_component_type(), rgb[plane].get()); rtt.unbindTexture(); }); layer->face(plane) = true; @@ -1588,23 +1653,11 @@ void Canvas::resize(int width, int height) m_size = { width, height }; for (int i = 0; i < 6; i++) { - if (ShaderManager::ext_float32_linear) - { - m_tmp[i].create(width, height, -1, GL_RGBA32F); - m_tmp_dual[i].create(width, height, -1, GL_RGBA32F); - } - else if (ShaderManager::ext_float16) - { - m_tmp[i].create(width, height, -1, GL_RGBA16F); - m_tmp_dual[i].create(width, height, -1, GL_RGBA16F); - } - else - { - m_tmp[i].create(width, height, -1, GL_RGBA8); - m_tmp_dual[i].create(width, height, -1, GL_RGBA8); - } - m_tex[i].create(width, height, GL_RGBA8); - m_tex2[i].create(width, height, GL_RGBA8); + const auto stroke_format = current_canvas_stroke_internal_format(); + m_tmp[i].create(width, height, -1, stroke_format); + m_tmp_dual[i].create(width, height, -1, stroke_format); + m_tex[i].create(width, height, rgba8_internal_format()); + m_tex2[i].create(width, height, rgba8_internal_format()); } for (auto& l : m_layers) l->resize(width, height); @@ -1640,35 +1693,23 @@ bool Canvas::create(int width, int height) m_size = { width, height }; for (int i = 0; i < 6; i++) { - if (ShaderManager::ext_float32_linear) - { - m_tmp[i].create(width, height, -1, GL_RGBA32F); - m_tmp_dual[i].create(width, height, -1, GL_RGBA32F); - } - else if (ShaderManager::ext_float16) - { - m_tmp[i].create(width, height, -1, GL_RGBA16F); - m_tmp_dual[i].create(width, height, -1, GL_RGBA16F); - } - else - { - m_tmp[i].create(width, height, -1, GL_RGBA8); - m_tmp_dual[i].create(width, height, -1, GL_RGBA8); - } - m_tex[i].create(width, height, GL_RGBA8); - m_tex2[i].create(width, height, GL_RGBA8); + const auto stroke_format = current_canvas_stroke_internal_format(); + m_tmp[i].create(width, height, -1, stroke_format); + m_tmp_dual[i].create(width, height, -1, stroke_format); + m_tex[i].create(width, height, rgba8_internal_format()); + m_tex2[i].create(width, height, rgba8_internal_format()); } #if defined(__GLES__) m_sampler_brush.create(); #else - m_sampler_brush.create(GL_LINEAR, GL_CLAMP_TO_BORDER); + m_sampler_brush.create(texture_filter_linear(), texture_wrap_clamp_to_border()); #endif - m_sampler.create(GL_LINEAR); - m_sampler_nearest.create(GL_NEAREST); - m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); + m_sampler.create(texture_filter_linear()); + m_sampler_nearest.create(texture_filter_nearest()); + m_sampler_brush.set_filter(texture_filter_linear_mipmap_linear(), texture_filter_linear()); m_sampler_brush.set_border({ 1, 1, 1, 1 }); - m_sampler_stencil.create(GL_LINEAR, GL_REPEAT); - m_sampler_mix.create(GL_NEAREST, GL_REPEAT); + m_sampler_stencil.create(texture_filter_linear(), texture_wrap_repeat()); + m_sampler_mix.create(texture_filter_nearest(), texture_wrap_repeat()); m_sampler_linear.create(); m_plane.create<1>(1, 1); m_plane_brush.create<1>(1, 1); @@ -1754,9 +1795,12 @@ void Canvas::import_equirectangular_thread(std::string file_path, std::shared_pt { Texture2D tex; static const GLint indices[] = { 5, 0, 4, 1, 2, 3 }; - static const GLint formats[] = { GL_RED, GL_RG, GL_RGB, GL_RGBA }; - static const GLint iformats[] = { GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 }; - tex.create(img.width, img.width, iformats[img.comp - 1], formats[img.comp - 1]); + const auto texture_format = texture_format_for_image_channels(img.comp); + tex.create( + img.width, + img.width, + static_cast(texture_format.internal_format), + static_cast(texture_format.pixel_format)); int stride = img.width * img.width * img.comp; Plane plane; plane.create<1>(2, 2); diff --git a/src/renderer_gl/opengl_capabilities.cpp b/src/renderer_gl/opengl_capabilities.cpp index 9c44fcf..e364347 100644 --- a/src/renderer_gl/opengl_capabilities.cpp +++ b/src/renderer_gl/opengl_capabilities.cpp @@ -105,6 +105,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_clamp_to_border = 0x812DU; constexpr std::uint32_t gl_clamp_to_edge = 0x812FU; constexpr std::uint32_t gl_texture0 = 0x84C0U; constexpr std::uint32_t gl_pixel_pack_buffer = 0x88EBU; @@ -652,6 +653,11 @@ std::uint32_t clamp_to_edge_texture_wrap() noexcept return gl_clamp_to_edge; } +std::uint32_t clamp_to_border_texture_wrap() noexcept +{ + return gl_clamp_to_border; +} + 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 17b072c..2aa871c 100644 --- a/src/renderer_gl/opengl_capabilities.h +++ b/src/renderer_gl/opengl_capabilities.h @@ -127,6 +127,7 @@ struct OpenGlReadbackFormat { [[nodiscard]] std::uint32_t nearest_texture_filter() noexcept; [[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]] 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 f670d47..f3eb7c8 100644 --- a/tests/renderer_gl/capabilities_tests.cpp +++ b/tests/renderer_gl/capabilities_tests.cpp @@ -359,6 +359,7 @@ void maps_app_initialization_parameters(pp::tests::Harness& h) PP_EXPECT(h, pp::renderer::gl::nearest_texture_filter() == 0x2600U); PP_EXPECT(h, pp::renderer::gl::repeat_texture_wrap() == 0x2901U); PP_EXPECT(h, pp::renderer::gl::clamp_to_edge_texture_wrap() == 0x812FU); + PP_EXPECT(h, pp::renderer::gl::clamp_to_border_texture_wrap() == 0x812DU); PP_EXPECT(h, pp::renderer::gl::active_texture_unit(0U) == 0x84C0U); PP_EXPECT(h, pp::renderer::gl::active_texture_unit(4U) == 0x84C4U); }