diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 1c38888..440e8a2 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -80,6 +80,11 @@ agent or engineer to remove them without reconstructing context from chat. composite setup now routes through `execute_canvas_draw_merge_temporary_composite(...)`; setup, sampler, texture, draw, and unbind callbacks still remain retained in the legacy Canvas path. +- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` temporary + erase and paint branch wiring now routes through + `execute_legacy_canvas_draw_merge_temporary_composite(...)`; the retained + path still owns the concrete setup, sampler, texture, draw, and unbind + callbacks. - 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::draw_stroke_immediate()` now routes retained preview feedback/material/composite planning plus stroke shader uniform assembly through diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 3efd1eb..cc7cbe4 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -660,6 +660,11 @@ Progress Notes: path still owns the concrete setup, sampler, texture, draw, and unbind callbacks. Next slice should target another narrow draw-merge seam without reopening the landed temporary-composite helper. +- 2026-06-13: `Canvas::draw_merge()` temporary erase and paint branch wiring + now routes through `execute_legacy_canvas_draw_merge_temporary_composite(...)`; + the retained path still owns the concrete setup, sampler, texture, draw, and + unbind callbacks. Next slice should target another narrow draw-merge seam + without reopening the landed temporary-composite helper. - 2026-06-13: `pp_paint_renderer_stroke_execution_tests` now also covers retained frame-plan assembly for previous-sample projection mode and zoom scaling. Next slice should target the remaining preview/Canvas stroke diff --git a/src/canvas.cpp b/src/canvas.cpp index c8d4a0b..e16f148 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -480,22 +480,6 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) gl.restore(); } -template -static void execute_canvas_draw_merge_temporary_composite( - Setup&& setup, - BindSamplers&& bind_samplers, - BindTextures&& bind_textures, - Draw&& draw, - UnbindTextures&& unbind_textures) -{ - pp::panopainter::execute_legacy_canvas_stroke_temporary_composite( - std::forward(setup), - std::forward(bind_samplers), - std::forward(bind_textures), - std::forward(draw), - std::forward(unbind_textures)); -} - std::array, 6> Canvas::stroke_draw_project(std::array& B, bool project_3d /*= false*/, glm::mat4 mv /*= glm::mat4(1)*/) const { // intersect P with the current face to clip diverging points from the plane @@ -1445,119 +1429,123 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array faces /*= SI m_merge_rtt.clear(); } - pp::panopainter::execute_legacy_canvas_draw_merge_layer_composite( - m_current_stroke && m_current_mode == kCanvasMode::Erase && m_show_tmp && m_current_layer_idx == layer_index, - m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index, - use_blend, - pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution { - .execute_temporary_erase = [&] { - execute_canvas_draw_merge_temporary_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( - pp::panopainter::LegacyStrokeEraseUniforms { - .mvp = ortho, - .texture_slot = 0, - .stroke_texture_slot = 1, - .mask_texture_slot = 2, - .alpha = m_layers[layer_index]->m_opacity, - .mask_enabled = m_smask_active, - }); - }, - [&] { - m_sampler.bind(0); - m_sampler.bind(1); - m_sampler.bind(2); - }, - [&] { - 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(); - }, - [&] { - m_plane.draw_fill(); - }, - [&] { - 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_layer_composite( + m_current_stroke && m_current_mode == kCanvasMode::Erase && m_show_tmp && m_current_layer_idx == layer_index, + m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index, + use_blend, + pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution { + .execute_temporary_erase = [&] { + pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( + pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution { + .setup = [&] { + //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( + pp::panopainter::LegacyStrokeEraseUniforms { + .mvp = ortho, + .texture_slot = 0, + .stroke_texture_slot = 1, + .mask_texture_slot = 2, + .alpha = m_layers[layer_index]->m_opacity, + .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); + m_tmp[plane_index].bindTexture(); + 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); glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale); if (b->m_pattern_flipx) patt_scale.x *= -1.f; if (b->m_pattern_flipy) patt_scale.y *= -1.f; - execute_canvas_draw_merge_temporary_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, + 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(); }, - .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(); - }); - }, .execute_layer_texture = [&] { pp::panopainter::execute_legacy_canvas_draw_merge_layer_texture( pp::panopainter::LegacyCanvasDrawMergeTextureAlphaUniforms { diff --git a/src/legacy_canvas_draw_merge_services.h b/src/legacy_canvas_draw_merge_services.h index 63b3127..fe216d1 100644 --- a/src/legacy_canvas_draw_merge_services.h +++ b/src/legacy_canvas_draw_merge_services.h @@ -94,6 +94,14 @@ struct LegacyCanvasDrawMergeLayerCompositeExecution { std::function execute_layer_blend; }; +struct LegacyCanvasDrawMergeTemporaryCompositeExecution { + std::function setup; + std::function bind_samplers; + std::function bind_textures; + std::function draw; + std::function unbind_textures; +}; + struct LegacyCanvasDrawMergePlaneSetupUniforms { LegacyCanvasDrawMergeCheckerboardUniforms checkerboard; bool use_blend = false; @@ -330,6 +338,16 @@ inline void execute_legacy_canvas_draw_merge_layer_composite( } } +inline void execute_legacy_canvas_draw_merge_temporary_composite( + const LegacyCanvasDrawMergeTemporaryCompositeExecution& execution) +{ + execution.setup(); + execution.bind_samplers(); + execution.bind_textures(); + execution.draw(); + execution.unbind_textures(); +} + inline void execute_legacy_canvas_draw_merge_plane_setup( const LegacyCanvasDrawMergePlaneSetupUniforms& uniforms, const LegacyCanvasDrawMergePlaneSetupExecution& execution)