Extract draw merge erase branch helper

This commit is contained in:
2026-06-13 22:47:28 +02:00
parent 42d4f6df1b
commit e8fdd96d37
5 changed files with 94 additions and 10 deletions

View File

@@ -193,6 +193,11 @@ agent or engineer to remove them without reconstructing context from chat.
the remaining temporary erase and paint callback bundle through the remaining temporary erase and paint callback bundle through
`execute_legacy_canvas_draw_merge_temporary_composite(...)`; branch `execute_legacy_canvas_draw_merge_temporary_composite(...)`; branch
selection remains in `Canvas`. 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 - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` now routes
the layer-composite shell through a local wrapper around the layer-composite shell through a local wrapper around
`execute_legacy_canvas_draw_merge_layer_composite(...)`; the final branch `execute_legacy_canvas_draw_merge_layer_composite(...)`; the final branch

View File

@@ -1327,10 +1327,11 @@ Completed Task Log:
### STR-016 - Extract Draw Merge Layer Composite Execution ### STR-016 - Extract Draw Merge Layer Composite Execution
Status: Ready Status: Blocked
Score: +2 renderer boundary and OpenGL parity Score: +2 renderer boundary and OpenGL parity
Debt: `DEBT-0036` Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp` 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: 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` | | 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 ### STR-012 - Extract Preview Final Composite Orchestration
Status: Done Status: Done

View File

@@ -1439,10 +1439,10 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SI
m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index, m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index,
use_blend, use_blend,
pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution { pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution {
.execute_temporary_erase = [&] { .execute_temporary_erase = [&] {
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution { pp::panopainter::make_legacy_canvas_draw_merge_temporary_erase_composite(
.setup = [&] { [&] {
//ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_box) / zoom); //ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_box) / zoom);
//ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index]->m_alpha_locked); //ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index]->m_alpha_locked);
pp::panopainter::setup_legacy_stroke_erase_shader( pp::panopainter::setup_legacy_stroke_erase_shader(
@@ -1455,12 +1455,12 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SI
.mask_enabled = m_smask_active, .mask_enabled = m_smask_active,
}); });
}, },
.bind_samplers = [&] { [&] {
m_sampler.bind(0); m_sampler.bind(0);
m_sampler.bind(1); m_sampler.bind(1);
m_sampler.bind(2); m_sampler.bind(2);
}, },
.bind_textures = [&] { [&] {
set_active_texture_unit(0); set_active_texture_unit(0);
m_layers[layer_index]->rtt(plane_index).bindTexture(); m_layers[layer_index]->rtt(plane_index).bindTexture();
set_active_texture_unit(1); set_active_texture_unit(1);
@@ -1468,17 +1468,16 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SI
set_active_texture_unit(2); set_active_texture_unit(2);
m_smask.rtt(plane_index).bindTexture(); m_smask.rtt(plane_index).bindTexture();
}, },
.draw = [&] { [&] {
m_plane.draw_fill(); m_plane.draw_fill();
}, },
.unbind_textures = [&] { [&] {
m_smask.rtt(plane_index).unbindTexture(); m_smask.rtt(plane_index).unbindTexture();
set_active_texture_unit(1); set_active_texture_unit(1);
m_tmp[plane_index].unbindTexture(); m_tmp[plane_index].unbindTexture();
set_active_texture_unit(0); set_active_texture_unit(0);
m_layers[layer_index]->rtt(plane_index).unbindTexture(); m_layers[layer_index]->rtt(plane_index).unbindTexture();
}, }));
});
}, },
.execute_temporary_paint = [&] { .execute_temporary_paint = [&] {
const auto stroke_material = canvas_stroke_material_plan(*b, false); const auto stroke_material = canvas_stroke_material_plan(*b, false);

View File

@@ -102,6 +102,28 @@ struct LegacyCanvasDrawMergeTemporaryCompositeExecution {
std::function<void()> unbind_textures; std::function<void()> 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>(setup),
.bind_samplers = std::forward<BindSamplers>(bind_samplers),
.bind_textures = std::forward<BindTextures>(bind_textures),
.draw = std::forward<Draw>(draw),
.unbind_textures = std::forward<UnbindTextures>(unbind_textures),
};
}
struct LegacyCanvasDrawMergePlaneSetupUniforms { struct LegacyCanvasDrawMergePlaneSetupUniforms {
LegacyCanvasDrawMergeCheckerboardUniforms checkerboard; LegacyCanvasDrawMergeCheckerboardUniforms checkerboard;
bool use_blend = false; bool use_blend = false;

View File

@@ -1,4 +1,5 @@
#include "assets/image_pixels.h" #include "assets/image_pixels.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_canvas_stroke_commit_services.h" #include "legacy_canvas_stroke_commit_services.h"
#include "legacy_node_stroke_preview_execution_services.h" #include "legacy_node_stroke_preview_execution_services.h"
#include "paint_renderer/compositor.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); 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<std::string> 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<std::string> expected {
"setup",
"bind_samplers",
"bind_textures",
"draw",
"unbind_textures",
};
PP_EXPECT(h, order == expected);
}
void plans_canvas_stroke_feedback_paths(pp::tests::Harness& h) void plans_canvas_stroke_feedback_paths(pp::tests::Harness& h)
{ {
const Extent2D extent { .width = 32, .height = 16 }; 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("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_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("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("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("canvas_stroke_feedback_preserves_legacy_fallback", canvas_stroke_feedback_preserves_legacy_fallback);
harness.run("plans_canvas_stroke_rasterization_boundary", plans_canvas_stroke_rasterization_boundary); harness.run("plans_canvas_stroke_rasterization_boundary", plans_canvas_stroke_rasterization_boundary);