From a6855fca05ddad188e1724802e90386138f418db Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 13 Jun 2026 19:21:42 +0200 Subject: [PATCH] Wrap stroke mix shell bundle --- docs/modernization/debt.md | 4 + docs/modernization/tasks.md | 4 + src/canvas.cpp | 62 +-------------- src/legacy_canvas_stroke_execution_services.h | 44 +++++++++++ .../paint_renderer/stroke_execution_tests.cpp | 76 +++++++++++++++++++ 5 files changed, 132 insertions(+), 58 deletions(-) diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 3015c45..12b66c6 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,10 @@ agent or engineer to remove them without reconstructing context from chat. ## Recent Reductions +- 2026-06-13: `LATER-003` was narrowed again. `Canvas::stroke_draw_mix()` now + routes the combined setup and request bundle through + `make_legacy_canvas_stroke_mix_pass_shell(...)`; the live path still owns + the concrete framebuffer bind and GL capability toggles. - 2026-06-13: `LATER-003` was narrowed again. `Canvas::stroke_draw_mix()` now routes the retained mix-pass shell through `execute_legacy_canvas_stroke_mix_pass_shell(...)`; the live path still owns diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index e557a97..1a01a65 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -604,6 +604,10 @@ Progress Notes: - 2026-06-13: `Canvas::stroke_draw_mix()` now routes the retained mix-pass shell through `execute_legacy_canvas_stroke_mix_pass_shell(...)`; the live path still owns the concrete framebuffer bind and GL capability toggles. +- 2026-06-13: `Canvas::stroke_draw_mix()` now routes the combined setup and + request bundle through `make_legacy_canvas_stroke_mix_pass_shell(...)`; the + live path still owns the concrete framebuffer bind and GL capability + toggles. - 2026-06-13: `Canvas::stroke_draw()` live-pass sampler wiring now reuses a retained helper builder, and the stroke execution tests cover it. `STR-004` is now done after the final pad-destination helper extraction and tracker diff --git a/src/canvas.cpp b/src/canvas.cpp index 5813643..e0c8ab4 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -403,7 +403,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) return current_layer.face(plane_index); }); const auto& b = m_current_stroke->m_brush; - const auto mix_setup = pp::panopainter::make_legacy_canvas_stroke_mix_pass_setup( + const auto mix_shell = pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell( [&] { m_mixer.bindFramebuffer(); apply_canvas_viewport(0, 0, m_mixer.getWidth(), m_mixer.getHeight()); @@ -421,63 +421,9 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) }); [[maybe_unused]] const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell( - mix_setup.begin, - mix_setup.end, - pp::panopainter::make_legacy_canvas_stroke_mix_pass_request( - "Canvas::stroke_draw_mix", - m_size, - mix_planes, - [&] { - m_sampler.bind(0); - m_sampler.bind(1); - m_sampler.bind(2); - }, - [&] { - m_sampler.unbind(); - }, - [&](int plane_index, const glm::mat4& plane_mvp_z) { - (void)plane_index; - pp::panopainter::setup_legacy_stroke_composite_shader( - pp::panopainter::LegacyStrokeCompositeUniforms { - .resolution = m_size, - .mvp = plane_mvp_z, - .pattern_texture_slot = 3, - .layer_alpha = 1.0f, - .alpha_lock = false, /*current_layer.m_alpha_locked*/ - .mask_enabled = false, /*m_smask_active*/ - .use_fragcoord = false, - .blend_mode = b->m_blend_mode, - .use_dual = false, - .use_pattern = false, - }); - }, - [&](int plane_index) { - set_active_texture_unit(0); - current_layer.rtt(plane_index).bindTexture(); - }, - [&](int plane_index) { - set_active_texture_unit(1); - m_tmp[plane_index].bindTexture(); - }, - [&](int plane_index) { - set_active_texture_unit(2); - m_smask.rtt(plane_index).bindTexture(); - }, - [&] { - m_node->m_face_plane.draw_fill(); - }, - [&](int plane_index) { - set_active_texture_unit(2); - m_smask.rtt(plane_index).unbindTexture(); - }, - [&](int plane_index) { - set_active_texture_unit(1); - m_tmp[plane_index].unbindTexture(); - }, - [&](int plane_index) { - set_active_texture_unit(0); - current_layer.rtt(plane_index).unbindTexture(); - })); + mix_shell.setup.begin, + mix_shell.setup.end, + mix_shell.request); gl.restore(); } diff --git a/src/legacy_canvas_stroke_execution_services.h b/src/legacy_canvas_stroke_execution_services.h index 6ada6e4..df155b8 100644 --- a/src/legacy_canvas_stroke_execution_services.h +++ b/src/legacy_canvas_stroke_execution_services.h @@ -387,6 +387,50 @@ struct LegacyCanvasStrokeMixPassSetup { }; } +struct LegacyCanvasStrokeMixPassShell { + LegacyCanvasStrokeMixPassSetup setup; + LegacyCanvasStrokeMixPassRequest request; +}; + +template +[[nodiscard]] inline LegacyCanvasStrokeMixPassShell make_legacy_canvas_stroke_mix_pass_shell( + BeginMixPass&& begin_mix_pass, + EndMixPass&& end_mix_pass, + std::string_view context, + glm::vec2 resolution, + std::span planes, + std::function bind_mix_samplers, + std::function unbind_mix_samplers, + std::function setup_plane_shader, + std::function bind_layer_texture, + std::function bind_stroke_texture, + std::function bind_mask_texture, + std::function draw_plane, + std::function unbind_mask_texture, + std::function unbind_stroke_texture, + std::function unbind_layer_texture) +{ + return LegacyCanvasStrokeMixPassShell { + .setup = make_legacy_canvas_stroke_mix_pass_setup( + std::forward(begin_mix_pass), + std::forward(end_mix_pass)), + .request = make_legacy_canvas_stroke_mix_pass_request( + context, + resolution, + planes, + std::move(bind_mix_samplers), + std::move(unbind_mix_samplers), + std::move(setup_plane_shader), + std::move(bind_layer_texture), + std::move(bind_stroke_texture), + std::move(bind_mask_texture), + std::move(draw_plane), + std::move(unbind_mask_texture), + std::move(unbind_stroke_texture), + std::move(unbind_layer_texture)), + }; +} + struct LegacyCanvasStrokeDualPassRequest { std::string_view context; std::function bind_brush_tip; diff --git a/tests/paint_renderer/stroke_execution_tests.cpp b/tests/paint_renderer/stroke_execution_tests.cpp index d0644ec..4682117 100644 --- a/tests/paint_renderer/stroke_execution_tests.cpp +++ b/tests/paint_renderer/stroke_execution_tests.cpp @@ -1903,6 +1903,79 @@ void retained_stroke_mix_pass_setup_builder_preserves_boundaries(pp::tests::Harn PP_EXPECT(h, events[1] == "end"); } +void retained_stroke_mix_pass_shell_builder_preserves_combined_wiring(pp::tests::Harness& h) +{ + const std::array planes { + LegacyCanvasStrokeMixPassPlane { .index = 2, .visible = true, .has_target = true, .opacity = 1.0F }, + }; + + std::vector events; + const auto shell = pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell( + [&] { events.emplace_back("begin"); }, + [&] { events.emplace_back("end"); }, + "mix-shell", + glm::vec2(64.0F, 32.0F), + planes, + [&] { events.emplace_back("bind-samplers"); }, + [&] { events.emplace_back("unbind-samplers"); }, + [&](int plane_index, const glm::mat4&) { + events.emplace_back("setup:" + std::to_string(plane_index)); + }, + [&](int plane_index) { + events.emplace_back("bind-layer:" + std::to_string(plane_index)); + }, + [&](int plane_index) { + events.emplace_back("bind-stroke:" + std::to_string(plane_index)); + }, + [&](int plane_index) { + events.emplace_back("bind-mask:" + std::to_string(plane_index)); + }, + [&] { events.emplace_back("draw"); }, + [&](int plane_index) { + events.emplace_back("unbind-mask:" + std::to_string(plane_index)); + }, + [&](int plane_index) { + events.emplace_back("unbind-stroke:" + std::to_string(plane_index)); + }, + [&](int plane_index) { + events.emplace_back("unbind-layer:" + std::to_string(plane_index)); + }); + + PP_EXPECT(h, shell.setup.begin); + PP_EXPECT(h, shell.setup.end); + PP_EXPECT(h, shell.request.context == "mix-shell"); + PP_EXPECT(h, shell.request.planes.size() == 1U); + + shell.setup.begin(); + shell.request.bind_mix_samplers(); + shell.request.setup_plane_shader(2, glm::mat4(1.0F)); + shell.request.bind_layer_texture(2); + shell.request.bind_stroke_texture(2); + shell.request.bind_mask_texture(2); + shell.request.draw_plane(); + shell.request.unbind_mask_texture(2); + shell.request.unbind_stroke_texture(2); + shell.request.unbind_layer_texture(2); + shell.request.unbind_mix_samplers(); + shell.setup.end(); + + const std::vector expected_events { + "begin", + "bind-samplers", + "setup:2", + "bind-layer:2", + "bind-stroke:2", + "bind-mask:2", + "draw", + "unbind-mask:2", + "unbind-stroke:2", + "unbind-layer:2", + "unbind-samplers", + "end", + }; + PP_EXPECT(h, events == expected_events); +} + } // namespace int main() @@ -2013,5 +2086,8 @@ int main() harness.run( "retained_stroke_mix_pass_setup_builder_preserves_boundaries", retained_stroke_mix_pass_setup_builder_preserves_boundaries); + harness.run( + "retained_stroke_mix_pass_shell_builder_preserves_combined_wiring", + retained_stroke_mix_pass_shell_builder_preserves_combined_wiring); return harness.finish(); }