Extend retained stroke helper dispatch tests

This commit is contained in:
2026-06-13 10:43:29 +02:00
parent 8acf79dbda
commit 2fadfdcd3e
3 changed files with 117 additions and 0 deletions

View File

@@ -3127,6 +3127,9 @@ Results:
input binding order, sample execution destination-copy behavior, live-pass input binding order, sample execution destination-copy behavior, live-pass
face-framebuffer dirty tracking, and pad-face destination-copy behavior face-framebuffer dirty tracking, and pad-face destination-copy behavior
without depending on the broader compositor test translation unit. without depending on the broader compositor test translation unit.
- `pp_paint_renderer_stroke_execution_tests` now also covers retained texture
dispatch activation order and sampler-dispatch routing across brush tip,
destination, pattern, and mixer helper inputs.
- `Canvas::stroke_draw` pad-pass destination bind/copy/unbind ordering now - `Canvas::stroke_draw` pad-pass destination bind/copy/unbind ordering now
shares the retained stroke execution helper callback surface, while shader shares the retained stroke execution helper callback surface, while shader
setup, pad color selection, framebuffer ownership, and final OpenGL draw setup, pad color selection, framebuffer ownership, and final OpenGL draw

View File

@@ -509,6 +509,11 @@ Done Checks:
Progress Notes: Progress Notes:
- 2026-06-13: `pp_paint_renderer_stroke_execution_tests` now also covers
retained texture-dispatch activation order and sampler-dispatch routing
across brush tip, destination, pattern, and mixer helper inputs. Next test
slice should extend the dedicated lane into frame-sample loop ordering or
preview-side retained helper coverage.
- 2026-06-13: Added `pp_paint_renderer_stroke_execution_tests` as a dedicated - 2026-06-13: Added `pp_paint_renderer_stroke_execution_tests` as a dedicated
retained stroke execution-helper target covering texture-input binding order, retained stroke execution-helper target covering texture-input binding order,
sample destination-copy behavior, live-pass face-framebuffer dirty tracking, sample destination-copy behavior, live-pass face-framebuffer dirty tracking,

View File

@@ -24,7 +24,9 @@
using pp::panopainter::LegacyCanvasStrokePadExecutionRequest; using pp::panopainter::LegacyCanvasStrokePadExecutionRequest;
using pp::panopainter::LegacyCanvasStrokePadFace; using pp::panopainter::LegacyCanvasStrokePadFace;
using pp::panopainter::LegacyCanvasStrokeSamplerDispatch;
using pp::panopainter::LegacyCanvasStrokeTextureBinding; using pp::panopainter::LegacyCanvasStrokeTextureBinding;
using pp::panopainter::LegacyCanvasStrokeTextureInputDispatch;
using pp::panopainter::LegacyCanvasStrokeTextureInput; using pp::panopainter::LegacyCanvasStrokeTextureInput;
using pp::panopainter::LegacyStrokeSampleExecutionRequest; using pp::panopainter::LegacyStrokeSampleExecutionRequest;
@@ -87,6 +89,107 @@ void retained_stroke_texture_inputs_bind_and_unbind_in_declared_order(pp::tests:
} }
} }
void retained_stroke_texture_dispatch_activates_units_and_routes_per_input(pp::tests::Harness& h)
{
const std::array<LegacyCanvasStrokeTextureBinding, 4> bindings {
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::brush_tip, .slot = 2 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::stroke_destination, .slot = 0 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::pattern, .slot = 4 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::mixer, .slot = 1 },
};
std::vector<std::string> events;
const LegacyCanvasStrokeTextureInputDispatch dispatch {
.activate_texture_unit = [&](int slot) { events.emplace_back("activate:" + std::to_string(slot)); },
.bind_brush_tip = [&]() { events.emplace_back("bind:brush_tip"); },
.unbind_brush_tip = [&]() { events.emplace_back("unbind:brush_tip"); },
.bind_stroke_destination = [&]() { events.emplace_back("bind:stroke_destination"); },
.unbind_stroke_destination = [&]() { events.emplace_back("unbind:stroke_destination"); },
.bind_pattern = [&]() { events.emplace_back("bind:pattern"); },
.unbind_pattern = [&]() { events.emplace_back("unbind:pattern"); },
.bind_mixer = [&]() { events.emplace_back("bind:mixer"); },
.unbind_mixer = [&]() { events.emplace_back("unbind:mixer"); },
};
pp::panopainter::bind_legacy_canvas_stroke_texture_input(
LegacyCanvasStrokeTextureInput::brush_tip,
dispatch);
pp::panopainter::unbind_legacy_canvas_stroke_texture_input(
LegacyCanvasStrokeTextureInput::brush_tip,
dispatch);
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(bindings, dispatch);
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(bindings, dispatch);
const std::vector<std::string> expected_events {
"bind:brush_tip",
"unbind:brush_tip",
"activate:2",
"bind:brush_tip",
"activate:0",
"bind:stroke_destination",
"activate:4",
"bind:pattern",
"activate:1",
"bind:mixer",
"activate:2",
"unbind:brush_tip",
"activate:0",
"unbind:stroke_destination",
"activate:4",
"unbind:pattern",
"activate:1",
"unbind:mixer",
};
PP_EXPECT(h, events == expected_events);
}
void retained_stroke_sampler_dispatch_routes_bind_and_unbind_per_input(pp::tests::Harness& h)
{
const std::array<LegacyCanvasStrokeTextureBinding, 4> bindings {
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::brush_tip, .slot = 3 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::stroke_destination, .slot = 1 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::pattern, .slot = 7 },
LegacyCanvasStrokeTextureBinding { .input = LegacyCanvasStrokeTextureInput::mixer, .slot = 5 },
};
std::vector<std::string> events;
const LegacyCanvasStrokeSamplerDispatch dispatch {
.bind_brush_tip_sampler = [&](int slot) { events.emplace_back("bind:brush_tip:" + std::to_string(slot)); },
.unbind_brush_tip_sampler = [&]() { events.emplace_back("unbind:brush_tip"); },
.bind_stroke_destination_sampler =
[&](int slot) { events.emplace_back("bind:stroke_destination:" + std::to_string(slot)); },
.unbind_stroke_destination_sampler = [&]() { events.emplace_back("unbind:stroke_destination"); },
.bind_pattern_sampler = [&](int slot) { events.emplace_back("bind:pattern:" + std::to_string(slot)); },
.unbind_pattern_sampler = [&]() { events.emplace_back("unbind:pattern"); },
.bind_mixer_sampler = [&](int slot) { events.emplace_back("bind:mixer:" + std::to_string(slot)); },
.unbind_mixer_sampler = [&]() { events.emplace_back("unbind:mixer"); },
};
pp::panopainter::bind_legacy_canvas_stroke_sampler_input(
LegacyCanvasStrokeTextureInput::mixer,
9,
dispatch);
pp::panopainter::unbind_legacy_canvas_stroke_sampler_input(
LegacyCanvasStrokeTextureInput::mixer,
dispatch);
pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs(bindings, dispatch);
pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs(bindings, dispatch);
const std::vector<std::string> expected_events {
"bind:mixer:9",
"unbind:mixer",
"bind:brush_tip:3",
"bind:stroke_destination:1",
"bind:pattern:7",
"bind:mixer:5",
"unbind:brush_tip",
"unbind:stroke_destination",
"unbind:pattern",
"unbind:mixer",
};
PP_EXPECT(h, events == expected_events);
}
void retained_stroke_sample_executor_copies_destination_and_expands_quads(pp::tests::Harness& h) void retained_stroke_sample_executor_copies_destination_and_expands_quads(pp::tests::Harness& h)
{ {
const auto vertices = make_quad_vertices(); const auto vertices = make_quad_vertices();
@@ -369,6 +472,12 @@ int main()
harness.run( harness.run(
"retained_stroke_sample_executor_copies_destination_and_expands_quads", "retained_stroke_sample_executor_copies_destination_and_expands_quads",
retained_stroke_sample_executor_copies_destination_and_expands_quads); retained_stroke_sample_executor_copies_destination_and_expands_quads);
harness.run(
"retained_stroke_texture_dispatch_activates_units_and_routes_per_input",
retained_stroke_texture_dispatch_activates_units_and_routes_per_input);
harness.run(
"retained_stroke_sampler_dispatch_routes_bind_and_unbind_per_input",
retained_stroke_sampler_dispatch_routes_bind_and_unbind_per_input);
harness.run( harness.run(
"retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty", "retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty",
retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty); retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty);