Extract stroke commit callback orchestration
This commit is contained in:
@@ -18,6 +18,11 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
|
|
||||||
## Recent Reductions
|
## Recent Reductions
|
||||||
|
|
||||||
|
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_commit()` now
|
||||||
|
builds its retained callback table through
|
||||||
|
`make_legacy_canvas_stroke_commit_callbacks(...)`; the legacy executor still
|
||||||
|
owns ordering, history capture, and dilate sequencing, and the concrete
|
||||||
|
Canvas state wiring remains open in the legacy path.
|
||||||
- 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
|
||||||
per-plane merge-target clear, blend-state gating, and optional checkerboard
|
per-plane merge-target clear, blend-state gating, and optional checkerboard
|
||||||
prepass through `execute_legacy_canvas_draw_merge_plane_setup(...)`;
|
prepass through `execute_legacy_canvas_draw_merge_plane_setup(...)`;
|
||||||
|
|||||||
@@ -989,7 +989,7 @@ ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_ex
|
|||||||
|
|
||||||
### STR-009 - Extract Stroke Commit Callback Orchestration
|
### STR-009 - Extract Stroke Commit Callback Orchestration
|
||||||
|
|
||||||
Status: Ready
|
Status: Done
|
||||||
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_stroke_execution_services.h`,
|
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
|
||||||
@@ -1016,3 +1016,9 @@ Validation:
|
|||||||
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
|
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
|
||||||
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
|
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Completed Task Log:
|
||||||
|
|
||||||
|
| Date | Task | Score | Validation | Commit |
|
||||||
|
| --- | --- | ---: | --- | --- |
|
||||||
|
| 2026-06-13 | STR-009 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "retained_stroke_commit_callback_builder_preserves_order|retained_stroke_commit_runner_preserves_per_face_step_order" --output-on-failure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `pending` |
|
||||||
|
|||||||
103
src/canvas.cpp
103
src/canvas.cpp
@@ -392,11 +392,13 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
|||||||
gl.save();
|
gl.save();
|
||||||
const auto layer_index = m_current_layer_idx;
|
const auto layer_index = m_current_layer_idx;
|
||||||
auto& current_layer = *m_layers[layer_index];
|
auto& current_layer = *m_layers[layer_index];
|
||||||
|
std::array<glm::mat4, 6> plane_transform {};
|
||||||
|
std::copy(std::begin(m_plane_transform), std::end(m_plane_transform), plane_transform.begin());
|
||||||
const auto mix_planes = pp::panopainter::plan_legacy_canvas_stroke_mix_pass_planes(
|
const auto mix_planes = pp::panopainter::plan_legacy_canvas_stroke_mix_pass_planes(
|
||||||
current_layer.m_visible,
|
current_layer.m_visible,
|
||||||
current_layer.m_opacity,
|
current_layer.m_opacity,
|
||||||
glm::scale(glm::vec3(1, -1, 1)) * m_proj * m_mv,
|
glm::scale(glm::vec3(1, -1, 1)) * m_proj * m_mv,
|
||||||
m_plane_transform,
|
plane_transform,
|
||||||
[&](int plane_index) {
|
[&](int plane_index) {
|
||||||
return current_layer.face(plane_index);
|
return current_layer.face(plane_index);
|
||||||
});
|
});
|
||||||
@@ -757,8 +759,7 @@ void Canvas::stroke_draw()
|
|||||||
[&] {
|
[&] {
|
||||||
m_sampler.unbind();
|
m_sampler.unbind();
|
||||||
});
|
});
|
||||||
const pp::panopainter::LegacyCanvasStrokeTextureInputDispatch main_pass_texture_dispatch {
|
const auto main_pass_texture_dispatch = pp::panopainter::make_legacy_canvas_stroke_main_pass_texture_dispatch(
|
||||||
pp::panopainter::make_legacy_canvas_stroke_main_pass_texture_dispatch(
|
|
||||||
[&](int texture_slot) {
|
[&](int texture_slot) {
|
||||||
set_active_texture_unit(texture_slot);
|
set_active_texture_unit(texture_slot);
|
||||||
},
|
},
|
||||||
@@ -845,7 +846,7 @@ void Canvas::stroke_draw()
|
|||||||
.input = pp::panopainter::LegacyCanvasStrokeTextureInput::stroke_destination,
|
.input = pp::panopainter::LegacyCanvasStrokeTextureInput::stroke_destination,
|
||||||
.slot = 1,
|
.slot = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const auto make_pad_destination_texture_dispatch = [&](int face_index) {
|
const auto make_pad_destination_texture_dispatch = [&](int face_index) {
|
||||||
return pp::panopainter::make_legacy_canvas_stroke_pad_destination_texture_dispatch(
|
return pp::panopainter::make_legacy_canvas_stroke_pad_destination_texture_dispatch(
|
||||||
[&](int texture_slot) {
|
[&](int texture_slot) {
|
||||||
@@ -914,10 +915,6 @@ void Canvas::stroke_draw()
|
|||||||
pp::panopainter::execute_legacy_canvas_stroke_dual_pass(
|
pp::panopainter::execute_legacy_canvas_stroke_dual_pass(
|
||||||
pp::panopainter::LegacyCanvasStrokeDualPassRequest {
|
pp::panopainter::LegacyCanvasStrokeDualPassRequest {
|
||||||
.context = "Canvas::stroke_draw",
|
.context = "Canvas::stroke_draw",
|
||||||
.setup_dual_shader = [&] {
|
|
||||||
pp::panopainter::setup_legacy_stroke_dual_shader(
|
|
||||||
stroke_material.dual_pass.uses_pattern);
|
|
||||||
},
|
|
||||||
.bind_brush_tip = [&] {
|
.bind_brush_tip = [&] {
|
||||||
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(
|
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(
|
||||||
dual_pass_texture_bindings,
|
dual_pass_texture_bindings,
|
||||||
@@ -936,6 +933,28 @@ void Canvas::stroke_draw()
|
|||||||
unbind_texture_2d();
|
unbind_texture_2d();
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
.unbind_brush_tip = [&] {
|
||||||
|
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
|
||||||
|
dual_pass_texture_bindings,
|
||||||
|
pp::panopainter::make_legacy_canvas_stroke_brush_tip_texture_dispatch(
|
||||||
|
[&](int texture_slot) {
|
||||||
|
set_active_texture_unit(texture_slot);
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
dual_brush->m_tip_texture ?
|
||||||
|
dual_brush->m_tip_texture->bind() :
|
||||||
|
unbind_texture_2d();
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
dual_brush->m_tip_texture ?
|
||||||
|
dual_brush->m_tip_texture->unbind() :
|
||||||
|
unbind_texture_2d();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
.setup_dual_shader = [&] {
|
||||||
|
pp::panopainter::setup_legacy_stroke_dual_shader(
|
||||||
|
stroke_material.dual_pass.uses_pattern);
|
||||||
|
},
|
||||||
.execute_frame_pass = [&] {
|
.execute_frame_pass = [&] {
|
||||||
pp::panopainter::execute_legacy_canvas_stroke_dual_pass_frame_callbacks(
|
pp::panopainter::execute_legacy_canvas_stroke_dual_pass_frame_callbacks(
|
||||||
frames_dual,
|
frames_dual,
|
||||||
@@ -958,24 +977,6 @@ void Canvas::stroke_draw()
|
|||||||
m_tmp_dual,
|
m_tmp_dual,
|
||||||
true);
|
true);
|
||||||
},
|
},
|
||||||
.unbind_brush_tip = [&] {
|
|
||||||
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
|
|
||||||
dual_pass_texture_bindings,
|
|
||||||
pp::panopainter::make_legacy_canvas_stroke_brush_tip_texture_dispatch(
|
|
||||||
[&](int texture_slot) {
|
|
||||||
set_active_texture_unit(texture_slot);
|
|
||||||
},
|
|
||||||
[&] {
|
|
||||||
dual_brush->m_tip_texture ?
|
|
||||||
dual_brush->m_tip_texture->bind() :
|
|
||||||
unbind_texture_2d();
|
|
||||||
},
|
|
||||||
[&] {
|
|
||||||
dual_brush->m_tip_texture ?
|
|
||||||
dual_brush->m_tip_texture->unbind() :
|
|
||||||
unbind_texture_2d();
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1117,44 +1118,39 @@ void Canvas::stroke_commit()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] const auto commit_result = pp::panopainter::execute_legacy_canvas_stroke_commit_sequence(
|
const auto commit_callbacks = pp::panopainter::make_legacy_canvas_stroke_commit_callbacks(
|
||||||
pp::panopainter::LegacyCanvasStrokeCommitRequest {
|
[&]() {
|
||||||
.context = "Canvas::stroke_commit",
|
|
||||||
.faces = faces,
|
|
||||||
.sequence = sequence,
|
|
||||||
.callbacks = {
|
|
||||||
.mark_commit_started = [&]() {
|
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
m_dirty_stroke = true; // new stroke ready for timelapse capture
|
m_dirty_stroke = true; // new stroke ready for timelapse capture
|
||||||
App::I->redraw = true;
|
App::I->redraw = true;
|
||||||
m_unsaved = true;
|
m_unsaved = true;
|
||||||
App::I->title_update();
|
App::I->title_update();
|
||||||
},
|
},
|
||||||
.capture_render_state = []() {},
|
[]() {},
|
||||||
.prepare_render_state = [&]() {
|
[&]() {
|
||||||
apply_canvas_viewport(0, 0, m_width, m_height);
|
apply_canvas_viewport(0, 0, m_width, m_height);
|
||||||
apply_canvas_capability(blend_state(), false);
|
apply_canvas_capability(blend_state(), false);
|
||||||
},
|
},
|
||||||
.restore_render_state = [&]() {
|
[&]() {
|
||||||
blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
|
blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
|
||||||
apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
|
apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
|
||||||
apply_canvas_clear_color(cc);
|
apply_canvas_clear_color(cc);
|
||||||
set_active_texture_unit(0);
|
set_active_texture_unit(0);
|
||||||
},
|
},
|
||||||
.publish_history = [&]() {
|
[&]() {
|
||||||
action->m_layer_idx = m_current_layer_idx;
|
action->m_layer_idx = m_current_layer_idx;
|
||||||
action->m_frame_idx = layer().m_frame_index;
|
action->m_frame_idx = layer().m_frame_index;
|
||||||
action->m_canvas = this;
|
action->m_canvas = this;
|
||||||
//action->m_stroke = std::move(m_current_stroke);
|
//action->m_stroke = std::move(m_current_stroke);
|
||||||
ActionManager::add(action);
|
ActionManager::add(action);
|
||||||
},
|
},
|
||||||
.capture_timelapse_frame = [&]() {
|
[&]() {
|
||||||
stroke_commit_timelapse();
|
stroke_commit_timelapse();
|
||||||
},
|
},
|
||||||
.bind_layer_framebuffer = [&](int i) {
|
[&](int i) {
|
||||||
m_layers[m_current_layer_idx]->rtt(i).bindFramebuffer();
|
m_layers[m_current_layer_idx]->rtt(i).bindFramebuffer();
|
||||||
},
|
},
|
||||||
.capture_history_region = [&](int i) {
|
[&](int i) {
|
||||||
// save image before commit
|
// save image before commit
|
||||||
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
||||||
action->m_image[i] = std::make_unique<uint8_t[]>(
|
action->m_image[i] = std::make_unique<uint8_t[]>(
|
||||||
@@ -1170,7 +1166,7 @@ void Canvas::stroke_commit()
|
|||||||
action->m_old_box[i] = m_layers[m_current_layer_idx]->box(i);
|
action->m_old_box[i] = m_layers[m_current_layer_idx]->box(i);
|
||||||
action->m_old_dirty[i] = m_layers[m_current_layer_idx]->face(i);
|
action->m_old_dirty[i] = m_layers[m_current_layer_idx]->face(i);
|
||||||
},
|
},
|
||||||
.apply_layer_dirty_region = [&](int i) {
|
[&](int i) {
|
||||||
if (!m_layers[m_current_layer_idx]->m_alpha_locked)
|
if (!m_layers[m_current_layer_idx]->m_alpha_locked)
|
||||||
{
|
{
|
||||||
auto& lbox = m_layers[m_current_layer_idx]->box(i);
|
auto& lbox = m_layers[m_current_layer_idx]->box(i);
|
||||||
@@ -1181,14 +1177,14 @@ void Canvas::stroke_commit()
|
|||||||
}
|
}
|
||||||
m_layers[m_current_layer_idx]->face(i) = true;
|
m_layers[m_current_layer_idx]->face(i) = true;
|
||||||
},
|
},
|
||||||
.copy_layer_to_commit_destination = [&](int i) {
|
[&](int i) {
|
||||||
// copy to tmp2 for layer blending
|
// copy to tmp2 for layer blending
|
||||||
set_active_texture_unit(0);
|
set_active_texture_unit(0);
|
||||||
m_tex2[i].bind();
|
m_tex2[i].bind();
|
||||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height);
|
copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height);
|
||||||
m_tex2[i].unbind();
|
m_tex2[i].unbind();
|
||||||
},
|
},
|
||||||
.bind_commit_inputs = [&](int i) {
|
[&](int i) {
|
||||||
pp::panopainter::bind_legacy_canvas_stroke_commit_inputs(
|
pp::panopainter::bind_legacy_canvas_stroke_commit_inputs(
|
||||||
sequence,
|
sequence,
|
||||||
[&](int texture_slot) {
|
[&](int texture_slot) {
|
||||||
@@ -1231,7 +1227,7 @@ void Canvas::stroke_commit()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.execute_erase_composite = [&](int) {
|
[&](int) {
|
||||||
pp::panopainter::execute_legacy_canvas_stroke_commit_erase(
|
pp::panopainter::execute_legacy_canvas_stroke_commit_erase(
|
||||||
[&]() {
|
[&]() {
|
||||||
pp::panopainter::setup_legacy_stroke_erase_shader(
|
pp::panopainter::setup_legacy_stroke_erase_shader(
|
||||||
@@ -1248,7 +1244,7 @@ void Canvas::stroke_commit()
|
|||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.execute_paint_composite = [&](int) {
|
[&](int) {
|
||||||
glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
|
glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
|
||||||
if (b->m_pattern_flipx) patt_scale.x *= -1.f;
|
if (b->m_pattern_flipx) patt_scale.x *= -1.f;
|
||||||
if (b->m_pattern_flipy) patt_scale.y *= -1.f;
|
if (b->m_pattern_flipy) patt_scale.y *= -1.f;
|
||||||
@@ -1283,7 +1279,7 @@ void Canvas::stroke_commit()
|
|||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.copy_committed_to_dilate_source = [&](int i) {
|
[&](int i) {
|
||||||
pp::panopainter::copy_legacy_canvas_stroke_commit_to_dilate_source(
|
pp::panopainter::copy_legacy_canvas_stroke_commit_to_dilate_source(
|
||||||
sequence,
|
sequence,
|
||||||
[&]() {
|
[&]() {
|
||||||
@@ -1307,15 +1303,22 @@ void Canvas::stroke_commit()
|
|||||||
.height = m_height,
|
.height = m_height,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.execute_commit_dilate = [&](int) {
|
[&](int) {
|
||||||
pp::panopainter::execute_legacy_canvas_stroke_commit_dilate([&]() {
|
pp::panopainter::execute_legacy_canvas_stroke_commit_dilate([&]() {
|
||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.unbind_layer_framebuffer = [&](int i) {
|
[&](int i) {
|
||||||
m_layers[m_current_layer_idx]->rtt(i).unbindFramebuffer();
|
m_layers[m_current_layer_idx]->rtt(i).unbindFramebuffer();
|
||||||
},
|
}
|
||||||
},
|
);
|
||||||
|
|
||||||
|
[[maybe_unused]] const auto commit_result = pp::panopainter::execute_legacy_canvas_stroke_commit_sequence(
|
||||||
|
pp::panopainter::LegacyCanvasStrokeCommitRequest {
|
||||||
|
.context = "Canvas::stroke_commit",
|
||||||
|
.faces = faces,
|
||||||
|
.sequence = sequence,
|
||||||
|
.callbacks = commit_callbacks,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace pp::panopainter {
|
namespace pp::panopainter {
|
||||||
|
|
||||||
@@ -52,6 +53,61 @@ struct LegacyCanvasStrokeCommitCopyExtent {
|
|||||||
int height = 0;
|
int height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename MarkCommitStarted,
|
||||||
|
typename CaptureRenderState,
|
||||||
|
typename PrepareRenderState,
|
||||||
|
typename RestoreRenderState,
|
||||||
|
typename PublishHistory,
|
||||||
|
typename CaptureTimelapseFrame,
|
||||||
|
typename BindLayerFramebuffer,
|
||||||
|
typename CaptureHistoryRegion,
|
||||||
|
typename ApplyLayerDirtyRegion,
|
||||||
|
typename CopyLayerToCommitDestination,
|
||||||
|
typename BindCommitInputs,
|
||||||
|
typename ExecuteEraseComposite,
|
||||||
|
typename ExecutePaintComposite,
|
||||||
|
typename CopyCommittedToDilateSource,
|
||||||
|
typename ExecuteCommitDilate,
|
||||||
|
typename UnbindLayerFramebuffer>
|
||||||
|
[[nodiscard]] inline LegacyCanvasStrokeCommitCallbacks make_legacy_canvas_stroke_commit_callbacks(
|
||||||
|
MarkCommitStarted&& mark_commit_started,
|
||||||
|
CaptureRenderState&& capture_render_state,
|
||||||
|
PrepareRenderState&& prepare_render_state,
|
||||||
|
RestoreRenderState&& restore_render_state,
|
||||||
|
PublishHistory&& publish_history,
|
||||||
|
CaptureTimelapseFrame&& capture_timelapse_frame,
|
||||||
|
BindLayerFramebuffer&& bind_layer_framebuffer,
|
||||||
|
CaptureHistoryRegion&& capture_history_region,
|
||||||
|
ApplyLayerDirtyRegion&& apply_layer_dirty_region,
|
||||||
|
CopyLayerToCommitDestination&& copy_layer_to_commit_destination,
|
||||||
|
BindCommitInputs&& bind_commit_inputs,
|
||||||
|
ExecuteEraseComposite&& execute_erase_composite,
|
||||||
|
ExecutePaintComposite&& execute_paint_composite,
|
||||||
|
CopyCommittedToDilateSource&& copy_committed_to_dilate_source,
|
||||||
|
ExecuteCommitDilate&& execute_commit_dilate,
|
||||||
|
UnbindLayerFramebuffer&& unbind_layer_framebuffer)
|
||||||
|
{
|
||||||
|
return LegacyCanvasStrokeCommitCallbacks {
|
||||||
|
.mark_commit_started = std::forward<MarkCommitStarted>(mark_commit_started),
|
||||||
|
.capture_render_state = std::forward<CaptureRenderState>(capture_render_state),
|
||||||
|
.prepare_render_state = std::forward<PrepareRenderState>(prepare_render_state),
|
||||||
|
.restore_render_state = std::forward<RestoreRenderState>(restore_render_state),
|
||||||
|
.publish_history = std::forward<PublishHistory>(publish_history),
|
||||||
|
.capture_timelapse_frame = std::forward<CaptureTimelapseFrame>(capture_timelapse_frame),
|
||||||
|
.bind_layer_framebuffer = std::forward<BindLayerFramebuffer>(bind_layer_framebuffer),
|
||||||
|
.capture_history_region = std::forward<CaptureHistoryRegion>(capture_history_region),
|
||||||
|
.apply_layer_dirty_region = std::forward<ApplyLayerDirtyRegion>(apply_layer_dirty_region),
|
||||||
|
.copy_layer_to_commit_destination = std::forward<CopyLayerToCommitDestination>(copy_layer_to_commit_destination),
|
||||||
|
.bind_commit_inputs = std::forward<BindCommitInputs>(bind_commit_inputs),
|
||||||
|
.execute_erase_composite = std::forward<ExecuteEraseComposite>(execute_erase_composite),
|
||||||
|
.execute_paint_composite = std::forward<ExecutePaintComposite>(execute_paint_composite),
|
||||||
|
.copy_committed_to_dilate_source = std::forward<CopyCommittedToDilateSource>(copy_committed_to_dilate_source),
|
||||||
|
.execute_commit_dilate = std::forward<ExecuteCommitDilate>(execute_commit_dilate),
|
||||||
|
.unbind_layer_framebuffer = std::forward<UnbindLayerFramebuffer>(unbind_layer_framebuffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::size_t legacy_canvas_stroke_commit_step_count(
|
[[nodiscard]] inline std::size_t legacy_canvas_stroke_commit_step_count(
|
||||||
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence) noexcept
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2013,6 +2013,88 @@ void retained_stroke_commit_runner_preserves_per_face_step_order(pp::tests::Harn
|
|||||||
PP_EXPECT(h, events == expected);
|
PP_EXPECT(h, events == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void retained_stroke_commit_callback_builder_preserves_order(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto sequence = plan_canvas_stroke_commit_sequence(
|
||||||
|
CanvasStrokeCommitRequest {
|
||||||
|
.erase_mode = false,
|
||||||
|
.alpha_locked = false,
|
||||||
|
.selection_mask_active = true,
|
||||||
|
.dual_stroke_enabled = true,
|
||||||
|
.pattern_enabled = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<std::string> events;
|
||||||
|
const auto record = [&](std::string_view event, int face_index = -1) {
|
||||||
|
if (face_index >= 0) {
|
||||||
|
events.push_back(std::string(event) + ":" + std::to_string(face_index));
|
||||||
|
} else {
|
||||||
|
events.push_back(std::string(event));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto callbacks = pp::panopainter::make_legacy_canvas_stroke_commit_callbacks(
|
||||||
|
[&]() { record("start"); },
|
||||||
|
[&]() { record("capture"); },
|
||||||
|
[&]() { record("prepare"); },
|
||||||
|
[&]() { record("restore"); },
|
||||||
|
[&]() { record("publish"); },
|
||||||
|
[&]() { record("timelapse"); },
|
||||||
|
[&](int face_index) { record("bind-fbo", face_index); },
|
||||||
|
[&](int face_index) { record("history", face_index); },
|
||||||
|
[&](int face_index) { record("dirty", face_index); },
|
||||||
|
[&](int face_index) { record("copy-layer", face_index); },
|
||||||
|
[&](int face_index) { record("bind-inputs", face_index); },
|
||||||
|
[&](int face_index) { record("erase", face_index); },
|
||||||
|
[&](int face_index) { record("paint", face_index); },
|
||||||
|
[&](int face_index) { record("copy-committed", face_index); },
|
||||||
|
[&](int face_index) { record("dilate", face_index); },
|
||||||
|
[&](int face_index) { record("unbind-fbo", face_index); });
|
||||||
|
|
||||||
|
const auto result = pp::panopainter::execute_legacy_canvas_stroke_commit_sequence(
|
||||||
|
pp::panopainter::LegacyCanvasStrokeCommitRequest {
|
||||||
|
.context = "test",
|
||||||
|
.faces = {
|
||||||
|
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 0, .dirty = true },
|
||||||
|
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 1, .dirty = false },
|
||||||
|
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 2, .dirty = true },
|
||||||
|
},
|
||||||
|
.sequence = sequence,
|
||||||
|
.callbacks = callbacks,
|
||||||
|
});
|
||||||
|
|
||||||
|
const std::vector<std::string> expected {
|
||||||
|
"start",
|
||||||
|
"capture",
|
||||||
|
"prepare",
|
||||||
|
"bind-fbo:0",
|
||||||
|
"history:0",
|
||||||
|
"dirty:0",
|
||||||
|
"copy-layer:0",
|
||||||
|
"bind-inputs:0",
|
||||||
|
"paint:0",
|
||||||
|
"copy-committed:0",
|
||||||
|
"dilate:0",
|
||||||
|
"unbind-fbo:0",
|
||||||
|
"bind-fbo:2",
|
||||||
|
"history:2",
|
||||||
|
"dirty:2",
|
||||||
|
"copy-layer:2",
|
||||||
|
"bind-inputs:2",
|
||||||
|
"paint:2",
|
||||||
|
"copy-committed:2",
|
||||||
|
"dilate:2",
|
||||||
|
"unbind-fbo:2",
|
||||||
|
"restore",
|
||||||
|
"publish",
|
||||||
|
"timelapse",
|
||||||
|
};
|
||||||
|
|
||||||
|
PP_EXPECT(h, result.ok);
|
||||||
|
PP_EXPECT(h, result.committed_faces == 2);
|
||||||
|
PP_EXPECT(h, events == expected);
|
||||||
|
}
|
||||||
|
|
||||||
void retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent(pp::tests::Harness& h)
|
void retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
pp::paint_renderer::CanvasStrokeCommitSequencePlan missing_scratch;
|
pp::paint_renderer::CanvasStrokeCommitSequencePlan missing_scratch;
|
||||||
@@ -3020,6 +3102,9 @@ int main()
|
|||||||
harness.run(
|
harness.run(
|
||||||
"retained_stroke_commit_runner_preserves_per_face_step_order",
|
"retained_stroke_commit_runner_preserves_per_face_step_order",
|
||||||
retained_stroke_commit_runner_preserves_per_face_step_order);
|
retained_stroke_commit_runner_preserves_per_face_step_order);
|
||||||
|
harness.run(
|
||||||
|
"retained_stroke_commit_callback_builder_preserves_order",
|
||||||
|
retained_stroke_commit_callback_builder_preserves_order);
|
||||||
harness.run(
|
harness.run(
|
||||||
"retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent",
|
"retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent",
|
||||||
retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent);
|
retained_stroke_commit_copy_skips_missing_layer_scratch_or_invalid_extent);
|
||||||
|
|||||||
Reference in New Issue
Block a user