From 037be1a72a381fffa15fb3b7c7587994ef67df64 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 13 Jun 2026 22:51:11 +0200 Subject: [PATCH] Extract draw merge temporary paint branch --- docs/modernization/debt.md | 5 + src/canvas.cpp | 125 +++++++++++----------- src/legacy_canvas_draw_merge_services.h | 22 ++++ tests/paint_renderer/compositor_tests.cpp | 25 +++++ 4 files changed, 114 insertions(+), 63 deletions(-) diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 5d2895e..1a965b7 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -198,6 +198,11 @@ agent or engineer to remove them without reconstructing context from chat. `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()` temporary + paint branch execution now routes through + `make_legacy_canvas_draw_merge_temporary_paint_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/src/canvas.cpp b/src/canvas.cpp index 9de375b..15fdf0d 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1485,70 +1485,69 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI if (b->m_pattern_flipx) patt_scale.x *= -1.f; if (b->m_pattern_flipy) patt_scale.y *= -1.f; - pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( - pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution { - .setup = [&] { - pp::panopainter::setup_legacy_stroke_composite_shader( - pp::panopainter::LegacyStrokeCompositeUniforms { - .resolution = Canvas::I->m_size, - .pattern = { - .scale = patt_scale, - .invert = static_cast(b->m_pattern_invert), - .brightness = b->m_pattern_brightness, - .contrast = b->m_pattern_contrast, - .depth = b->m_pattern_depth, - .blend_mode = b->m_pattern_blend_mode, - .offset = Canvas::I->m_pattern_offset, - }, - .mvp = ortho, - .layer_alpha = m_layers[layer_index]->m_opacity, - .alpha_lock = m_layers[layer_index]->m_alpha_locked, - .mask_enabled = m_smask_active, - .use_fragcoord = false, - .blend_mode = b->m_blend_mode, - .use_dual = stroke_material.composite_pass.use_dual, - .dual_blend_mode = stroke_material.composite_pass.dual_blend_mode, - .dual_alpha = stroke_material.composite_pass.dual_alpha, - .use_pattern = stroke_material.composite_pass.use_pattern, - }); - }, - .bind_samplers = [&] { - m_sampler.bind(0); - m_sampler.bind(1); - m_sampler.bind(2); - m_sampler.bind(3); - m_sampler_stencil.bind(4); - }, - .bind_textures = [&] { - set_active_texture_unit(0); - m_layers[layer_index]->rtt(plane_index).bindTexture(); - set_active_texture_unit(1); - m_tmp[plane_index].bindTexture(); - set_active_texture_unit(2); - m_smask.rtt(plane_index).bindTexture(); - set_active_texture_unit(3); - if (stroke_material.composite_pass.use_dual) - m_tmp_dual[plane_index].bindTexture(); - set_active_texture_unit(4); - b->m_pattern_texture ? - b->m_pattern_texture->bind() : - unbind_texture_2d(); - }, - .draw = [&] { - m_plane.draw_fill(); - }, - .unbind_textures = [&] { - set_active_texture_unit(3); - if (stroke_material.composite_pass.use_dual) - m_tmp_dual[plane_index].unbindTexture(); - set_active_texture_unit(2); - 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(); - }, + const auto execution = pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_composite( + [&] { + pp::panopainter::setup_legacy_stroke_composite_shader( + pp::panopainter::LegacyStrokeCompositeUniforms { + .resolution = Canvas::I->m_size, + .pattern = { + .scale = patt_scale, + .invert = static_cast(b->m_pattern_invert), + .brightness = b->m_pattern_brightness, + .contrast = b->m_pattern_contrast, + .depth = b->m_pattern_depth, + .blend_mode = b->m_pattern_blend_mode, + .offset = Canvas::I->m_pattern_offset, + }, + .mvp = ortho, + .layer_alpha = m_layers[layer_index]->m_opacity, + .alpha_lock = m_layers[layer_index]->m_alpha_locked, + .mask_enabled = m_smask_active, + .use_fragcoord = false, + .blend_mode = b->m_blend_mode, + .use_dual = stroke_material.composite_pass.use_dual, + .dual_blend_mode = stroke_material.composite_pass.dual_blend_mode, + .dual_alpha = stroke_material.composite_pass.dual_alpha, + .use_pattern = stroke_material.composite_pass.use_pattern, + }); + }, + [&] { + m_sampler.bind(0); + m_sampler.bind(1); + m_sampler.bind(2); + m_sampler.bind(3); + m_sampler_stencil.bind(4); + }, + [&] { + set_active_texture_unit(0); + m_layers[layer_index]->rtt(plane_index).bindTexture(); + set_active_texture_unit(1); + m_tmp[plane_index].bindTexture(); + set_active_texture_unit(2); + m_smask.rtt(plane_index).bindTexture(); + set_active_texture_unit(3); + if (stroke_material.composite_pass.use_dual) + m_tmp_dual[plane_index].bindTexture(); + set_active_texture_unit(4); + b->m_pattern_texture ? + b->m_pattern_texture->bind() : + unbind_texture_2d(); + }, + [&] { + m_plane.draw_fill(); + }, + [&] { + set_active_texture_unit(3); + if (stroke_material.composite_pass.use_dual) + m_tmp_dual[plane_index].unbindTexture(); + set_active_texture_unit(2); + 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(); }); + pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(execution); }, .execute_layer_texture = [&] { execute_canvas_draw_merge_layer_texture( diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index a21a5ec..b2e0b92 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -124,6 +124,28 @@ template < }; } +template < + typename Setup, + typename BindSamplers, + typename BindTextures, + typename Draw, + typename UnbindTextures> +[[nodiscard]] inline LegacyCanvasDrawMergeTemporaryCompositeExecution make_legacy_canvas_draw_merge_temporary_paint_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 a91cd10..492f4a9 100644 --- a/tests/paint_renderer/compositor_tests.cpp +++ b/tests/paint_renderer/compositor_tests.cpp @@ -3194,6 +3194,28 @@ void legacy_canvas_draw_merge_temporary_erase_helper_preserves_order(pp::tests:: PP_EXPECT(h, order == expected); } +void legacy_canvas_draw_merge_temporary_paint_helper_preserves_order(pp::tests::Harness& h) +{ + std::vector order; + const auto execution = pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_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 }; @@ -3557,6 +3579,9 @@ int main() harness.run( "legacy_canvas_draw_merge_temporary_erase_helper_preserves_order", legacy_canvas_draw_merge_temporary_erase_helper_preserves_order); + harness.run( + "legacy_canvas_draw_merge_temporary_paint_helper_preserves_order", + legacy_canvas_draw_merge_temporary_paint_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);