From 43bdc85c11b4195380d5a78afccda0e169b5aceb Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 13 Jun 2026 16:49:31 +0200 Subject: [PATCH] Extract stroke dual pass boundary --- docs/modernization/tasks.md | 6 + src/canvas.cpp | 112 ++++++++++-------- src/legacy_canvas_stroke_execution_services.h | 33 ++++++ 3 files changed, 99 insertions(+), 52 deletions(-) diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 6623750..da5b158 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -509,6 +509,12 @@ Done Checks: Progress Notes: +- 2026-06-13: `Canvas::stroke_draw()` dual-brush replay now routes shader + setup, brush-tip texture binding, live-pass execution, and brush-tip + unbinding through `execute_legacy_canvas_stroke_dual_pass(...)`; the live + adapter still owns the concrete texture callbacks and face-frame replay. + Next slice should target another narrow `stroke_draw()` seam without + reopening landed pad or sample helpers. - 2026-06-13: `Canvas::stroke_draw()` now routes the pad-stroke destination texture dispatch through a local helper lambda, so the repeated bind/unbind callback construction is centralized while the pad executor still owns the diff --git a/src/canvas.cpp b/src/canvas.cpp index 982ff3e..77dd2a1 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -906,67 +906,75 @@ void Canvas::stroke_draw() if (stroke_material.dual_pass.enabled && m_dual_stroke) { const auto& dual_brush = m_dual_stroke->m_brush; - pp::panopainter::setup_legacy_stroke_dual_shader(stroke_material.dual_pass.uses_pattern); - constexpr std::array dual_pass_texture_bindings { pp::panopainter::LegacyCanvasStrokeTextureBinding { .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, .slot = 0, }, }; - pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( - dual_pass_texture_bindings, - pp::panopainter::LegacyCanvasStrokeTextureInputDispatch { - .activate_texture_unit = [&](int texture_slot) { - set_active_texture_unit(texture_slot); - }, - .bind_brush_tip = [&] { - dual_brush->m_tip_texture ? - dual_brush->m_tip_texture->bind() : - unbind_texture_2d(); - }, - .unbind_brush_tip = [&] { - dual_brush->m_tip_texture ? - dual_brush->m_tip_texture->unbind() : - unbind_texture_2d(); - }, - }); auto frames_dual = stroke_draw_compute(*m_dual_stroke); const std::array include_dual_dirty = SIXPLETTE(stroke_material.composite_pass.dual_blend_mode == 0); - pp::panopainter::execute_legacy_canvas_stroke_live_pass_with_face_framebuffers( - frames_dual, - stroke_extent, - std::span(m_dirty_box), - std::span(), - std::span(include_dual_dirty), - [&](auto& f) { - pp::panopainter::apply_legacy_stroke_sample_uniforms( - pp::panopainter::LegacyStrokeSampleUniforms { - .color = f.col, - .alpha = f.flow, - .opacity = f.opacity, - }); - }, - [](auto&, int, auto&) {}, - [&](auto&, int i, auto& P) { - return stroke_draw_samples(i, P, copy_stroke_destination); - }, - m_tmp_dual, - true); - - pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( - dual_pass_texture_bindings, - pp::panopainter::LegacyCanvasStrokeTextureInputDispatch { - .activate_texture_unit = [&](int texture_slot) { - set_active_texture_unit(texture_slot); - }, - .unbind_brush_tip = [&] { - dual_brush->m_tip_texture ? - dual_brush->m_tip_texture->unbind() : - unbind_texture_2d(); - }, - }); + [[maybe_unused]] const auto dual_result = + pp::panopainter::execute_legacy_canvas_stroke_dual_pass( + pp::panopainter::LegacyCanvasStrokeDualPassRequest { + .context = "Canvas::stroke_draw", + .planes = dual_pass_texture_bindings, + .setup_dual_shader = [&] { + pp::panopainter::setup_legacy_stroke_dual_shader( + stroke_material.dual_pass.uses_pattern); + }, + .bind_brush_tip = [&] { + pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( + dual_pass_texture_bindings, + pp::panopainter::LegacyCanvasStrokeTextureInputDispatch { + .activate_texture_unit = [&](int texture_slot) { + set_active_texture_unit(texture_slot); + }, + .bind_brush_tip = [&] { + dual_brush->m_tip_texture ? + dual_brush->m_tip_texture->bind() : + unbind_texture_2d(); + }, + }); + }, + .execute_frame_pass = [&] { + pp::panopainter::execute_legacy_canvas_stroke_live_pass_with_face_framebuffers( + frames_dual, + stroke_extent, + std::span(m_dirty_box), + std::span(), + std::span(include_dual_dirty), + [&](auto& f) { + pp::panopainter::apply_legacy_stroke_sample_uniforms( + pp::panopainter::LegacyStrokeSampleUniforms { + .color = f.col, + .alpha = f.flow, + .opacity = f.opacity, + }); + }, + [](auto&, int, auto&) {}, + [&](auto&, int i, auto& P) { + return stroke_draw_samples(i, P, copy_stroke_destination); + }, + m_tmp_dual, + true); + }, + .unbind_brush_tip = [&] { + pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( + dual_pass_texture_bindings, + pp::panopainter::LegacyCanvasStrokeTextureInputDispatch { + .activate_texture_unit = [&](int texture_slot) { + set_active_texture_unit(texture_slot); + }, + .unbind_brush_tip = [&] { + dual_brush->m_tip_texture ? + dual_brush->m_tip_texture->unbind() : + unbind_texture_2d(); + }, + }); + }, + }); } pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs( diff --git a/src/legacy_canvas_stroke_execution_services.h b/src/legacy_canvas_stroke_execution_services.h index b6d431a..d5ab892 100644 --- a/src/legacy_canvas_stroke_execution_services.h +++ b/src/legacy_canvas_stroke_execution_services.h @@ -179,9 +179,42 @@ struct LegacyCanvasStrokeMixPassResult { std::size_t composed_planes = 0; }; +struct LegacyCanvasStrokeDualPassRequest { + std::string_view context; + std::span planes; + std::function bind_brush_tip; + std::function unbind_brush_tip; + std::function setup_dual_shader; + std::function execute_frame_pass; +}; + +struct LegacyCanvasStrokeDualPassResult { + bool ok = false; + std::size_t composed_planes = 0; +}; + [[nodiscard]] inline LegacyCanvasStrokeMixPassResult execute_legacy_canvas_stroke_mix_pass( const LegacyCanvasStrokeMixPassRequest& request); +[[nodiscard]] inline LegacyCanvasStrokeDualPassResult execute_legacy_canvas_stroke_dual_pass( + const LegacyCanvasStrokeDualPassRequest& request) +{ + LegacyCanvasStrokeDualPassResult result; + if (!request.setup_dual_shader || + !request.bind_brush_tip || + !request.unbind_brush_tip || + !request.execute_frame_pass) { + return result; + } + + request.setup_dual_shader(); + request.bind_brush_tip(); + request.execute_frame_pass(); + request.unbind_brush_tip(); + result.ok = true; + return result; +} + template [[nodiscard]] inline std::array plan_legacy_canvas_stroke_mix_pass_planes(