Lock stroke mix shell coverage
This commit is contained in:
@@ -89,6 +89,9 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
- 2026-06-13: `LATER-003` was narrowed again. The retained stroke mix shell
|
- 2026-06-13: `LATER-003` was narrowed again. The retained stroke mix shell
|
||||||
now has direct executor regression coverage in
|
now has direct executor regression coverage in
|
||||||
`retained_stroke_mix_pass_shell_builder_preserves_combined_wiring`.
|
`retained_stroke_mix_pass_shell_builder_preserves_combined_wiring`.
|
||||||
|
- 2026-06-13: `LATER-003` was narrowed again. The retained stroke mix shell
|
||||||
|
now also has isolated executor regression coverage in
|
||||||
|
`retained_stroke_mix_pass_shell_executor_preserves_combined_wiring`.
|
||||||
- 2026-06-13: `DEBT-0036` was narrowed again. `NodeStrokePreview::draw_stroke_immediate()`
|
- 2026-06-13: `DEBT-0036` was narrowed again. `NodeStrokePreview::draw_stroke_immediate()`
|
||||||
now routes final composite execution and preview copy-back through a retained
|
now routes final composite execution and preview copy-back through a retained
|
||||||
local wrapper, leaving the call site with only sequence wiring.
|
local wrapper, leaving the call site with only sequence wiring.
|
||||||
|
|||||||
@@ -632,6 +632,9 @@ Progress Notes:
|
|||||||
- 2026-06-13: `retained_stroke_mix_pass_shell_builder_preserves_combined_wiring`
|
- 2026-06-13: `retained_stroke_mix_pass_shell_builder_preserves_combined_wiring`
|
||||||
now also exercises the direct shell executor path, locking the combined mix
|
now also exercises the direct shell executor path, locking the combined mix
|
||||||
shell boundary with call-order regression coverage.
|
shell boundary with call-order regression coverage.
|
||||||
|
- 2026-06-13: `retained_stroke_mix_pass_shell_executor_preserves_combined_wiring`
|
||||||
|
now covers the direct shell executor path separately, keeping the shell
|
||||||
|
boundary regression isolated from the builder coverage.
|
||||||
- 2026-06-13: `Canvas::stroke_draw_samples()` now reuses a retained destination
|
- 2026-06-13: `Canvas::stroke_draw_samples()` now reuses a retained destination
|
||||||
texture dispatch helper for the live sample path; `Canvas` still owns the
|
texture dispatch helper for the live sample path; `Canvas` still owns the
|
||||||
concrete face textures and callback execution.
|
concrete face textures and callback execution.
|
||||||
|
|||||||
@@ -386,63 +386,43 @@ void Canvas::stroke_cancel()
|
|||||||
m_current_stroke = nullptr;
|
m_current_stroke = nullptr;
|
||||||
m_show_tmp = false;
|
m_show_tmp = false;
|
||||||
}
|
}
|
||||||
static void execute_canvas_stroke_mix_pass(
|
void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
||||||
Canvas& canvas,
|
|
||||||
const glm::vec2& bb_min,
|
|
||||||
const glm::vec2& bb_sz,
|
|
||||||
const std::array<glm::mat4, 6>& plane_transform,
|
|
||||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
|
||||||
std::size_t layer_index,
|
|
||||||
const Stroke* current_stroke)
|
|
||||||
{
|
{
|
||||||
auto& current_layer = *layers[layer_index];
|
gl_state gl;
|
||||||
|
gl.save();
|
||||||
|
const auto layer_index = m_current_layer_idx;
|
||||||
|
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)) * canvas.m_proj * canvas.m_mv,
|
glm::scale(glm::vec3(1, -1, 1)) * m_proj * m_mv,
|
||||||
plane_transform,
|
plane_transform,
|
||||||
[&](int plane_index) {
|
[&](int plane_index) {
|
||||||
return current_layer.face(plane_index);
|
return current_layer.face(plane_index);
|
||||||
});
|
});
|
||||||
const auto& b = current_stroke->m_brush;
|
|
||||||
const auto mix_shell = pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell(
|
const auto mix_shell = pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell(
|
||||||
[&] {
|
[&] {
|
||||||
canvas.m_mixer.bindFramebuffer();
|
m_mixer.bindFramebuffer();
|
||||||
canvas.apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight());
|
apply_canvas_viewport(0, 0, m_mixer.getWidth(), m_mixer.getHeight());
|
||||||
canvas.apply_canvas_capability(canvas.depth_test_state(), false);
|
apply_canvas_capability(depth_test_state(), false);
|
||||||
canvas.apply_canvas_capability(canvas.scissor_test_state(), true);
|
apply_canvas_capability(scissor_test_state(), true);
|
||||||
canvas.apply_canvas_capability(canvas.blend_state(), false);
|
apply_canvas_capability(blend_state(), false);
|
||||||
canvas.apply_canvas_scissor(
|
apply_canvas_scissor(
|
||||||
static_cast<std::int32_t>(bb_min.x),
|
static_cast<std::int32_t>(bb_min.x),
|
||||||
static_cast<std::int32_t>(bb_min.y),
|
static_cast<std::int32_t>(bb_min.y),
|
||||||
static_cast<std::int32_t>(bb_sz.x),
|
static_cast<std::int32_t>(bb_sz.x),
|
||||||
static_cast<std::int32_t>(bb_sz.y));
|
static_cast<std::int32_t>(bb_sz.y));
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
canvas.m_mixer.unbindFramebuffer();
|
m_mixer.unbindFramebuffer();
|
||||||
});
|
});
|
||||||
[[maybe_unused]] const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell(
|
[[maybe_unused]] const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell(
|
||||||
mix_shell.setup.begin,
|
mix_shell.setup.begin,
|
||||||
mix_shell.setup.end,
|
mix_shell.setup.end,
|
||||||
mix_shell.request);
|
mix_shell.request);
|
||||||
(void)mix_planes;
|
(void)mix_planes;
|
||||||
(void)b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
|
||||||
{
|
|
||||||
gl_state gl;
|
|
||||||
gl.save();
|
|
||||||
std::array<glm::mat4, 6> plane_transform {};
|
|
||||||
std::copy(std::begin(m_plane_transform), std::end(m_plane_transform), plane_transform.begin());
|
|
||||||
execute_canvas_stroke_mix_pass(
|
|
||||||
*this,
|
|
||||||
bb_min,
|
|
||||||
bb_sz,
|
|
||||||
plane_transform,
|
|
||||||
m_layers,
|
|
||||||
m_current_layer_idx,
|
|
||||||
m_current_stroke);
|
|
||||||
|
|
||||||
gl.restore();
|
gl.restore();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1959,15 +1959,6 @@ void retained_stroke_mix_pass_shell_builder_preserves_combined_wiring(pp::tests:
|
|||||||
shell.request.unbind_mix_samplers();
|
shell.request.unbind_mix_samplers();
|
||||||
shell.setup.end();
|
shell.setup.end();
|
||||||
|
|
||||||
events.clear();
|
|
||||||
shell.setup.begin();
|
|
||||||
const auto shell_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell(
|
|
||||||
shell.setup.begin,
|
|
||||||
shell.setup.end,
|
|
||||||
shell.request);
|
|
||||||
PP_EXPECT(h, shell_result.ok);
|
|
||||||
PP_EXPECT(h, shell_result.composed_planes == 1U);
|
|
||||||
|
|
||||||
const std::vector<std::string> expected_events {
|
const std::vector<std::string> expected_events {
|
||||||
"begin",
|
"begin",
|
||||||
"bind-samplers",
|
"bind-samplers",
|
||||||
@@ -1985,6 +1976,68 @@ void retained_stroke_mix_pass_shell_builder_preserves_combined_wiring(pp::tests:
|
|||||||
PP_EXPECT(h, events == expected_events);
|
PP_EXPECT(h, events == expected_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void retained_stroke_mix_pass_shell_executor_preserves_combined_wiring(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const std::array<LegacyCanvasStrokeMixPassPlane, 1> planes {
|
||||||
|
LegacyCanvasStrokeMixPassPlane { .index = 5, .visible = true, .has_target = true, .opacity = 0.5F },
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> events;
|
||||||
|
const auto shell = pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell(
|
||||||
|
[&] { events.emplace_back("begin"); },
|
||||||
|
[&] { events.emplace_back("end"); },
|
||||||
|
"mix-shell-executor",
|
||||||
|
glm::vec2(32.0F, 16.0F),
|
||||||
|
planes,
|
||||||
|
[&] { events.emplace_back("bind-samplers"); },
|
||||||
|
[&] { events.emplace_back("unbind-samplers"); },
|
||||||
|
[&](int plane_index, const glm::mat4&) {
|
||||||
|
events.emplace_back("setup:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("bind-layer:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("bind-stroke:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("bind-mask:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&] { events.emplace_back("draw"); },
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("unbind-mask:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("unbind-stroke:" + std::to_string(plane_index));
|
||||||
|
},
|
||||||
|
[&](int plane_index) {
|
||||||
|
events.emplace_back("unbind-layer:" + std::to_string(plane_index));
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto shell_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell(
|
||||||
|
shell.setup.begin,
|
||||||
|
shell.setup.end,
|
||||||
|
shell.request);
|
||||||
|
|
||||||
|
PP_EXPECT(h, shell_result.ok);
|
||||||
|
PP_EXPECT(h, shell_result.composed_planes == 1U);
|
||||||
|
const std::vector<std::string> expected_events {
|
||||||
|
"begin",
|
||||||
|
"bind-samplers",
|
||||||
|
"setup:5",
|
||||||
|
"bind-layer:5",
|
||||||
|
"bind-stroke:5",
|
||||||
|
"bind-mask:5",
|
||||||
|
"draw",
|
||||||
|
"unbind-mask:5",
|
||||||
|
"unbind-stroke:5",
|
||||||
|
"unbind-layer:5",
|
||||||
|
"unbind-samplers",
|
||||||
|
"end",
|
||||||
|
};
|
||||||
|
PP_EXPECT(h, events == expected_events);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -2098,5 +2151,8 @@ int main()
|
|||||||
harness.run(
|
harness.run(
|
||||||
"retained_stroke_mix_pass_shell_builder_preserves_combined_wiring",
|
"retained_stroke_mix_pass_shell_builder_preserves_combined_wiring",
|
||||||
retained_stroke_mix_pass_shell_builder_preserves_combined_wiring);
|
retained_stroke_mix_pass_shell_builder_preserves_combined_wiring);
|
||||||
|
harness.run(
|
||||||
|
"retained_stroke_mix_pass_shell_executor_preserves_combined_wiring",
|
||||||
|
retained_stroke_mix_pass_shell_executor_preserves_combined_wiring);
|
||||||
return harness.finish();
|
return harness.finish();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user