Extract pad stroke face orchestration
This commit is contained in:
@@ -86,9 +86,10 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
`execute_legacy_canvas_stroke_main_pass_frame_callbacks(...)`; the retained
|
`execute_legacy_canvas_stroke_main_pass_frame_callbacks(...)`; the retained
|
||||||
path still owns the concrete shader, sampler, and framebuffer wiring.
|
path still owns the concrete shader, sampler, and framebuffer wiring.
|
||||||
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw()` pad-face
|
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw()` pad-face
|
||||||
orchestration remains retained and is next targeted for helper extraction;
|
orchestration now routes through
|
||||||
pad destination dispatch already routes through a retained helper, but the
|
`execute_legacy_canvas_stroke_pad_face_callbacks(...)`; the retained path
|
||||||
pad face loop and copy timing still live in `Canvas`.
|
still owns the concrete brush shape, destination dispatch, and framebuffer
|
||||||
|
wiring.
|
||||||
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw_samples()`
|
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw_samples()`
|
||||||
now routes polygon triangulation, sample-point assembly, and retained
|
now routes polygon triangulation, sample-point assembly, and retained
|
||||||
destination-copy / upload / draw helper handoff through
|
destination-copy / upload / draw helper handoff through
|
||||||
|
|||||||
@@ -954,7 +954,7 @@ ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_ex
|
|||||||
|
|
||||||
### STR-008 - Extract Pad Stroke Face Orchestration
|
### STR-008 - Extract Pad Stroke Face Orchestration
|
||||||
|
|
||||||
Status: Ready
|
Status: Done
|
||||||
Score: +1 renderer boundary and OpenGL parity
|
Score: +1 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`,
|
||||||
@@ -980,3 +980,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-008 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | pending |
|
||||||
|
|||||||
@@ -858,46 +858,42 @@ void Canvas::stroke_draw()
|
|||||||
m_tex[face_index].unbind();
|
m_tex[face_index].unbind();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
[[maybe_unused]] const auto pad_result = pp::panopainter::execute_legacy_canvas_stroke_pad_faces(
|
[[maybe_unused]] const auto pad_result = pp::panopainter::execute_legacy_canvas_stroke_pad_face_callbacks(
|
||||||
pp::panopainter::LegacyCanvasStrokePadExecutionRequest {
|
pad_faces,
|
||||||
.context = "Canvas::stroke_draw",
|
stroke_extent,
|
||||||
.extent = stroke_extent,
|
copy_stroke_destination,
|
||||||
.faces = pad_faces,
|
[&](std::span<const vertex_t> pad_quad) {
|
||||||
.copy_stroke_destination = copy_stroke_destination,
|
m_brush_shape.update_vertices(
|
||||||
.upload_pad_vertices = [&](std::span<const vertex_t> pad_quad) {
|
const_cast<vertex_t*>(pad_quad.data()),
|
||||||
m_brush_shape.update_vertices(
|
static_cast<int>(pad_quad.size()));
|
||||||
const_cast<vertex_t*>(pad_quad.data()),
|
},
|
||||||
static_cast<int>(pad_quad.size()));
|
[&](int face_index) {
|
||||||
},
|
m_tmp[face_index].bindFramebuffer();
|
||||||
.begin_face = [&](int face_index) {
|
},
|
||||||
m_tmp[face_index].bindFramebuffer();
|
[&](int face_index) {
|
||||||
},
|
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(
|
||||||
.bind_destination_texture = [&](int face_index) {
|
pad_destination_texture_binding,
|
||||||
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(
|
make_pad_destination_texture_dispatch(face_index));
|
||||||
pad_destination_texture_binding,
|
},
|
||||||
make_pad_destination_texture_dispatch(face_index));
|
[&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) {
|
||||||
},
|
copy_framebuffer_to_texture_2d(
|
||||||
.copy_framebuffer_to_destination_texture =
|
copy_region.x,
|
||||||
[&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) {
|
copy_region.y,
|
||||||
copy_framebuffer_to_texture_2d(
|
copy_region.x,
|
||||||
copy_region.x,
|
copy_region.y,
|
||||||
copy_region.y,
|
copy_region.width,
|
||||||
copy_region.x,
|
copy_region.height);
|
||||||
copy_region.y,
|
},
|
||||||
copy_region.width,
|
[&](int face_index) {
|
||||||
copy_region.height);
|
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
|
||||||
},
|
pad_destination_texture_binding,
|
||||||
.unbind_destination_texture = [&](int face_index) {
|
make_pad_destination_texture_dispatch(face_index));
|
||||||
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
|
},
|
||||||
pad_destination_texture_binding,
|
[&] {
|
||||||
make_pad_destination_texture_dispatch(face_index));
|
m_brush_shape.draw_fill();
|
||||||
},
|
},
|
||||||
.draw_pad = [&] {
|
[&](int face_index) {
|
||||||
m_brush_shape.draw_fill();
|
m_tmp[face_index].unbindFramebuffer();
|
||||||
},
|
|
||||||
.finish_face = [&](int face_index) {
|
|
||||||
m_tmp[face_index].unbindFramebuffer();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// DRAW DUAL BRUSH
|
// DRAW DUAL BRUSH
|
||||||
|
|||||||
@@ -248,6 +248,9 @@ struct LegacyCanvasStrokePadExecutionResult {
|
|||||||
std::size_t padded_faces = 0;
|
std::size_t padded_faces = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] inline LegacyCanvasStrokePadExecutionResult execute_legacy_canvas_stroke_pad_faces(
|
||||||
|
const LegacyCanvasStrokePadExecutionRequest& request);
|
||||||
|
|
||||||
struct LegacyCanvasStrokeMixPassPlane {
|
struct LegacyCanvasStrokeMixPassPlane {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
@@ -368,6 +371,35 @@ std::size_t execute_legacy_canvas_stroke_main_pass_frame_callbacks(
|
|||||||
pass_dirty_faces);
|
pass_dirty_faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Faces, typename UploadPadVertices, typename BeginFace, typename BindDestinationTexture, typename CopyFramebufferToDestinationTexture, typename UnbindDestinationTexture, typename DrawPad, typename FinishFace>
|
||||||
|
std::size_t execute_legacy_canvas_stroke_pad_face_callbacks(
|
||||||
|
Faces&& faces,
|
||||||
|
pp::renderer::Extent2D extent,
|
||||||
|
bool copy_stroke_destination,
|
||||||
|
UploadPadVertices&& upload_pad_vertices,
|
||||||
|
BeginFace&& begin_face,
|
||||||
|
BindDestinationTexture&& bind_destination_texture,
|
||||||
|
CopyFramebufferToDestinationTexture&& copy_framebuffer_to_destination_texture,
|
||||||
|
UnbindDestinationTexture&& unbind_destination_texture,
|
||||||
|
DrawPad&& draw_pad,
|
||||||
|
FinishFace&& finish_face)
|
||||||
|
{
|
||||||
|
return execute_legacy_canvas_stroke_pad_faces(
|
||||||
|
LegacyCanvasStrokePadExecutionRequest {
|
||||||
|
.context = "Canvas::stroke_draw",
|
||||||
|
.extent = extent,
|
||||||
|
.faces = std::forward<Faces>(faces),
|
||||||
|
.copy_stroke_destination = copy_stroke_destination,
|
||||||
|
.upload_pad_vertices = std::forward<UploadPadVertices>(upload_pad_vertices),
|
||||||
|
.begin_face = std::forward<BeginFace>(begin_face),
|
||||||
|
.bind_destination_texture = std::forward<BindDestinationTexture>(bind_destination_texture),
|
||||||
|
.copy_framebuffer_to_destination_texture = std::forward<CopyFramebufferToDestinationTexture>(copy_framebuffer_to_destination_texture),
|
||||||
|
.unbind_destination_texture = std::forward<UnbindDestinationTexture>(unbind_destination_texture),
|
||||||
|
.draw_pad = std::forward<DrawPad>(draw_pad),
|
||||||
|
.finish_face = std::forward<FinishFace>(finish_face),
|
||||||
|
}).padded_faces;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline LegacyCanvasStrokeDualPassResult execute_legacy_canvas_stroke_dual_pass(
|
[[nodiscard]] inline LegacyCanvasStrokeDualPassResult execute_legacy_canvas_stroke_dual_pass(
|
||||||
const LegacyCanvasStrokeDualPassRequest& request)
|
const LegacyCanvasStrokeDualPassRequest& request)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1437,6 +1437,72 @@ void retained_stroke_main_pass_frame_callbacks_preserve_order(pp::tests::Harness
|
|||||||
PP_EXPECT(h, events == expected_events);
|
PP_EXPECT(h, events == expected_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void retained_stroke_pad_face_callbacks_preserve_order(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const std::array<bool, 3> dirty_faces { true, false, true };
|
||||||
|
const std::array<glm::vec4, 3> pass_dirty_boxes {
|
||||||
|
glm::vec4(5.0F, 10.0F, 20.0F, 30.0F),
|
||||||
|
glm::vec4(0.0F, 0.0F, 0.0F, 0.0F),
|
||||||
|
glm::vec4(60.0F, 15.0F, 70.0F, 25.0F),
|
||||||
|
};
|
||||||
|
const auto faces = pp::panopainter::make_legacy_canvas_stroke_pad_faces(dirty_faces, pass_dirty_boxes);
|
||||||
|
|
||||||
|
std::vector<std::string> events;
|
||||||
|
std::vector<pp::paint_renderer::CanvasStrokeCopyRegion> copy_regions;
|
||||||
|
std::array<vertex_t, 4> uploaded_quad {};
|
||||||
|
|
||||||
|
const auto result = pp::panopainter::execute_legacy_canvas_stroke_pad_face_callbacks(
|
||||||
|
std::span<const LegacyCanvasStrokePadFace>(faces),
|
||||||
|
pp::renderer::Extent2D { .width = 100, .height = 80 },
|
||||||
|
true,
|
||||||
|
[&](std::span<const vertex_t> vertices) {
|
||||||
|
events.emplace_back("upload:" + std::to_string(vertices.size()));
|
||||||
|
std::copy(vertices.begin(), vertices.end(), uploaded_quad.begin());
|
||||||
|
},
|
||||||
|
[&](int face_index) {
|
||||||
|
events.emplace_back("begin:" + std::to_string(face_index));
|
||||||
|
},
|
||||||
|
[&](int face_index) {
|
||||||
|
events.emplace_back("bind:" + std::to_string(face_index));
|
||||||
|
},
|
||||||
|
[&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) {
|
||||||
|
events.emplace_back("copy");
|
||||||
|
copy_regions.push_back(copy_region);
|
||||||
|
},
|
||||||
|
[&](int face_index) {
|
||||||
|
events.emplace_back("unbind:" + std::to_string(face_index));
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
events.emplace_back("draw");
|
||||||
|
},
|
||||||
|
[&](int face_index) {
|
||||||
|
events.emplace_back("finish:" + std::to_string(face_index));
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, result == 2U);
|
||||||
|
const std::vector<std::string> expected_events {
|
||||||
|
"upload:4",
|
||||||
|
"begin:0",
|
||||||
|
"bind:0",
|
||||||
|
"draw",
|
||||||
|
"unbind:0",
|
||||||
|
"finish:0",
|
||||||
|
"upload:4",
|
||||||
|
"begin:2",
|
||||||
|
"bind:2",
|
||||||
|
"copy",
|
||||||
|
"draw",
|
||||||
|
"unbind:2",
|
||||||
|
"finish:2",
|
||||||
|
};
|
||||||
|
PP_EXPECT(h, events == expected_events);
|
||||||
|
PP_EXPECT(h, copy_regions.size() == 1U);
|
||||||
|
PP_EXPECT(h, faces[0].dirty);
|
||||||
|
PP_EXPECT(h, !faces[1].dirty);
|
||||||
|
PP_EXPECT(h, faces[2].dirty);
|
||||||
|
PP_EXPECT(h, uploaded_quad.size() == 4U);
|
||||||
|
}
|
||||||
|
|
||||||
void retained_stroke_pad_executor_copies_destination_for_dirty_faces_only(pp::tests::Harness& h)
|
void retained_stroke_pad_executor_copies_destination_for_dirty_faces_only(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
const std::array<bool, 3> dirty_faces { true, false, true };
|
const std::array<bool, 3> dirty_faces { true, false, true };
|
||||||
|
|||||||
Reference in New Issue
Block a user