Share retained stroke temporary composite helper
This commit is contained in:
@@ -38,6 +38,11 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
through `execute_legacy_canvas_stroke_face_sample_polygon(...)`; the
|
through `execute_legacy_canvas_stroke_face_sample_polygon(...)`; the
|
||||||
retained sample executor owns the face-aware dispatch contract while
|
retained sample executor owns the face-aware dispatch contract while
|
||||||
`Canvas` keeps only concrete GL object callbacks.
|
`Canvas` keeps only concrete GL object callbacks.
|
||||||
|
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` non-erase
|
||||||
|
live temporary-stroke composite now routes setup, sampler bind, texture
|
||||||
|
bind, draw, and texture unbind ordering through
|
||||||
|
`execute_legacy_canvas_stroke_temporary_composite(...)`; erase-path and
|
||||||
|
broader final composite ownership remain retained in `Canvas`.
|
||||||
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::stroke_draw_mix()`
|
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::stroke_draw_mix()`
|
||||||
now routes mixer framebuffer bind/unbind, viewport/scissor/blend state,
|
now routes mixer framebuffer bind/unbind, viewport/scissor/blend state,
|
||||||
texture-slot binding, and final plane draw through one local helper;
|
texture-slot binding, and final plane draw through one local helper;
|
||||||
|
|||||||
@@ -3137,6 +3137,10 @@ Results:
|
|||||||
`execute_legacy_canvas_stroke_face_sample_polygon(...)` for face-indexed
|
`execute_legacy_canvas_stroke_face_sample_polygon(...)` for face-indexed
|
||||||
destination bind/copy/unbind and brush upload/draw dispatch, while concrete
|
destination bind/copy/unbind and brush upload/draw dispatch, while concrete
|
||||||
GL object callbacks remain in the legacy Canvas path.
|
GL object callbacks remain in the legacy Canvas path.
|
||||||
|
- `Canvas::draw_merge()` non-erase live temporary-stroke composite now shares
|
||||||
|
`execute_legacy_canvas_stroke_temporary_composite(...)` for setup, sampler
|
||||||
|
bind, texture bind, draw, and texture unbind ordering, while erase-path and
|
||||||
|
broader final composite ownership remain in the legacy Canvas path.
|
||||||
- `NodeStrokePreview::stroke_draw_mix()` now shares one local helper for mixer
|
- `NodeStrokePreview::stroke_draw_mix()` now shares one local helper for mixer
|
||||||
framebuffer bind/unbind, viewport/scissor/blend state, texture-slot
|
framebuffer bind/unbind, viewport/scissor/blend state, texture-slot
|
||||||
binding, and final plane draw, while material planning and shader uniform
|
binding, and final plane draw, while material planning and shader uniform
|
||||||
|
|||||||
@@ -509,6 +509,13 @@ Done Checks:
|
|||||||
|
|
||||||
Progress Notes:
|
Progress Notes:
|
||||||
|
|
||||||
|
- 2026-06-13: `Canvas::draw_merge()` non-erase live temporary-stroke
|
||||||
|
composite ordering now routes through
|
||||||
|
`execute_legacy_canvas_stroke_temporary_composite(...)`; erase-path and
|
||||||
|
broader final composite ownership still remain local to `Canvas`. Next slice
|
||||||
|
should target the erase temporary composite branch or another similarly
|
||||||
|
narrow final composite seam without reopening landed sample, mix, dirty, or
|
||||||
|
framebuffer helpers.
|
||||||
- 2026-06-13: `Canvas::stroke_draw_samples()` now routes face-indexed
|
- 2026-06-13: `Canvas::stroke_draw_samples()` now routes face-indexed
|
||||||
destination bind/copy/unbind and brush upload/draw through
|
destination bind/copy/unbind and brush upload/draw through
|
||||||
`execute_legacy_canvas_stroke_face_sample_polygon(...)`; the retained sample
|
`execute_legacy_canvas_stroke_face_sample_polygon(...)`; the retained sample
|
||||||
|
|||||||
113
src/canvas.cpp
113
src/canvas.cpp
@@ -1438,64 +1438,73 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SI
|
|||||||
}
|
}
|
||||||
else if (m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index)
|
else if (m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index)
|
||||||
{
|
{
|
||||||
m_sampler.bind(0);
|
|
||||||
m_sampler.bind(1);
|
|
||||||
m_sampler.bind(2);
|
|
||||||
m_sampler.bind(3);
|
|
||||||
m_sampler_stencil.bind(4);
|
|
||||||
|
|
||||||
const auto stroke_material = canvas_stroke_material_plan(*b, false);
|
const auto stroke_material = canvas_stroke_material_plan(*b, false);
|
||||||
glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
|
glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
|
||||||
if (b->m_pattern_flipx) patt_scale.x *= -1.f;
|
if (b->m_pattern_flipx) patt_scale.x *= -1.f;
|
||||||
if (b->m_pattern_flipy) patt_scale.y *= -1.f;
|
if (b->m_pattern_flipy) patt_scale.y *= -1.f;
|
||||||
|
|
||||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
pp::panopainter::execute_legacy_canvas_stroke_temporary_composite(
|
||||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
[&] {
|
||||||
.resolution = Canvas::I->m_size,
|
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||||
.pattern = {
|
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||||
.scale = patt_scale,
|
.resolution = Canvas::I->m_size,
|
||||||
.invert = static_cast<float>(b->m_pattern_invert),
|
.pattern = {
|
||||||
.brightness = b->m_pattern_brightness,
|
.scale = patt_scale,
|
||||||
.contrast = b->m_pattern_contrast,
|
.invert = static_cast<float>(b->m_pattern_invert),
|
||||||
.depth = b->m_pattern_depth,
|
.brightness = b->m_pattern_brightness,
|
||||||
.blend_mode = b->m_pattern_blend_mode,
|
.contrast = b->m_pattern_contrast,
|
||||||
.offset = Canvas::I->m_pattern_offset,
|
.depth = b->m_pattern_depth,
|
||||||
},
|
.blend_mode = b->m_pattern_blend_mode,
|
||||||
.mvp = ortho,
|
.offset = Canvas::I->m_pattern_offset,
|
||||||
.layer_alpha = m_layers[layer_index]->m_opacity,
|
},
|
||||||
.alpha_lock = m_layers[layer_index]->m_alpha_locked,
|
.mvp = ortho,
|
||||||
.mask_enabled = m_smask_active,
|
.layer_alpha = m_layers[layer_index]->m_opacity,
|
||||||
.use_fragcoord = false,
|
.alpha_lock = m_layers[layer_index]->m_alpha_locked,
|
||||||
.blend_mode = b->m_blend_mode,
|
.mask_enabled = m_smask_active,
|
||||||
.use_dual = stroke_material.composite_pass.use_dual,
|
.use_fragcoord = false,
|
||||||
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
|
.blend_mode = b->m_blend_mode,
|
||||||
.dual_alpha = stroke_material.composite_pass.dual_alpha,
|
.use_dual = stroke_material.composite_pass.use_dual,
|
||||||
.use_pattern = stroke_material.composite_pass.use_pattern,
|
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
|
||||||
|
.dual_alpha = stroke_material.composite_pass.dual_alpha,
|
||||||
|
.use_pattern = stroke_material.composite_pass.use_pattern,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
m_sampler.bind(0);
|
||||||
|
m_sampler.bind(1);
|
||||||
|
m_sampler.bind(2);
|
||||||
|
m_sampler.bind(3);
|
||||||
|
m_sampler_stencil.bind(4);
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
set_active_texture_unit(0);
|
||||||
|
m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||||
|
set_active_texture_unit(1);
|
||||||
|
m_tmp[plane_index].bindTexture();
|
||||||
|
set_active_texture_unit(2);
|
||||||
|
m_smask.rtt(plane_index).bindTexture();
|
||||||
|
set_active_texture_unit(3);
|
||||||
|
if (stroke_material.composite_pass.use_dual)
|
||||||
|
m_tmp_dual[plane_index].bindTexture();
|
||||||
|
set_active_texture_unit(4);
|
||||||
|
b->m_pattern_texture ?
|
||||||
|
b->m_pattern_texture->bind() :
|
||||||
|
unbind_texture_2d();
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
m_plane.draw_fill();
|
||||||
|
},
|
||||||
|
[&] {
|
||||||
|
set_active_texture_unit(3);
|
||||||
|
if (stroke_material.composite_pass.use_dual)
|
||||||
|
m_tmp_dual[plane_index].unbindTexture();
|
||||||
|
set_active_texture_unit(2);
|
||||||
|
m_smask.rtt(plane_index).unbindTexture();
|
||||||
|
set_active_texture_unit(1);
|
||||||
|
m_tmp[plane_index].unbindTexture();
|
||||||
|
set_active_texture_unit(0);
|
||||||
|
m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||||
});
|
});
|
||||||
|
|
||||||
set_active_texture_unit(0);
|
|
||||||
m_layers[layer_index]->rtt(plane_index).bindTexture();
|
|
||||||
set_active_texture_unit(1);
|
|
||||||
m_tmp[plane_index].bindTexture();
|
|
||||||
set_active_texture_unit(2);
|
|
||||||
m_smask.rtt(plane_index).bindTexture();
|
|
||||||
set_active_texture_unit(3);
|
|
||||||
if (stroke_material.composite_pass.use_dual)
|
|
||||||
m_tmp_dual[plane_index].bindTexture();
|
|
||||||
set_active_texture_unit(4);
|
|
||||||
b->m_pattern_texture ?
|
|
||||||
b->m_pattern_texture->bind() :
|
|
||||||
unbind_texture_2d();
|
|
||||||
m_plane.draw_fill();
|
|
||||||
set_active_texture_unit(3);
|
|
||||||
if (stroke_material.composite_pass.use_dual)
|
|
||||||
m_tmp_dual[plane_index].unbindTexture();
|
|
||||||
set_active_texture_unit(2);
|
|
||||||
m_smask.rtt(plane_index).unbindTexture();
|
|
||||||
set_active_texture_unit(1);
|
|
||||||
m_tmp[plane_index].unbindTexture();
|
|
||||||
set_active_texture_unit(0);
|
|
||||||
m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -656,6 +656,26 @@ std::size_t execute_legacy_canvas_stroke_live_pass_with_face_framebuffers(
|
|||||||
pass_dirty_faces);
|
pass_dirty_faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename SetupCompositeShader,
|
||||||
|
typename BindCompositeSamplers,
|
||||||
|
typename BindCompositeTextures,
|
||||||
|
typename DrawComposite,
|
||||||
|
typename UnbindCompositeTextures>
|
||||||
|
void execute_legacy_canvas_stroke_temporary_composite(
|
||||||
|
SetupCompositeShader&& setup_composite_shader,
|
||||||
|
BindCompositeSamplers&& bind_composite_samplers,
|
||||||
|
BindCompositeTextures&& bind_composite_textures,
|
||||||
|
DrawComposite&& draw_composite,
|
||||||
|
UnbindCompositeTextures&& unbind_composite_textures)
|
||||||
|
{
|
||||||
|
setup_composite_shader();
|
||||||
|
bind_composite_samplers();
|
||||||
|
bind_composite_textures();
|
||||||
|
draw_composite();
|
||||||
|
unbind_composite_textures();
|
||||||
|
}
|
||||||
|
|
||||||
[[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 {
|
||||||
|
|||||||
@@ -709,6 +709,27 @@ void retained_stroke_preview_texture_copy_binds_before_copy(pp::tests::Harness&
|
|||||||
PP_EXPECT(h, copy_args[5] == 64);
|
PP_EXPECT(h, copy_args[5] == 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void retained_stroke_temporary_composite_preserves_retained_call_order(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::vector<std::string> events;
|
||||||
|
|
||||||
|
pp::panopainter::execute_legacy_canvas_stroke_temporary_composite(
|
||||||
|
[&]() { events.emplace_back("setup"); },
|
||||||
|
[&]() { events.emplace_back("bind-samplers"); },
|
||||||
|
[&]() { events.emplace_back("bind-textures"); },
|
||||||
|
[&]() { events.emplace_back("draw"); },
|
||||||
|
[&]() { events.emplace_back("unbind-textures"); });
|
||||||
|
|
||||||
|
const std::vector<std::string> expected_events {
|
||||||
|
"setup",
|
||||||
|
"bind-samplers",
|
||||||
|
"bind-textures",
|
||||||
|
"draw",
|
||||||
|
"unbind-textures",
|
||||||
|
};
|
||||||
|
PP_EXPECT(h, events == expected_events);
|
||||||
|
}
|
||||||
|
|
||||||
void retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order(pp::tests::Harness& h)
|
void retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
const std::array<LegacyCanvasStrokeMixPassPlane, 4> planes {
|
const std::array<LegacyCanvasStrokeMixPassPlane, 4> planes {
|
||||||
@@ -825,6 +846,9 @@ int main()
|
|||||||
harness.run(
|
harness.run(
|
||||||
"retained_stroke_preview_texture_copy_binds_before_copy",
|
"retained_stroke_preview_texture_copy_binds_before_copy",
|
||||||
retained_stroke_preview_texture_copy_binds_before_copy);
|
retained_stroke_preview_texture_copy_binds_before_copy);
|
||||||
|
harness.run(
|
||||||
|
"retained_stroke_temporary_composite_preserves_retained_call_order",
|
||||||
|
retained_stroke_temporary_composite_preserves_retained_call_order);
|
||||||
harness.run(
|
harness.run(
|
||||||
"retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order",
|
"retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order",
|
||||||
retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order);
|
retained_stroke_mix_pass_skips_inactive_planes_and_preserves_texture_order);
|
||||||
|
|||||||
Reference in New Issue
Block a user