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
face-framebuffer dirty tracking, and pad-face destination-copy behavior
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
shares the retained stroke execution helper callback surface, while shader
setup, pad color selection, framebuffer ownership, and final OpenGL draw

View File

@@ -509,6 +509,11 @@ Done Checks:
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
retained stroke execution-helper target covering texture-input binding order,
sample destination-copy behavior, live-pass face-framebuffer dirty tracking,

View File

@@ -24,7 +24,9 @@
using pp::panopainter::LegacyCanvasStrokePadExecutionRequest;
using pp::panopainter::LegacyCanvasStrokePadFace;
using pp::panopainter::LegacyCanvasStrokeSamplerDispatch;
using pp::panopainter::LegacyCanvasStrokeTextureBinding;
using pp::panopainter::LegacyCanvasStrokeTextureInputDispatch;
using pp::panopainter::LegacyCanvasStrokeTextureInput;
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)
{
const auto vertices = make_quad_vertices();
@@ -369,6 +472,12 @@ int main()
harness.run(
"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(
"retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty",
retained_stroke_sample_executor_unbinds_and_skips_draw_when_bounds_are_empty);