Extract stroke preview final composite helper

This commit is contained in:
2026-06-13 10:13:53 +02:00
parent f1f0dd5d03
commit 39cc62f41f
3 changed files with 94 additions and 47 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. `NodeStrokePreview` final
composite sampler/input binding and slot intent now route through one local
preview helper; mixer execution, per-sample stroke callbacks, framebuffer
copies, and final OpenGL draw ownership remain retained in the preview node.
- 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw` pad-pass - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::stroke_draw` pad-pass
destination bind/copy/unbind ordering now routes through destination bind/copy/unbind ordering now routes through
`legacy_canvas_stroke_execution_services.h`; shader setup, pad color `legacy_canvas_stroke_execution_services.h`; shader setup, pad color

View File

@@ -3097,6 +3097,10 @@ Results:
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
remain in the legacy Canvas path. remain in the legacy Canvas path.
- `NodeStrokePreview` final composite sampler/input binding and texture-slot
intent now share one local retained helper, while mixer execution,
per-sample stroke callbacks, framebuffer copies, and final OpenGL draw
ownership remain in the preview node.
- `Canvas::stroke_draw` pad-region planning now shares the retained stroke - `Canvas::stroke_draw` pad-region planning now shares the retained stroke
execution helper wrapping `pp_paint_renderer`, while pad color selection, execution helper wrapping `pp_paint_renderer`, while pad color selection,
dirty-face iteration, framebuffer copies, quad upload, and draw execution dirty-face iteration, framebuffer copies, quad upload, and draw execution

View File

@@ -96,6 +96,78 @@ void apply_stroke_preview_capability(std::uint32_t state, bool enabled)
pp::legacy::ui_gl::set_capability(state, enabled, "NodeStrokePreview"); pp::legacy::ui_gl::set_capability(state, enabled, "NodeStrokePreview");
} }
namespace stroke_preview_composite_slots {
constexpr std::uint32_t kBackground = 0U;
constexpr std::uint32_t kStroke = 1U;
constexpr std::uint32_t kDual = 3U;
constexpr std::uint32_t kPattern = 4U;
}
struct StrokePreviewCompositePassInputs {
glm::vec2 resolution;
glm::vec2 pattern_scale;
const Brush& brush;
const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass;
Texture2D& background_texture;
Texture2D& stroke_texture;
Texture2D& dual_texture;
Sampler& linear_sampler;
Sampler& repeat_sampler;
std::function<void()> draw_composite;
};
void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePassInputs& inputs)
{
pp::panopainter::execute_legacy_stroke_preview_final_composite(
[&] {
pp::panopainter::setup_legacy_stroke_composite_shader(
pp::panopainter::LegacyStrokeCompositeUniforms {
.resolution = inputs.resolution,
.pattern = {
.scale = inputs.pattern_scale,
.invert = static_cast<float>(inputs.brush.m_pattern_invert),
.brightness = inputs.brush.m_pattern_brightness,
.contrast = inputs.brush.m_pattern_contrast,
.depth = inputs.brush.m_pattern_depth,
.blend_mode = inputs.composite_pass.pattern_blend_mode,
.offset = glm::vec2(inputs.brush.m_pattern_rand_offset ? 0.5f : 0.0f),
},
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
.layer_alpha = 1.0f,
.alpha_lock = false,
.mask_enabled = false,
.use_fragcoord = false,
.blend_mode = inputs.brush.m_blend_mode,
.use_dual = inputs.composite_pass.use_dual,
.dual_blend_mode = inputs.composite_pass.dual_blend_mode,
.dual_alpha = inputs.composite_pass.dual_alpha,
.use_pattern = inputs.composite_pass.use_pattern,
});
},
[&] {
inputs.linear_sampler.bind(stroke_preview_composite_slots::kBackground);
inputs.linear_sampler.bind(stroke_preview_composite_slots::kStroke);
inputs.linear_sampler.bind(2U);
inputs.linear_sampler.bind(stroke_preview_composite_slots::kDual);
inputs.repeat_sampler.bind(stroke_preview_composite_slots::kPattern);
},
[&] {
set_active_texture_unit(stroke_preview_composite_slots::kBackground);
inputs.background_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kStroke);
inputs.stroke_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kDual);
inputs.dual_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kPattern);
inputs.brush.m_pattern_texture ?
inputs.brush.m_pattern_texture->bind() :
unbind_texture_2d();
},
[&] {
inputs.draw_composite();
});
}
template <typename Frames, typename BeforeFrame, typename DrawSample> template <typename Frames, typename BeforeFrame, typename DrawSample>
void execute_stroke_preview_frames( void execute_stroke_preview_frames(
Frames& frames, Frames& frames,
@@ -585,53 +657,20 @@ void NodeStrokePreview::draw_stroke_immediate()
// COMPOSITE // COMPOSITE
pp::panopainter::execute_legacy_stroke_preview_final_composite( execute_stroke_preview_final_composite_pass(
[&] { StrokePreviewCompositePassInputs {
pp::panopainter::setup_legacy_stroke_composite_shader( .resolution = size,
pp::panopainter::LegacyStrokeCompositeUniforms { .pattern_scale = patt_scale,
.resolution = size, .brush = *b,
.pattern = { .composite_pass = material.composite_pass,
.scale = patt_scale, .background_texture = m_tex_background,
.invert = static_cast<float>(b->m_pattern_invert), .stroke_texture = m_tex,
.brightness = b->m_pattern_brightness, .dual_texture = m_tex_dual,
.contrast = b->m_pattern_contrast, .linear_sampler = m_sampler_linear,
.depth = b->m_pattern_depth, .repeat_sampler = m_sampler_linear_repeat,
.blend_mode = material.composite_pass.pattern_blend_mode, .draw_composite = [&] {
.offset = glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f), m_plane.draw_fill();
}, },
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
.layer_alpha = 1.0f,
.alpha_lock = false,
.mask_enabled = false,
.use_fragcoord = false,
.blend_mode = b->m_blend_mode,
.use_dual = material.composite_pass.use_dual,
.dual_blend_mode = material.composite_pass.dual_blend_mode,
.dual_alpha = material.composite_pass.dual_alpha,
.use_pattern = material.composite_pass.use_pattern,
});
},
[&] {
m_sampler_linear.bind(0);
m_sampler_linear.bind(1);
m_sampler_linear.bind(2);
m_sampler_linear.bind(3);
m_sampler_linear_repeat.bind(4);
},
[&] {
set_active_texture_unit(0U);
m_tex_background.bind();
set_active_texture_unit(1U);
m_tex.bind();
set_active_texture_unit(3U);
m_tex_dual.bind();
set_active_texture_unit(4U);
b->m_pattern_texture ?
b->m_pattern_texture->bind() :
unbind_texture_2d();
},
[&] {
m_plane.draw_fill();
}); });
// copy the result to the actual preview // copy the result to the actual preview