Share retained stroke live pass helper

This commit is contained in:
2026-06-13 10:17:47 +02:00
parent 39cc62f41f
commit bc624ceb8d
4 changed files with 58 additions and 9 deletions

View File

@@ -18,6 +18,12 @@ 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_draw` main and
dual live-pass dirty semantics now route through
`execute_legacy_canvas_stroke_live_pass_with_dirty_tracking(...)` in
`legacy_canvas_stroke_execution_services.h`; shader timing, sampler/texture
binding, framebuffer ownership, pad execution, and final OpenGL draw remain
retained in `Canvas`.
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview` final - 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview` final
composite sampler/input binding and slot intent now route through one local composite sampler/input binding and slot intent now route through one local
preview helper; mixer execution, per-sample stroke callbacks, framebuffer preview helper; mixer execution, per-sample stroke callbacks, framebuffer

View File

@@ -3093,6 +3093,11 @@ Results:
dirty tracking now share one retained stroke execution helper surface, while dirty tracking now share one retained stroke execution helper surface, while
shader timing, sampler/texture binding, framebuffer ownership, pad execution, shader timing, sampler/texture binding, framebuffer ownership, pad execution,
and final OpenGL draw ordering remain in the legacy Canvas path. and final OpenGL draw ordering remain in the legacy Canvas path.
- `Canvas::stroke_draw` main and dual live-pass dirty semantics now share one
retained helper around the face loop, current/dual dirty accumulation, and
dual-pass dirty preservation, while shader timing, sampler/texture binding,
framebuffer ownership, pad execution, and final OpenGL draw ordering remain
in the legacy Canvas path.
- `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

@@ -630,7 +630,6 @@ void Canvas::stroke_draw()
const auto cc = query_canvas_clear_color(); const auto cc = query_canvas_clear_color();
const auto& brush = m_current_stroke->m_brush; const auto& brush = m_current_stroke->m_brush;
const auto& dual_brush = m_dual_stroke->m_brush;
auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f);
apply_canvas_viewport(0, 0, m_width, m_height); apply_canvas_viewport(0, 0, m_width, m_height);
@@ -690,7 +689,7 @@ void Canvas::stroke_draw()
std::array<bool, 6> box_dirty = SIXPLETTE(false); std::array<bool, 6> box_dirty = SIXPLETTE(false);
const std::array<bool, 6> include_main_dirty = SIXPLETTE(true); const std::array<bool, 6> include_main_dirty = SIXPLETTE(true);
glm::vec4 pad_color; glm::vec4 pad_color;
pp::panopainter::execute_legacy_canvas_stroke_frame_samples_with_dirty_tracking( pp::panopainter::execute_legacy_canvas_stroke_live_pass_with_dirty_tracking(
frames, frames,
stroke_extent, stroke_extent,
std::span<glm::vec4>(m_dirty_box), std::span<glm::vec4>(m_dirty_box),
@@ -718,7 +717,6 @@ void Canvas::stroke_draw()
}); });
return stroke_draw_samples(i, P, copy_stroke_destination); return stroke_draw_samples(i, P, copy_stroke_destination);
}, },
[&](auto&, int, auto&, auto&) {},
[&](auto&, int i, auto&, glm::vec4) { [&](auto&, int i, auto&, glm::vec4) {
m_tmp[i].unbindFramebuffer(); m_tmp[i].unbindFramebuffer();
}); });
@@ -792,8 +790,9 @@ void Canvas::stroke_draw()
// DRAW DUAL BRUSH // DRAW DUAL BRUSH
if (stroke_material.dual_pass.enabled) if (stroke_material.dual_pass.enabled && m_dual_stroke)
{ {
const auto& dual_brush = m_dual_stroke->m_brush;
pp::panopainter::setup_legacy_stroke_dual_shader(stroke_material.dual_pass.uses_pattern); pp::panopainter::setup_legacy_stroke_dual_shader(stroke_material.dual_pass.uses_pattern);
set_active_texture_unit(0); set_active_texture_unit(0);
@@ -803,7 +802,7 @@ void Canvas::stroke_draw()
auto frames_dual = stroke_draw_compute(*m_dual_stroke); auto frames_dual = stroke_draw_compute(*m_dual_stroke);
const std::array<bool, 6> include_dual_dirty = const std::array<bool, 6> include_dual_dirty =
SIXPLETTE(stroke_material.composite_pass.dual_blend_mode == 0); SIXPLETTE(stroke_material.composite_pass.dual_blend_mode == 0);
pp::panopainter::execute_legacy_canvas_stroke_frame_samples_with_dirty_tracking( pp::panopainter::execute_legacy_canvas_stroke_live_pass_with_dirty_tracking(
frames_dual, frames_dual,
stroke_extent, stroke_extent,
std::span<glm::vec4>(m_dirty_box), std::span<glm::vec4>(m_dirty_box),
@@ -823,12 +822,15 @@ void Canvas::stroke_draw()
[&](auto&, int i, auto& P) { [&](auto&, int i, auto& P) {
return stroke_draw_samples(i, P, copy_stroke_destination); return stroke_draw_samples(i, P, copy_stroke_destination);
}, },
[&](auto&, int, auto&, auto& request) {
request.previous_pass_dirty_box = request.sample_dirty_box;
},
[&](auto&, int i, auto&, glm::vec4) { [&](auto&, int i, auto&, glm::vec4) {
m_tmp_dual[i].unbindFramebuffer(); m_tmp_dual[i].unbindFramebuffer();
}); },
true);
set_active_texture_unit(0);
dual_brush->m_tip_texture ?
dual_brush->m_tip_texture->unbind() :
unbind_texture_2d();
} }
m_sampler_brush.unbind(); m_sampler_brush.unbind();

View File

@@ -315,6 +315,42 @@ std::size_t execute_legacy_canvas_stroke_frame_samples_with_dirty_tracking(
return executed_faces; return executed_faces;
} }
template <typename Frames, typename BeginFrame, typename BeginFace, typename ExecuteSample, typename FinishFace>
std::size_t execute_legacy_canvas_stroke_live_pass_with_dirty_tracking(
Frames&& frames,
pp::renderer::Extent2D extent,
std::span<glm::vec4> accumulated_dirty_boxes,
std::span<glm::vec4> pass_dirty_boxes,
std::span<const bool> include_in_committed_dirty_box,
BeginFrame&& begin_frame,
BeginFace&& begin_face,
ExecuteSample&& execute_sample,
FinishFace&& finish_face,
bool preserve_sample_dirty_as_pass_dirty = false,
std::span<bool> committed_dirty_faces = {},
std::span<bool> pass_dirty_faces = {})
{
return execute_legacy_canvas_stroke_frame_samples_with_dirty_tracking(
std::forward<Frames>(frames),
extent,
accumulated_dirty_boxes,
pass_dirty_boxes,
include_in_committed_dirty_box,
std::forward<BeginFrame>(begin_frame),
std::forward<BeginFace>(begin_face),
std::forward<ExecuteSample>(execute_sample),
[&](auto&, int, auto&, auto& request) {
if (preserve_sample_dirty_as_pass_dirty) {
request.previous_pass_dirty_box = request.sample_dirty_box;
}
},
[&](auto& frame, int face_index, auto& vertices, glm::vec4 sample_dirty_box) {
finish_face(frame, face_index, vertices, sample_dirty_box);
},
committed_dirty_faces,
pass_dirty_faces);
}
[[nodiscard]] inline pp::paint_renderer::CanvasStrokeBox legacy_canvas_stroke_box(glm::vec4 box) noexcept [[nodiscard]] inline pp::paint_renderer::CanvasStrokeBox legacy_canvas_stroke_box(glm::vec4 box) noexcept
{ {
return pp::paint_renderer::CanvasStrokeBox { return pp::paint_renderer::CanvasStrokeBox {