diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 55c24e8..b66b6f8 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -201,6 +201,10 @@ agent or engineer to remove them without reconstructing context from chat. `execute_legacy_canvas_draw_merge_layer_texture(...)`; per-plane iteration, temporary-stroke branch selection, and concrete layer RTT ownership remain in the legacy Canvas path. +- 2026-06-14: DEBT-0036 was narrowed again. `NodeStrokePreview::stroke_draw_mix()` + now routes the mix-pass execution request through + `make_stroke_draw_mix_execution_request(...)`; the retained path still owns + the concrete framebuffer, viewport, and draw ordering. - 2026-06-13: DEBT-0036 was narrowed again. `Canvas::draw_merge()` temporary composite setup now routes through `execute_canvas_draw_merge_temporary_composite(...)`; setup, sampler, texture, draw, and unbind callbacks still remain retained in diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index ee6fbc2..fb7e6d7 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -1870,7 +1870,7 @@ ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_ex ### STR-041 - Extract Preview Mix Pass Execution Ownership -Status: Ready +Status: Done Score: no score movement Debt: `DEBT-0036` Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp` @@ -1881,6 +1881,8 @@ Move the remaining `NodeStrokePreview::stroke_draw_mix()` execution ownership into a retained helper so the callsite keeps only the structural mix-pass orchestration. +Closeout: `cf859cd4` + Done Checks: - `NodeStrokePreview::stroke_draw_mix()` no longer owns the mix-pass execution diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index 0585aea..e2b22a0 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -514,64 +514,11 @@ void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2 make_stroke_preview_mix_pass_request(*b, m_size)); gl_state gl; [[maybe_unused]] const bool mix_ok = pp::panopainter::execute_legacy_node_stroke_preview_mix_pass( - pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest { - .shader = mix_pass.shader, - .mixer_width = m_rtt_mixer.getWidth(), - .mixer_height = m_rtt_mixer.getHeight(), - .scissor_x = static_cast(bb_min.x), - .scissor_y = static_cast(bb_min.y), - .scissor_width = static_cast(bb_sz.x), - .scissor_height = static_cast(bb_sz.y), - .save_state = [&] { - gl.save(); - }, - .setup_mix_shader = [&](const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader_plan) { - pp::panopainter::setup_legacy_stroke_composite_shader( - make_stroke_preview_mix_composite_uniforms(shader_plan)); - }, - .bind_mixer_framebuffer = [&] { - m_rtt_mixer.bindFramebuffer(); - }, - .configure_mix_target_state = [&]( - int mixer_width, - int mixer_height, - int scissor_x, - int scissor_y, - int scissor_width, - int scissor_height) { - apply_stroke_preview_viewport(0, 0, mixer_width, mixer_height); - apply_stroke_preview_capability(pp::renderer::gl::depth_test_state(), false); - apply_stroke_preview_capability(pp::renderer::gl::scissor_test_state(), true); - apply_stroke_preview_capability(pp::renderer::gl::blend_state(), false); - apply_stroke_preview_scissor( - scissor_x, - scissor_y, - scissor_width, - scissor_height); - }, - .bind_mix_inputs = [&] { - m_sampler_linear.bind(stroke_preview_composite_slots::kBackground); - set_active_texture_unit(stroke_preview_composite_slots::kBackground); - m_tex_background.bind(); - set_active_texture_unit(stroke_preview_composite_slots::kStroke); - m_rtt.bindTexture(); - set_active_texture_unit(stroke_preview_composite_slots::kDual); - m_tex_dual.bind(); - set_active_texture_unit(stroke_preview_composite_slots::kPattern); - b->m_pattern_texture ? - b->m_pattern_texture->bind() : - unbind_texture_2d(); - }, - .draw_mix = [&] { - m_plane.draw_fill(); - }, - .unbind_mixer_framebuffer = [&] { - m_rtt_mixer.unbindFramebuffer(); - }, - .restore_state = [&] { - gl.restore(); - }, - }); + make_stroke_draw_mix_execution_request( + mix_pass, + gl, + bb_min, + bb_sz)); assert(mix_ok); } @@ -931,6 +878,73 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( }; } +pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest +NodeStrokePreview::make_stroke_draw_mix_execution_request( + const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan& mix_pass, + gl_state& gl, + const glm::vec2& bb_min, + const glm::vec2& bb_sz) +{ + return pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest { + .shader = mix_pass.shader, + .mixer_width = m_rtt_mixer.getWidth(), + .mixer_height = m_rtt_mixer.getHeight(), + .scissor_x = static_cast(bb_min.x), + .scissor_y = static_cast(bb_min.y), + .scissor_width = static_cast(bb_sz.x), + .scissor_height = static_cast(bb_sz.y), + .save_state = [&] { + gl.save(); + }, + .setup_mix_shader = [&](const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader_plan) { + pp::panopainter::setup_legacy_stroke_composite_shader( + make_stroke_preview_mix_composite_uniforms(shader_plan)); + }, + .bind_mixer_framebuffer = [&] { + m_rtt_mixer.bindFramebuffer(); + }, + .configure_mix_target_state = [&]( + int mixer_width, + int mixer_height, + int scissor_x, + int scissor_y, + int scissor_width, + int scissor_height) { + apply_stroke_preview_viewport(0, 0, mixer_width, mixer_height); + apply_stroke_preview_capability(pp::renderer::gl::depth_test_state(), false); + apply_stroke_preview_capability(pp::renderer::gl::scissor_test_state(), true); + apply_stroke_preview_capability(pp::renderer::gl::blend_state(), false); + apply_stroke_preview_scissor( + scissor_x, + scissor_y, + scissor_width, + scissor_height); + }, + .bind_mix_inputs = [&] { + m_sampler_linear.bind(stroke_preview_composite_slots::kBackground); + set_active_texture_unit(stroke_preview_composite_slots::kBackground); + m_tex_background.bind(); + set_active_texture_unit(stroke_preview_composite_slots::kStroke); + m_rtt.bindTexture(); + set_active_texture_unit(stroke_preview_composite_slots::kDual); + m_tex_dual.bind(); + set_active_texture_unit(stroke_preview_composite_slots::kPattern); + m_brush->m_pattern_texture ? + m_brush->m_pattern_texture->bind() : + unbind_texture_2d(); + }, + .draw_mix = [&] { + m_plane.draw_fill(); + }, + .unbind_mixer_framebuffer = [&] { + m_rtt_mixer.unbindFramebuffer(); + }, + .restore_state = [&] { + gl.restore(); + }, + }; +} + Image NodeStrokePreview::render_to_image() { std::lock_guard _lock(s_render_mutex); diff --git a/src/node_stroke_preview.h b/src/node_stroke_preview.h index f159b55..9f0ad6b 100644 --- a/src/node_stroke_preview.h +++ b/src/node_stroke_preview.h @@ -73,6 +73,11 @@ public: bool copy_stroke_destination, float zoom, const glm::vec2& size); + pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest make_stroke_draw_mix_execution_request( + const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan& mix_pass, + gl_state& gl, + const glm::vec2& bb_min, + const glm::vec2& bb_sz); void draw_stroke(); void draw_stroke_immediate(); Image render_to_image();