diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 59c6db7..e904fd4 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -355,10 +355,13 @@ Known local toolchain state: atlas texture formats, text mesh buffer targets, attribute component and normalization tokens, draw primitive/index type, upload usage, and active texture unit selection also consume the backend mapping. Text mesh - buffer/VAO creation, deferred index/vertex uploads, and indexed draw calls - now consume tested `pp_renderer_gl` mesh dispatch contracts too. Canvas undo/redo - dirty-region texture updates and readbacks also consume the backend-owned 2D - texture target, RGBA pixel format, and unsigned-byte component mapping. + buffer/VAO creation, deferred index/vertex uploads, indexed draw calls, and + draw-time texture-unit activation now consume tested `pp_renderer_gl` + dispatch contracts too. Canvas undo/redo dirty-region texture updates and + readbacks also consume the backend-owned 2D texture target, RGBA pixel + format, and unsigned-byte component mapping; canvas stroke commit, thumbnail, + and object-draw history paths now consume tested capability-state query + dispatch for saved blend state. `NodeViewport` preview rendering also consumes backend-owned viewport query, clear-color query, color-buffer clear mask, and blend-state tokens. `NodeImageTexture` preview drawing also consumes backend-owned fallback 2D @@ -373,8 +376,8 @@ Known local toolchain state: paths also consume backend-owned blend-state tokens. Canvas layer cube/equirect generation, clear, restore, and snapshot paths also consume backend-owned cube/2D texture targets, active texture units, - blend/clear state, viewport execution, target-aware framebuffer-to-texture - copies, and RGBA8 read/write pixel mapping. + cube texture binding, blend/clear state, viewport execution, target-aware + framebuffer-to-texture copies, and RGBA8 read/write pixel mapping. `NodePanelGrid` heightmap preview and lightmap baking also consume backend-owned texture readback formats, sampler filters, depth/blend state, depth clears, viewport queries, color-mask booleans, active texture units, @@ -666,12 +669,12 @@ Known local toolchain state: color/depth attachment, status-check, and binding-restore dispatch consumed by retained `RTT::create`/`RTT::destroy`, tested RTT render-target clear, masked color clear with color-write-mask restore, and texture-bind dispatch, - tested active-texture dispatch consumed by retained Canvas, NodeCanvas, and - NodeStrokePreview texture-unit switches, + tested active-texture dispatch consumed by retained Canvas, Font, NodeCanvas, + and NodeStrokePreview texture-unit switches, tested viewport/scissor/capability dispatch consumed by retained Canvas, NodeCanvas, NodeStrokePreview, and HMD render-state paths, - tested capability-state query dispatch consumed by retained `NodeCanvas`, - `CanvasMode`, and `NodePanelGrid` draw-state restore paths, + tested capability-state query dispatch consumed by retained `Canvas`, + `NodeCanvas`, `CanvasMode`, and `NodePanelGrid` draw-state restore paths, tested viewport query, clear-color query, and clear-color restore dispatch consumed by retained `Canvas`, `CanvasLayer`, `NodeCanvas`, and `NodeStrokePreview` draw-state paths, @@ -681,7 +684,8 @@ Known local toolchain state: tested pixel-buffer allocation/readback/map/unmap/delete dispatch consumed by retained `PBO` recording readbacks, tested framebuffer-to-texture copy dispatch consumed by retained canvas/UI paint paths and CanvasLayer - cube-face generation, tested framebuffer bind/restore dispatch consumed by + cube-face generation, tested cube texture bind dispatch consumed by + CanvasLayer equirect export, tested framebuffer bind/restore dispatch consumed by retained `RTT` render-target pass entry and exit paths, tested depth renderbuffer allocation/delete and framebuffer depth attach/detach dispatch consumed by retained RTT and canvas object-drawing helpers, diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 7594eb4..4eb6c53 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -16,6 +16,18 @@ agent or engineer to remove them without reconstructing context from chat. - Do not close an entry until the removal condition is met and validated. - Prefer deleting shortcuts over expanding this log. +## Recent Reductions + +- 2026-06-04: DEBT-0036 was narrowed again. Canvas stroke commit, + thumbnail, and object-draw history paths now query saved blend state through + tested `pp_renderer_gl` capability-state dispatch; CanvasLayer equirect + export now binds cube textures through tested `pp_renderer_gl` dispatch; and + `Font` text drawing now activates texture units through tested + `pp_renderer_gl` dispatch. The debt remains open for live stroke + rasterization, dual-brush compositing, pattern feedback math, thumbnail layer + compositing, brush-preview compositing, and retained `ShaderManager::ext_*` + compatibility fields. + ## Open Debt | ID | Status | Owner | Item | Reason | Validation | Removal Condition | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 747b256..11a4816 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -1078,13 +1078,15 @@ capability detection also live in `pp_renderer_gl`. Legacy font atlas texture formats, text mesh buffer targets, attribute component/normalization, draw primitive/index type, upload usage, and active texture unit selection also delegate to `pp_renderer_gl`; text mesh buffer/VAO creation, deferred index -and vertex uploads, and indexed draw calls now execute through the same tested -mesh dispatch contracts used by `Shape`, leaving the retained `Font` utility -with thin GL adapter functions for mesh operations. +and vertex uploads, indexed draw calls, and text draw texture-unit activation +now execute through the same tested dispatch contracts used by `Shape`, leaving +the retained `Font` utility with thin GL adapter functions for mesh operations. Canvas undo/redo dirty-region texture updates and readbacks now also execute through retained `RTT` helpers backed by `pp_renderer_gl`, including 2D texture target, dirty-region offsets, RGBA pixel format, and unsigned-byte component -type mapping. +type mapping. Canvas stroke commit, thumbnail generation, and object-draw +history paths now query saved blend state through the same tested capability +state dispatch before restoring it. `NodeViewport` preview rendering now also delegates viewport query, clear-color query, color-buffer clear mask, viewport execution, color clear, clear-color restore, and blend-state execution through the shared @@ -1101,8 +1103,8 @@ Simple UI text, text-input, border, scroll, and animation timeline draw paths now also execute blend-state changes through the shared UI GL adapter. Canvas layer cube/equirect generation, clear, restore, and snapshot paths now also delegate cube/2D texture targets, active texture units, blend/clear state, -viewport execution, target-aware framebuffer-to-texture copies, and RGBA8 -read/write pixel mapping to `pp_renderer_gl`. +viewport execution, target-aware framebuffer-to-texture copies, cube texture +binding, and RGBA8 read/write pixel mapping to `pp_renderer_gl`. `NodePanelGrid` heightmap preview and lightmap baking now delegate texture readback formats, sampler filters, depth/blend state, depth clears, viewport queries, color-mask booleans, active texture units, and float render-target diff --git a/src/canvas.cpp b/src/canvas.cpp index 9692efc..f9e577a 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -184,6 +184,11 @@ void disable_opengl_state(std::uint32_t state) noexcept glDisable(static_cast(state)); } +std::uint8_t query_opengl_capability(std::uint32_t state) noexcept +{ + return static_cast(glIsEnabled(static_cast(state))); +} + void set_opengl_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept { glViewport(static_cast(x), static_cast(y), static_cast(width), static_cast(height)); @@ -297,6 +302,19 @@ void apply_canvas_capability(std::uint32_t state, bool enabled) LOG("Canvas capability dispatch failed because: %s", status.message); } +bool query_canvas_capability(std::uint32_t state) +{ + const auto result = pp::renderer::gl::query_opengl_capability_state( + state, + pp::renderer::gl::OpenGlCapabilityStateQueryDispatch { + .is_enabled = query_opengl_capability, + }); + if (!result.ok()) { + LOG("Canvas capability query dispatch failed because: %s", result.status().message); + } + return result.value(); +} + void gen_opengl_renderbuffers(std::uint32_t count, std::uint32_t* ids) noexcept { glGenRenderbuffers(static_cast(count), reinterpret_cast(ids)); @@ -1121,7 +1139,7 @@ void Canvas::stroke_commit() // save viewport and clear color states const auto vp = query_canvas_viewport(); const auto cc = query_canvas_clear_color(); - auto blend = glIsEnabled(blend_state()); + auto blend = query_canvas_capability(blend_state()); // allocate action to add to history auto action = new ActionStroke; @@ -2992,7 +3010,7 @@ Image Canvas::thumbnail_generate(int w, int h) // save viewport and clear color states const auto vp = query_canvas_viewport(); const auto cc = query_canvas_clear_color(); - auto blend = glIsEnabled(blend_state()); + auto blend = query_canvas_capability(blend_state()); // prepare common states apply_canvas_viewport(0, 0, w, h); @@ -3125,7 +3143,7 @@ void Canvas::draw_objects_direct(std::function(texture_unit)); } +void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept +{ + glBindTexture(static_cast(target), static_cast(texture)); +} + void set_opengl_clear_color(float r, float g, float b, float a) noexcept { glClearColor(r, g, b, a); @@ -108,6 +113,17 @@ void set_layer_active_texture_unit(std::uint32_t unit_index) LOG("Layer active texture dispatch failed because: %s", status.message); } +void bind_layer_texture_cube(std::uint32_t texture_id) +{ + const auto status = pp::renderer::gl::bind_opengl_texture_cube( + texture_id, + pp::renderer::gl::OpenGlTexture2DBindDispatch { + .bind_texture = bind_opengl_texture, + }); + if (!status.ok()) + LOG("Layer cube texture bind dispatch failed because: %s", status.message); +} + void copy_layer_framebuffer_to_texture( std::uint32_t texture_target, std::int32_t destination_x, @@ -248,7 +264,7 @@ Texture2D Layer::gen_equirect(glm::ivec2 size /*= { 0, 0 }*/) apply_layer_viewport(0, 0, latlong.getWidth(), latlong.getHeight()); set_layer_active_texture_unit(0U); - glBindTexture(pp::renderer::gl::texture_cube_map_target(), cube.m_cubetex_id); + bind_layer_texture_cube(cube.m_cubetex_id); ShaderManager::use(kShader::Equirect); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); @@ -290,7 +306,7 @@ PBO Layer::gen_equirect_pbo(glm::ivec2 size /*= { 0, 0 }*/) apply_layer_viewport(0, 0, latlong.getWidth(), latlong.getHeight()); set_layer_active_texture_unit(0U); - glBindTexture(pp::renderer::gl::texture_cube_map_target(), cube.m_cubetex_id); + bind_layer_texture_cube(cube.m_cubetex_id); ShaderManager::use(kShader::Equirect); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); diff --git a/src/font.cpp b/src/font.cpp index 18ef35d..17393e8 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -23,11 +23,6 @@ namespace { return static_cast(pp::renderer::gl::texture_format_for_channel_count(1U).pixel_format); } -[[nodiscard]] GLenum texture_unit(std::uint32_t unit_index) noexcept -{ - return static_cast(pp::renderer::gl::active_texture_unit(unit_index)); -} - void gen_buffers_adapter(std::uint32_t count, std::uint32_t* ids) noexcept { glGenBuffers(static_cast(count), ids); @@ -97,6 +92,22 @@ void draw_arrays_adapter(std::uint32_t mode, std::int32_t first, std::int32_t co glDrawArrays(static_cast(mode), static_cast(first), static_cast(count)); } +void activate_texture_adapter(std::uint32_t texture_unit) noexcept +{ + glActiveTexture(static_cast(texture_unit)); +} + +void activate_text_texture_unit(std::uint32_t unit_index) +{ + const auto status = pp::renderer::gl::activate_opengl_texture_unit( + unit_index, + pp::renderer::gl::OpenGlActiveTextureDispatch { + .active_texture = activate_texture_adapter, + }); + if (!status.ok()) + LOG("Text active texture dispatch failed because: %s", status.message); +} + [[nodiscard]] std::span text_mesh_vertex_attributes() noexcept { static const std::array attributes { @@ -431,7 +442,7 @@ void TextMesh::draw() auto& f = FontManager::get(font, size, weight, italic); if (f.font_tex.ready()) { - glActiveTexture(texture_unit(0U)); + activate_text_texture_unit(0U); f.font_tex.bind(); FontManager::m_sampler.bind(0);