From e8fdd96d376774a6fa8516ff8316a75a9e627fbb Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 13 Jun 2026 22:47:28 +0200 Subject: [PATCH] Extract draw merge erase branch helper --- docs/modernization/debt.md | 5 ++++ docs/modernization/tasks.md | 34 ++++++++++++++++++++++- src/canvas.cpp | 17 ++++++------ src/legacy_canvas_draw_merge_services.h | 22 +++++++++++++++ tests/paint_renderer/compositor_tests.cpp | 26 +++++++++++++++++ 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 48e6fff..5d2895e 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -193,6 +193,11 @@ agent or engineer to remove them without reconstructing context from chat. the remaining temporary erase and paint callback bundle through `execute_legacy_canvas_draw_merge_temporary_composite(...)`; branch selection remains in `Canvas`. +- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` temporary + erase branch execution now routes through + `make_legacy_canvas_draw_merge_temporary_erase_composite(...)`; the live + path still owns the concrete layer RTT, mixer RTT, sampler, and plane + callbacks. - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` now routes the layer-composite shell through a local wrapper around `execute_legacy_canvas_draw_merge_layer_composite(...)`; the final branch diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index b9a5000..14ebc0c 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -1327,10 +1327,11 @@ Completed Task Log: ### STR-016 - Extract Draw Merge Layer Composite Execution -Status: Ready +Status: Blocked Score: +2 renderer boundary and OpenGL parity Debt: `DEBT-0036` Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp` +Blocked By: Helper API shape mismatch in the current per-layer composite extraction attempt Goal: @@ -1366,6 +1367,37 @@ ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_composito | --- | --- | ---: | --- | --- | | 2026-06-13 | STR-016 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `pending` | +### STR-017 - Extract Draw Merge Temporary Erase Composite Branch + +Status: Done +Score: +1 renderer boundary and OpenGL parity +Debt: `DEBT-0036` +Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp` + +Goal: + +Move the remaining temporary erase branch inside `Canvas::draw_merge()` into a +retained helper so the callsite keeps only branch selection and concrete GL +object wiring. + +Done Checks: + +- `Canvas::draw_merge()` no longer builds the temporary erase composite inline. +- Regression coverage proves the extracted helper preserves erase-branch order. +- `docs/modernization/debt.md` records the reduced draw-merge erase surface. + +Validation: + +```powershell +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure +``` + +### Completed Task Log + +| Date | Task | Score | Validation | Commit | +| --- | --- | ---: | --- | --- | +| 2026-06-13 | STR-017 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `pending` | + ### STR-012 - Extract Preview Final Composite Orchestration Status: Done diff --git a/src/canvas.cpp b/src/canvas.cpp index 43c70c3..9de375b 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1439,10 +1439,10 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index, use_blend, pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution { - .execute_temporary_erase = [&] { + .execute_temporary_erase = [&] { pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( - pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution { - .setup = [&] { + pp::panopainter::make_legacy_canvas_draw_merge_temporary_erase_composite( + [&] { //ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_box) / zoom); //ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index]->m_alpha_locked); pp::panopainter::setup_legacy_stroke_erase_shader( @@ -1455,12 +1455,12 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI .mask_enabled = m_smask_active, }); }, - .bind_samplers = [&] { + [&] { m_sampler.bind(0); m_sampler.bind(1); m_sampler.bind(2); }, - .bind_textures = [&] { + [&] { set_active_texture_unit(0); m_layers[layer_index]->rtt(plane_index).bindTexture(); set_active_texture_unit(1); @@ -1468,17 +1468,16 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI set_active_texture_unit(2); m_smask.rtt(plane_index).bindTexture(); }, - .draw = [&] { + [&] { m_plane.draw_fill(); }, - .unbind_textures = [&] { + [&] { m_smask.rtt(plane_index).unbindTexture(); set_active_texture_unit(1); m_tmp[plane_index].unbindTexture(); set_active_texture_unit(0); m_layers[layer_index]->rtt(plane_index).unbindTexture(); - }, - }); + })); }, .execute_temporary_paint = [&] { const auto stroke_material = canvas_stroke_material_plan(*b, false); diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index fe216d1..a21a5ec 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -102,6 +102,28 @@ struct LegacyCanvasDrawMergeTemporaryCompositeExecution { std::function unbind_textures; }; +template < + typename Setup, + typename BindSamplers, + typename BindTextures, + typename Draw, + typename UnbindTextures> +[[nodiscard]] inline LegacyCanvasDrawMergeTemporaryCompositeExecution make_legacy_canvas_draw_merge_temporary_erase_composite( + Setup&& setup, + BindSamplers&& bind_samplers, + BindTextures&& bind_textures, + Draw&& draw, + UnbindTextures&& unbind_textures) +{ + return LegacyCanvasDrawMergeTemporaryCompositeExecution { + .setup = std::forward(setup), + .bind_samplers = std::forward(bind_samplers), + .bind_textures = std::forward(bind_textures), + .draw = std::forward(draw), + .unbind_textures = std::forward(unbind_textures), + }; +} + struct LegacyCanvasDrawMergePlaneSetupUniforms { LegacyCanvasDrawMergeCheckerboardUniforms checkerboard; bool use_blend = false; diff --git a/tests/paint_renderer/compositor_tests.cpp b/tests/paint_renderer/compositor_tests.cpp index 6ab2448..a91cd10 100644 --- a/tests/paint_renderer/compositor_tests.cpp +++ b/tests/paint_renderer/compositor_tests.cpp @@ -1,4 +1,5 @@ #include "assets/image_pixels.h" +#include "legacy_canvas_draw_merge_services.h" #include "legacy_canvas_stroke_commit_services.h" #include "legacy_node_stroke_preview_execution_services.h" #include "paint_renderer/compositor.h" @@ -3171,6 +3172,28 @@ void canvas_blend_gate_combines_layer_and_stroke_complexity(pp::tests::Harness& PP_EXPECT(h, plan.value().path == StrokeCompositePath::framebuffer_fetch); } +void legacy_canvas_draw_merge_temporary_erase_helper_preserves_order(pp::tests::Harness& h) +{ + std::vector order; + const auto execution = pp::panopainter::make_legacy_canvas_draw_merge_temporary_erase_composite( + [&] { order.emplace_back("setup"); }, + [&] { order.emplace_back("bind_samplers"); }, + [&] { order.emplace_back("bind_textures"); }, + [&] { order.emplace_back("draw"); }, + [&] { order.emplace_back("unbind_textures"); }); + + pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(execution); + + const std::vector expected { + "setup", + "bind_samplers", + "bind_textures", + "draw", + "unbind_textures", + }; + PP_EXPECT(h, order == expected); +} + void plans_canvas_stroke_feedback_paths(pp::tests::Harness& h) { const Extent2D extent { .width = 32, .height = 16 }; @@ -3531,6 +3554,9 @@ int main() harness.run("plans_canvas_blend_gate_from_persisted_indices", plans_canvas_blend_gate_from_persisted_indices); harness.run("canvas_blend_gate_preserves_legacy_fallbacks", canvas_blend_gate_preserves_legacy_fallbacks); harness.run("canvas_blend_gate_combines_layer_and_stroke_complexity", canvas_blend_gate_combines_layer_and_stroke_complexity); + harness.run( + "legacy_canvas_draw_merge_temporary_erase_helper_preserves_order", + legacy_canvas_draw_merge_temporary_erase_helper_preserves_order); harness.run("plans_canvas_stroke_feedback_paths", plans_canvas_stroke_feedback_paths); harness.run("canvas_stroke_feedback_preserves_legacy_fallback", canvas_stroke_feedback_preserves_legacy_fallback); harness.run("plans_canvas_stroke_rasterization_boundary", plans_canvas_stroke_rasterization_boundary);