Extract preview final composite orchestration

This commit is contained in:
2026-06-13 18:36:43 +02:00
parent 3d3a99a536
commit 87c4bee112
4 changed files with 195 additions and 65 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::draw_stroke_immediate()`
now routes final-composite setup and preview copy-back through retained
helpers in `legacy_node_stroke_preview_execution_services.h`; the retained
path still owns the concrete texture objects and pass-order wiring.
- 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::draw_stroke_immediate()` - 2026-06-13: DEBT-0036 was narrowed again. `NodeStrokePreview::draw_stroke_immediate()`
now routes main-pass texture binding through now routes main-pass texture binding through
`bind_legacy_node_stroke_preview_main_pass_textures(...)`; the retained path `bind_legacy_node_stroke_preview_main_pass_textures(...)`; the retained path

View File

@@ -6,6 +6,7 @@
#include "legacy_canvas_stroke_shader_services.h" #include "legacy_canvas_stroke_shader_services.h"
#include "legacy_canvas_stroke_services.h" #include "legacy_canvas_stroke_services.h"
#include "paint_renderer/compositor.h" #include "paint_renderer/compositor.h"
#include "texture.h"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@@ -242,6 +243,69 @@ struct LegacyNodeStrokePreviewMainPassTextureDispatch {
std::function<void()> bind_mixer; std::function<void()> bind_mixer;
}; };
struct LegacyNodeStrokePreviewFinalCompositeRequest {
glm::vec2 resolution {};
glm::vec2 pattern_scale {};
const Brush* brush = nullptr;
const pp::paint_renderer::CanvasStrokeCompositePassPlan* composite_pass = nullptr;
std::function<void()> setup_composite_shader;
std::function<void()> bind_composite_samplers;
std::function<void()> bind_composite_inputs;
std::function<void()> draw_composite;
};
[[nodiscard]] inline bool execute_legacy_node_stroke_preview_final_composite(
const LegacyNodeStrokePreviewFinalCompositeRequest& request)
{
if (!request.brush ||
!request.composite_pass ||
!request.setup_composite_shader ||
!request.bind_composite_samplers ||
!request.bind_composite_inputs ||
!request.draw_composite) {
return false;
}
pp::panopainter::execute_legacy_stroke_preview_final_composite(
[&] {
request.setup_composite_shader();
},
[&] {
request.bind_composite_samplers();
},
[&] {
request.bind_composite_inputs();
},
[&] {
request.draw_composite();
});
return true;
}
struct LegacyNodeStrokePreviewCopyResultRequest {
Texture2D* preview_texture = nullptr;
glm::vec2 size {};
std::function<void(int, int, int, int, int, int)> copy_framebuffer_to_texture;
};
[[nodiscard]] inline bool copy_legacy_node_stroke_preview_result(
const LegacyNodeStrokePreviewCopyResultRequest& request)
{
if (!request.preview_texture || !request.copy_framebuffer_to_texture) {
return false;
}
pp::panopainter::copy_legacy_stroke_preview_texture(
[&] {
request.preview_texture->bind();
},
request.copy_framebuffer_to_texture,
pp::panopainter::LegacyStrokePreviewCopySize {
.width = static_cast<int>(request.size.x),
.height = static_cast<int>(request.size.y),
});
return true;
}
[[nodiscard]] inline LegacyNodeStrokePreviewMainPassTextureDispatch make_legacy_node_stroke_preview_main_pass_texture_dispatch( [[nodiscard]] inline LegacyNodeStrokePreviewMainPassTextureDispatch make_legacy_node_stroke_preview_main_pass_texture_dispatch(
std::function<void(int)> activate_texture_unit, std::function<void(int)> activate_texture_unit,
std::function<void()> bind_brush_tip, std::function<void()> bind_brush_tip,

View File

@@ -151,8 +151,14 @@ pp::panopainter::LegacyStrokeCompositeUniforms make_stroke_preview_mix_composite
void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePassInputs& inputs) void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePassInputs& inputs)
{ {
pp::panopainter::execute_legacy_stroke_preview_final_composite( [[maybe_unused]] const bool composite_ok =
[&] { pp::panopainter::execute_legacy_node_stroke_preview_final_composite(
pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest {
.resolution = inputs.resolution,
.pattern_scale = inputs.pattern_scale,
.brush = &inputs.brush,
.composite_pass = &inputs.composite_pass,
.setup_composite_shader = [&] {
pp::panopainter::setup_legacy_stroke_composite_shader( pp::panopainter::setup_legacy_stroke_composite_shader(
pp::panopainter::LegacyStrokeCompositeUniforms { pp::panopainter::LegacyStrokeCompositeUniforms {
.resolution = inputs.resolution, .resolution = inputs.resolution,
@@ -177,14 +183,14 @@ void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePas
.use_pattern = inputs.composite_pass.use_pattern, .use_pattern = inputs.composite_pass.use_pattern,
}); });
}, },
[&] { .bind_composite_samplers = [&] {
inputs.linear_sampler.bind(stroke_preview_composite_slots::kBackground); inputs.linear_sampler.bind(stroke_preview_composite_slots::kBackground);
inputs.linear_sampler.bind(stroke_preview_composite_slots::kStroke); inputs.linear_sampler.bind(stroke_preview_composite_slots::kStroke);
inputs.linear_sampler.bind(2U); inputs.linear_sampler.bind(2U);
inputs.linear_sampler.bind(stroke_preview_composite_slots::kDual); inputs.linear_sampler.bind(stroke_preview_composite_slots::kDual);
inputs.repeat_sampler.bind(stroke_preview_composite_slots::kPattern); inputs.repeat_sampler.bind(stroke_preview_composite_slots::kPattern);
}, },
[&] { .bind_composite_inputs = [&] {
set_active_texture_unit(stroke_preview_composite_slots::kBackground); set_active_texture_unit(stroke_preview_composite_slots::kBackground);
inputs.background_texture.bind(); inputs.background_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kStroke); set_active_texture_unit(stroke_preview_composite_slots::kStroke);
@@ -196,9 +202,11 @@ void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePas
inputs.brush.m_pattern_texture->bind() : inputs.brush.m_pattern_texture->bind() :
unbind_texture_2d(); unbind_texture_2d();
}, },
[&] { .draw_composite = [&] {
inputs.draw_composite(); inputs.draw_composite();
},
}); });
assert(composite_ok);
} }
void copy_stroke_preview_framebuffer_to_texture( void copy_stroke_preview_framebuffer_to_texture(
@@ -394,11 +402,12 @@ void execute_stroke_preview_background_capture_pass(
void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2 size) void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2 size)
{ {
pp::panopainter::copy_legacy_stroke_preview_texture( [[maybe_unused]] const bool copy_ok =
[&] { pp::panopainter::copy_legacy_node_stroke_preview_result(
preview_texture.bind(); pp::panopainter::LegacyNodeStrokePreviewCopyResultRequest {
}, .preview_texture = &preview_texture,
[]( .size = size,
.copy_framebuffer_to_texture = [](
int src_x, int src_x,
int src_y, int src_y,
int dst_x, int dst_x,
@@ -407,10 +416,8 @@ void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2
int height) { int height) {
copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height);
}, },
pp::panopainter::LegacyStrokePreviewCopySize {
.width = static_cast<int>(size.x),
.height = static_cast<int>(size.y),
}); });
assert(copy_ok);
} }
} }

View File

@@ -2659,6 +2659,58 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t
}); });
} }
void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order(pp::tests::Harness& h)
{
std::vector<std::string> steps;
const bool composite_ok = pp::panopainter::execute_legacy_node_stroke_preview_final_composite(
pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest {
.resolution = glm::vec2(64.0F, 32.0F),
.pattern_scale = glm::vec2(0.25F, -0.5F),
.brush = reinterpret_cast<const Brush*>(1),
.composite_pass = reinterpret_cast<const pp::paint_renderer::CanvasStrokeCompositePassPlan*>(1),
.setup_composite_shader = [&] {
steps.emplace_back("setup");
},
.bind_composite_samplers = [&] {
steps.emplace_back("bind_samplers");
},
.bind_composite_inputs = [&] {
steps.emplace_back("bind_inputs");
},
.draw_composite = [&] {
steps.emplace_back("draw");
},
});
PP_EXPECT(h, composite_ok);
PP_EXPECT(h, steps == std::vector<std::string> {
"setup",
"bind_samplers",
"bind_inputs",
"draw",
});
steps.clear();
const bool copy_ok = pp::panopainter::copy_legacy_node_stroke_preview_result(
pp::panopainter::LegacyNodeStrokePreviewCopyResultRequest {
.preview_texture = reinterpret_cast<Texture2D*>(1),
.size = glm::vec2(32.0F, 16.0F),
.copy_framebuffer_to_texture = [&](int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
steps.emplace_back(
"copy:" +
std::to_string(src_x) + "," +
std::to_string(src_y) + "," +
std::to_string(dst_x) + "," +
std::to_string(dst_y) + "," +
std::to_string(width) + "," +
std::to_string(height));
},
});
PP_EXPECT(h, copy_ok);
PP_EXPECT(h, steps == std::vector<std::string> {
"copy:0,0,0,0,32,16",
});
}
void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs(pp::tests::Harness& h) void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs(pp::tests::Harness& h)
{ {
const auto plan = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup( const auto plan = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup(
@@ -3255,6 +3307,9 @@ int main()
harness.run( harness.run(
"legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order", "legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order",
legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order); legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order);
harness.run(
"legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order",
legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order);
harness.run( harness.run(
"legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs", "legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs",
legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs); legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs);