Extract preview final composite orchestration
This commit is contained in:
@@ -18,6 +18,10 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
|
||||
## 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()`
|
||||
now routes main-pass texture binding through
|
||||
`bind_legacy_node_stroke_preview_main_pass_textures(...)`; the retained path
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "legacy_canvas_stroke_shader_services.h"
|
||||
#include "legacy_canvas_stroke_services.h"
|
||||
#include "paint_renderer/compositor.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -242,6 +243,69 @@ struct LegacyNodeStrokePreviewMainPassTextureDispatch {
|
||||
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(
|
||||
std::function<void(int)> activate_texture_unit,
|
||||
std::function<void()> bind_brush_tip,
|
||||
|
||||
@@ -151,54 +151,62 @@ pp::panopainter::LegacyStrokeCompositeUniforms make_stroke_preview_mix_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();
|
||||
});
|
||||
[[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::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,
|
||||
});
|
||||
},
|
||||
.bind_composite_samplers = [&] {
|
||||
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);
|
||||
},
|
||||
.bind_composite_inputs = [&] {
|
||||
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();
|
||||
},
|
||||
.draw_composite = [&] {
|
||||
inputs.draw_composite();
|
||||
},
|
||||
});
|
||||
assert(composite_ok);
|
||||
}
|
||||
|
||||
void copy_stroke_preview_framebuffer_to_texture(
|
||||
@@ -394,23 +402,22 @@ void execute_stroke_preview_background_capture_pass(
|
||||
|
||||
void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2 size)
|
||||
{
|
||||
pp::panopainter::copy_legacy_stroke_preview_texture(
|
||||
[&] {
|
||||
preview_texture.bind();
|
||||
},
|
||||
[](
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int 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),
|
||||
});
|
||||
[[maybe_unused]] const bool copy_ok =
|
||||
pp::panopainter::copy_legacy_node_stroke_preview_result(
|
||||
pp::panopainter::LegacyNodeStrokePreviewCopyResultRequest {
|
||||
.preview_texture = &preview_texture,
|
||||
.size = size,
|
||||
.copy_framebuffer_to_texture = [](
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height) {
|
||||
copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height);
|
||||
},
|
||||
});
|
||||
assert(copy_ok);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
const auto plan = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup(
|
||||
@@ -3255,6 +3307,9 @@ int main()
|
||||
harness.run(
|
||||
"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(
|
||||
"legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs",
|
||||
legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs);
|
||||
|
||||
Reference in New Issue
Block a user