diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 7b359a8..b738888 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,13 @@ agent or engineer to remove them without reconstructing context from chat. ## Recent Reductions +- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` per-layer + blend composite now routes merge-RTT unbind, shader setup, optional + destination-copy feedback, draw, and cleanup ordering through + `execute_legacy_canvas_draw_merge_layer_blend(...)`; layer iteration, + temporary-stroke branch selection, framebuffer copies, sampler/texture + object callbacks, and final merged-plane ownership remain retained in + `Canvas`. - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` erase live temporary-stroke composite now routes retained setup, sampler bind, texture bind, draw, and texture unbind ordering through diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 3056a15..0111b9f 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -3145,6 +3145,11 @@ Results: `execute_legacy_canvas_stroke_temporary_composite(...)`, leaving only the concrete GL object callbacks and broader final composite ownership in the legacy Canvas path. +- `Canvas::draw_merge()` per-layer blend composite now routes merge-RTT + unbind, shader setup, optional destination-copy feedback, draw, and cleanup + ordering through `execute_legacy_canvas_draw_merge_layer_blend(...)`, while + temporary-stroke branch selection, framebuffer copies, and final merged-plane + ownership remain in the legacy Canvas path. - `NodeStrokePreview::draw_stroke_immediate()` now shares `execute_legacy_node_stroke_preview_pass_sequence(...)` for dual-pass/background/main-pass/final-composite/copy-back ordering, while the diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 83f18af..c41bb4a 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -509,6 +509,15 @@ Done Checks: Progress Notes: +- 2026-06-13: `Canvas::draw_merge()` per-layer blend composite now routes + merge-RTT unbind, shader setup, optional destination-copy feedback, draw, + and cleanup ordering through + `execute_legacy_canvas_draw_merge_layer_blend(...)`; temporary-stroke + branch selection, layer iteration, and final merged-plane redraw ownership + remain local to `Canvas`. Next slice should target the remaining end-of-plane + merged-texture copy/grid/final-redraw seam or another similarly narrow final + composite boundary without reopening landed temporary-composite or + per-layer blend helpers. - 2026-06-13: `Canvas::draw_merge()` erase live temporary-stroke composite now routes retained setup, sampler bind, texture bind, draw, and texture unbind ordering through `execute_legacy_canvas_stroke_temporary_composite(...)`; diff --git a/src/canvas.cpp b/src/canvas.cpp index cac217a..f3355f9 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1535,47 +1535,49 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI if (use_blend) { - m_merge_rtt.unbindFramebuffer(); - } - - // draw the blended - if (use_blend) - { - m_sampler.bind(0); - m_sampler.bind(2); - - pp::panopainter::setup_legacy_canvas_draw_merge_texture_blend_shader( - pp::panopainter::LegacyCanvasDrawMergeTextureBlendUniforms { - .mvp = ortho, - .texture_slot = 0, - .destination_texture_slot = 2, - .use_destination_texture = copy_blend_destination, - .blend_mode = m_layers[layer_index]->m_blend_mode, - .alpha = 1.f, + pp::panopainter::execute_legacy_canvas_draw_merge_layer_blend( + pp::panopainter::LegacyCanvasDrawMergeLayerBlendUniforms { + .shader = { + .mvp = ortho, + .texture_slot = 0, + .destination_texture_slot = 2, + .use_destination_texture = copy_blend_destination, + .blend_mode = m_layers[layer_index]->m_blend_mode, + .alpha = 1.f, + }, + .copy_destination = copy_blend_destination, + }, + pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution { + .unbind_merge_framebuffer = [&] { + m_merge_rtt.unbindFramebuffer(); + }, + .bind_samplers = [&] { + m_sampler.bind(0); + m_sampler.bind(2); + }, + .bind_merge_texture = [&] { + set_active_texture_unit(0); + m_merge_rtt.bindTexture(); + }, + .bind_destination_texture = [&] { + set_active_texture_unit(2); + m_merge_tex.bind(); + }, + .copy_destination_framebuffer = [&] { + copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height); + }, + .draw = [&] { + m_plane.draw_fill(); + }, + .unbind_destination_texture = [&] { + set_active_texture_unit(2); + m_merge_tex.unbind(); + }, + .unbind_merge_texture = [&] { + set_active_texture_unit(0); + m_merge_rtt.unbindTexture(); + }, }); - if (copy_blend_destination) - { - m_sampler.bind(2); - } - - set_active_texture_unit(0); - m_merge_rtt.bindTexture(); - if (copy_blend_destination) - { - set_active_texture_unit(2); - m_merge_tex.bind(); - copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height); - } - - m_plane.draw_fill(); - - if (copy_blend_destination) - { - set_active_texture_unit(2); - m_merge_tex.unbind(); - } - set_active_texture_unit(0); - m_merge_rtt.unbindTexture(); } } diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index 633bfca..045378d 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -64,6 +64,22 @@ struct LegacyCanvasDrawMergeShaderExecution { std::function set_mat4; }; +struct LegacyCanvasDrawMergeLayerBlendUniforms { + LegacyCanvasDrawMergeTextureBlendUniforms shader; + bool copy_destination = false; +}; + +struct LegacyCanvasDrawMergeLayerBlendExecution { + std::function unbind_merge_framebuffer; + std::function bind_samplers; + std::function bind_merge_texture; + std::function bind_destination_texture; + std::function copy_destination_framebuffer; + std::function draw; + std::function unbind_destination_texture; + std::function unbind_merge_texture; +}; + [[nodiscard]] inline LegacyCanvasDrawMergeShaderExecution legacy_shader_manager_draw_merge_execution() noexcept { return { @@ -218,4 +234,27 @@ inline void setup_legacy_canvas_draw_merge_texture_colorize_shader( setup_legacy_canvas_draw_merge_texture_colorize_shader(uniforms, legacy_shader_manager_draw_merge_execution()); } +inline void execute_legacy_canvas_draw_merge_layer_blend( + const LegacyCanvasDrawMergeLayerBlendUniforms& uniforms, + const LegacyCanvasDrawMergeLayerBlendExecution& execution) +{ + execution.unbind_merge_framebuffer(); + execution.bind_samplers(); + setup_legacy_canvas_draw_merge_texture_blend_shader(uniforms.shader); + execution.bind_merge_texture(); + + if (uniforms.copy_destination) { + execution.bind_destination_texture(); + execution.copy_destination_framebuffer(); + } + + execution.draw(); + + if (uniforms.copy_destination) { + execution.unbind_destination_texture(); + } + + execution.unbind_merge_texture(); +} + } // namespace pp::panopainter