Narrow retained stroke preview execution
This commit is contained in:
@@ -18,6 +18,12 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
|
|
||||||
## Recent Reductions
|
## Recent Reductions
|
||||||
|
|
||||||
|
- 2026-06-13: DEBT-0036 preview-adapter hardening grew again.
|
||||||
|
`pp_paint_renderer_compositor_tests` now covers
|
||||||
|
`legacy_node_stroke_preview_execution_services.h` framebuffer-feedback
|
||||||
|
fallback clamping plus retained preview composite slot intent, while live
|
||||||
|
preview sample execution, mixer passes, texture binding, and final draw
|
||||||
|
ordering remain retained.
|
||||||
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::stroke_draw_compute`
|
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::stroke_draw_compute`
|
||||||
now routes preview quad frame planning through
|
now routes preview quad frame planning through
|
||||||
`legacy_canvas_stroke_execution_services.h`. Preview stroke sampling, mixer
|
`legacy_canvas_stroke_execution_services.h`. Preview stroke sampling, mixer
|
||||||
|
|||||||
@@ -3082,6 +3082,13 @@ Results:
|
|||||||
- `NodeStrokePreview::stroke_draw_compute` now shares the retained stroke
|
- `NodeStrokePreview::stroke_draw_compute` now shares the retained stroke
|
||||||
execution helper for preview quad frame planning. Preview sample execution,
|
execution helper for preview quad frame planning. Preview sample execution,
|
||||||
mixer passes, texture binding, and final draw ordering remain retained.
|
mixer passes, texture binding, and final draw ordering remain retained.
|
||||||
|
- `NodeStrokePreview` preview stroke frame sequencing now shares one retained
|
||||||
|
local executor for dual and main preview sample traversal, and
|
||||||
|
`pp_paint_renderer_compositor_tests` now covers
|
||||||
|
`legacy_node_stroke_preview_execution_services.h` feedback fallback clamping
|
||||||
|
plus retained preview composite slot intent. Preview texture binding,
|
||||||
|
framebuffer copies, mixer ownership, and final OpenGL draw ordering remain
|
||||||
|
retained.
|
||||||
- `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
|
||||||
|
|||||||
@@ -96,6 +96,25 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Frames, typename BeforeFrame, typename DrawSample>
|
||||||
|
void execute_stroke_preview_frames(
|
||||||
|
Frames& frames,
|
||||||
|
BeforeFrame&& before_frame,
|
||||||
|
DrawSample&& draw_sample)
|
||||||
|
{
|
||||||
|
for (auto& frame : frames) {
|
||||||
|
before_frame(frame);
|
||||||
|
pp::panopainter::use_legacy_stroke_shader();
|
||||||
|
pp::panopainter::apply_legacy_stroke_sample_uniforms(
|
||||||
|
pp::panopainter::LegacyStrokeSampleUniforms {
|
||||||
|
.color = frame.col,
|
||||||
|
.alpha = frame.flow,
|
||||||
|
.opacity = frame.opacity,
|
||||||
|
});
|
||||||
|
draw_sample(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
||||||
@@ -456,16 +475,14 @@ void NodeStrokePreview::draw_stroke_immediate()
|
|||||||
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, zoom);
|
auto frames_dual = stroke_draw_compute(m_dual_stroke, zoom);
|
||||||
for (auto& f : frames_dual)
|
execute_stroke_preview_frames(
|
||||||
{
|
frames_dual,
|
||||||
pp::panopainter::apply_legacy_stroke_sample_uniforms(
|
[](auto& frame) {
|
||||||
pp::panopainter::LegacyStrokeSampleUniforms {
|
frame.col = { 0, 0, 0, 1 };
|
||||||
.color = { 0, 0, 0, 1 },
|
},
|
||||||
.alpha = f.flow,
|
[&](auto& frame) {
|
||||||
.opacity = f.opacity,
|
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex_dual, copy_stroke_destination);
|
||||||
});
|
});
|
||||||
/*auto rect =*/ stroke_draw_samples(f.shapes, m_tex_dual, copy_stroke_destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy raw stroke to tex
|
// copy raw stroke to tex
|
||||||
set_active_texture_unit(1U);
|
set_active_texture_unit(1U);
|
||||||
@@ -536,24 +553,22 @@ void NodeStrokePreview::draw_stroke_immediate()
|
|||||||
preview_composite_plan.uses_mixer ? m_rtt_mixer.bindTexture() : unbind_texture_2d();
|
preview_composite_plan.uses_mixer ? m_rtt_mixer.bindTexture() : unbind_texture_2d();
|
||||||
auto frames = stroke_draw_compute(m_stroke, zoom);
|
auto frames = stroke_draw_compute(m_stroke, zoom);
|
||||||
m_rtt.clear();
|
m_rtt.clear();
|
||||||
for (auto& f : frames)
|
execute_stroke_preview_frames(
|
||||||
{
|
frames,
|
||||||
if (b->m_tip_mix > 0.f)
|
[&](auto& frame) {
|
||||||
{
|
if (b->m_tip_mix > 0.f)
|
||||||
stroke_draw_mix(xy(f.m_mixer_rect), zw(f.m_mixer_rect));
|
{
|
||||||
}
|
stroke_draw_mix(xy(frame.m_mixer_rect), zw(frame.m_mixer_rect));
|
||||||
|
}
|
||||||
|
|
||||||
pp::panopainter::use_legacy_stroke_shader();
|
frame.col = b->m_blend_mode != 0 || b->m_tip_mix > 0.f ?
|
||||||
pp::panopainter::apply_legacy_stroke_sample_uniforms(
|
glm::vec4 { .7, .4, .1, 1 } :
|
||||||
pp::panopainter::LegacyStrokeSampleUniforms {
|
glm::vec4 { 0, 0, 0, 1 };
|
||||||
.color = b->m_blend_mode != 0 || b->m_tip_mix > 0.f ?
|
frame.flow = glm::max(frame.flow, m_min_flow);
|
||||||
glm::vec4 { .7, .4, .1, 1 } /*f.col*/ :
|
},
|
||||||
glm::vec4 { 0, 0, 0, 1 } /*f.col*/,
|
[&](auto& frame) {
|
||||||
.alpha = glm::max(f.flow, m_min_flow),
|
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex, copy_stroke_destination);
|
||||||
.opacity = f.opacity,
|
});
|
||||||
});
|
|
||||||
/*auto rect =*/ stroke_draw_samples(f.shapes, m_tex, copy_stroke_destination);
|
|
||||||
}
|
|
||||||
set_active_texture_unit(3U);
|
set_active_texture_unit(3U);
|
||||||
m_rtt_mixer.unbindTexture();
|
m_rtt_mixer.unbindTexture();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "assets/image_pixels.h"
|
#include "assets/image_pixels.h"
|
||||||
#include "legacy_canvas_stroke_commit_services.h"
|
#include "legacy_canvas_stroke_commit_services.h"
|
||||||
|
#include "legacy_node_stroke_preview_execution_services.h"
|
||||||
#include "paint_renderer/compositor.h"
|
#include "paint_renderer/compositor.h"
|
||||||
#include "renderer_api/recording_renderer.h"
|
#include "renderer_api/recording_renderer.h"
|
||||||
#include "test_harness.h"
|
#include "test_harness.h"
|
||||||
@@ -2011,6 +2012,48 @@ void plans_stroke_preview_composite_with_all_retained_inputs(pp::tests::Harness&
|
|||||||
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::mixer, 3));
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::mixer, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void legacy_node_stroke_preview_feedback_adapter_clamps_invalid_extent(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto fetch = pp::panopainter::plan_legacy_node_stroke_preview_feedback(
|
||||||
|
RenderDeviceFeatures { .framebuffer_fetch = true },
|
||||||
|
32,
|
||||||
|
16);
|
||||||
|
PP_EXPECT(h, fetch.path == StrokeCompositePath::framebuffer_fetch);
|
||||||
|
PP_EXPECT(h, fetch.reads_destination_color);
|
||||||
|
PP_EXPECT(h, !fetch.requires_auxiliary_texture);
|
||||||
|
PP_EXPECT(h, !fetch.compatibility_fallback);
|
||||||
|
|
||||||
|
const auto fallback = pp::panopainter::plan_legacy_node_stroke_preview_feedback(
|
||||||
|
RenderDeviceFeatures { .texture_copy = true },
|
||||||
|
-32,
|
||||||
|
16);
|
||||||
|
PP_EXPECT(h, fallback.path == StrokeCompositePath::ping_pong_textures);
|
||||||
|
PP_EXPECT(h, !fallback.reads_destination_color);
|
||||||
|
PP_EXPECT(h, fallback.requires_auxiliary_texture);
|
||||||
|
PP_EXPECT(h, !fallback.requires_texture_copy);
|
||||||
|
PP_EXPECT(h, !fallback.requires_render_target_blit);
|
||||||
|
PP_EXPECT(h, fallback.compatibility_fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void legacy_node_stroke_preview_composite_adapter_preserves_retained_inputs(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto plan = pp::panopainter::plan_legacy_node_stroke_preview_composite(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
|
||||||
|
expect_preview_sequence(h, plan);
|
||||||
|
PP_EXPECT(h, plan.uses_mixer);
|
||||||
|
PP_EXPECT(h, plan.uses_dual);
|
||||||
|
PP_EXPECT(h, plan.uses_pattern);
|
||||||
|
PP_EXPECT(h, plan.texture_slot_count == 5U);
|
||||||
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::background, 0));
|
||||||
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::stroke, 1));
|
||||||
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::dual, 3));
|
||||||
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::pattern, 4));
|
||||||
|
PP_EXPECT(h, has_preview_texture_slot(plan, StrokePreviewTextureRole::mixer, 3));
|
||||||
|
}
|
||||||
|
|
||||||
void plans_canvas_blend_gate_from_persisted_indices(pp::tests::Harness& h)
|
void plans_canvas_blend_gate_from_persisted_indices(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
const std::vector<int> normal_layers { 0, 0, 0 };
|
const std::vector<int> normal_layers { 0, 0, 0 };
|
||||||
@@ -2450,6 +2493,12 @@ int main()
|
|||||||
harness.run(
|
harness.run(
|
||||||
"plans_stroke_preview_composite_with_all_retained_inputs",
|
"plans_stroke_preview_composite_with_all_retained_inputs",
|
||||||
plans_stroke_preview_composite_with_all_retained_inputs);
|
plans_stroke_preview_composite_with_all_retained_inputs);
|
||||||
|
harness.run(
|
||||||
|
"legacy_node_stroke_preview_feedback_adapter_clamps_invalid_extent",
|
||||||
|
legacy_node_stroke_preview_feedback_adapter_clamps_invalid_extent);
|
||||||
|
harness.run(
|
||||||
|
"legacy_node_stroke_preview_composite_adapter_preserves_retained_inputs",
|
||||||
|
legacy_node_stroke_preview_composite_adapter_preserves_retained_inputs);
|
||||||
harness.run("plans_canvas_blend_gate_from_persisted_indices", plans_canvas_blend_gate_from_persisted_indices);
|
harness.run("plans_canvas_blend_gate_from_persisted_indices", plans_canvas_blend_gate_from_persisted_indices);
|
||||||
harness.run("canvas_blend_gate_preserves_legacy_fallbacks", canvas_blend_gate_preserves_legacy_fallbacks);
|
harness.run("canvas_blend_gate_preserves_legacy_fallbacks", canvas_blend_gate_preserves_legacy_fallbacks);
|
||||||
harness.run("plans_canvas_stroke_feedback_paths", plans_canvas_stroke_feedback_paths);
|
harness.run("plans_canvas_stroke_feedback_paths", plans_canvas_stroke_feedback_paths);
|
||||||
|
|||||||
Reference in New Issue
Block a user