Route stroke frame-face traversal through helper

This commit is contained in:
2026-06-13 06:42:17 +02:00
parent 6251c6d566
commit d2fb4057ab
4 changed files with 54 additions and 31 deletions

View File

@@ -18,6 +18,10 @@ 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` current and
dual stroke frame-face traversal now routes through the retained stroke
execution helper; framebuffer binding, shader uniform timing, dirty-box
mutation, sampler/texture binding, and live draw execution remain retained.
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw_compute` - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw_compute`
frame planning now routes brush-quad construction, mixer feedback bounds, frame planning now routes brush-quad construction, mixer feedback bounds,
2D/3D projection selection intent, and frame assembly through the retained 2D/3D projection selection intent, and frame assembly through the retained

View File

@@ -3087,6 +3087,10 @@ Results:
execution helper for brush-quad construction, mixer feedback bounds, 2D/3D execution helper for brush-quad construction, mixer feedback bounds, 2D/3D
projection selection intent, and frame assembly, while legacy projection projection selection intent, and frame assembly, while legacy projection
geometry, stroke samples, and live draw execution remain retained. geometry, stroke samples, and live draw execution remain retained.
- `Canvas::stroke_draw` current and dual stroke frame-face traversal now shares
the retained stroke execution helper, while framebuffer binding, shader
uniform timing, dirty-box mutation, sampler/texture binding, and live draw
execution remain retained.
- Remaining simple color, hue, color-quad, grid heightmap, and pen/line - Remaining simple color, hue, color-quad, grid heightmap, and pen/line
preview shader setup in UI nodes and canvas modes now shares retained helper preview shader setup in UI nodes and canvas modes now shares retained helper
surfaces, while geometry, texture/sampler binding, blend/depth state, surfaces, while geometry, texture/sampler binding, blend/depth state,

View File

@@ -690,24 +690,21 @@ void Canvas::stroke_draw()
std::array<glm::vec4, 6> box_face = SIXPLETTE(glm::vec4(m_size, 0, 0)); std::array<glm::vec4, 6> box_face = SIXPLETTE(glm::vec4(m_size, 0, 0));
std::array<bool, 6> box_dirty = SIXPLETTE(false); std::array<bool, 6> box_dirty = SIXPLETTE(false);
glm::vec4 pad_color; glm::vec4 pad_color;
for (auto& f : frames) pp::panopainter::execute_legacy_canvas_stroke_frame_faces(
{ frames,
if (brush->m_tip_mix > 0.f) [&](auto& f) {
{ if (brush->m_tip_mix > 0.f)
stroke_draw_mix(xy(f.m_mixer_rect), zw(f.m_mixer_rect)); {
} stroke_draw_mix(xy(f.m_mixer_rect), zw(f.m_mixer_rect));
}
for (int i = 0; i < 6; i++) },
{ [&](auto& f, int i, auto& P) {
auto& P = f.shapes[i];
if (P.size() < 3)
continue;
m_dirty_face[i] = true; m_dirty_face[i] = true;
merge_faces[i] = true; merge_faces[i] = true;
box_dirty[i] = true; box_dirty[i] = true;
m_tmp[i].bindFramebuffer(); m_tmp[i].bindFramebuffer();
pp::panopainter::use_legacy_stroke_shader(); pp::panopainter::use_legacy_stroke_shader();
pp::panopainter::apply_legacy_stroke_sample_uniforms( pp::panopainter::apply_legacy_stroke_sample_uniforms(
pp::panopainter::LegacyStrokeSampleUniforms { pp::panopainter::LegacyStrokeSampleUniforms {
@@ -718,7 +715,7 @@ void Canvas::stroke_draw()
auto box_sample = stroke_draw_samples(i, P, copy_stroke_destination); auto box_sample = stroke_draw_samples(i, P, copy_stroke_destination);
m_tmp[i].unbindFramebuffer(); m_tmp[i].unbindFramebuffer();
const auto dirty_update = pp::panopainter::plan_legacy_canvas_stroke_face_dirty_update( const auto dirty_update = pp::panopainter::plan_legacy_canvas_stroke_face_dirty_update(
pp::panopainter::LegacyCanvasStrokeFaceDirtyRequest { pp::panopainter::LegacyCanvasStrokeFaceDirtyRequest {
.extent = stroke_extent, .extent = stroke_extent,
@@ -731,8 +728,7 @@ void Canvas::stroke_draw()
box_face[i] = dirty_update.pass_dirty_box; box_face[i] = dirty_update.pass_dirty_box;
// TODO: maybe average color? // TODO: maybe average color?
pad_color = f.col; pad_color = f.col;
} });
}
set_active_texture_unit(3); set_active_texture_unit(3);
m_mixer.unbindTexture(); m_mixer.unbindTexture();
@@ -812,19 +808,17 @@ void Canvas::stroke_draw()
dual_brush->m_tip_texture->bind() : dual_brush->m_tip_texture->bind() :
unbind_texture_2d(); unbind_texture_2d();
auto frames_dual = stroke_draw_compute(*m_dual_stroke); auto frames_dual = stroke_draw_compute(*m_dual_stroke);
for (auto& f : frames_dual) pp::panopainter::execute_legacy_canvas_stroke_frame_faces(
{ frames_dual,
pp::panopainter::apply_legacy_stroke_sample_uniforms( [&](auto& f) {
pp::panopainter::LegacyStrokeSampleUniforms { pp::panopainter::apply_legacy_stroke_sample_uniforms(
.color = f.col, pp::panopainter::LegacyStrokeSampleUniforms {
.alpha = f.flow, .color = f.col,
.opacity = f.opacity, .alpha = f.flow,
}); .opacity = f.opacity,
for (int i = 0; i < 6; i++) });
{ },
auto& P = f.shapes[i]; [&](auto&, int i, auto& P) {
if (P.size() < 3)
continue;
m_tmp_dual[i].bindFramebuffer(); m_tmp_dual[i].bindFramebuffer();
auto box_sample = stroke_draw_samples(i, P, copy_stroke_destination); auto box_sample = stroke_draw_samples(i, P, copy_stroke_destination);
m_tmp_dual[i].unbindFramebuffer(); m_tmp_dual[i].unbindFramebuffer();
@@ -840,8 +834,7 @@ void Canvas::stroke_draw()
stroke_material.composite_pass.dual_blend_mode == 0, stroke_material.composite_pass.dual_blend_mode == 0,
}); });
m_dirty_box[i] = dirty_update.accumulated_dirty_box; m_dirty_box[i] = dirty_update.accumulated_dirty_box;
} });
}
} }
m_sampler_brush.unbind(); m_sampler_brush.unbind();

View File

@@ -8,6 +8,7 @@
#include "util.h" #include "util.h"
#include <array> #include <array>
#include <cstddef>
#include <functional> #include <functional>
#include <span> #include <span>
#include <string_view> #include <string_view>
@@ -152,6 +153,27 @@ template <typename ProjectStroke, typename MakeFrame>
return frames; return frames;
} }
template <typename Frames, typename BeginFrame, typename ExecuteFace>
std::size_t execute_legacy_canvas_stroke_frame_faces(
Frames&& frames,
BeginFrame&& begin_frame,
ExecuteFace&& execute_face)
{
std::size_t executed_faces = 0;
for (auto& frame : frames) {
begin_frame(frame);
for (int face_index = 0; face_index < 6; ++face_index) {
auto& vertices = frame.shapes[face_index];
if (vertices.size() < 3) {
continue;
}
execute_face(frame, face_index, vertices);
++executed_faces;
}
}
return executed_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 {