Narrow stroke execution planning helpers

This commit is contained in:
2026-06-13 06:28:21 +02:00
parent 493282264d
commit 13f334ae55
8 changed files with 226 additions and 35 deletions

View File

@@ -780,16 +780,16 @@ void Canvas::stroke_draw()
m_tmp[i].unbindFramebuffer();
const auto dirty_update = pp::paint_renderer::plan_canvas_stroke_face_dirty_update(
pp::paint_renderer::CanvasStrokeFaceDirtyUpdateRequest {
const auto dirty_update = pp::panopainter::plan_legacy_canvas_stroke_face_dirty_update(
pp::panopainter::LegacyCanvasStrokeFaceDirtyRequest {
.extent = stroke_extent,
.previous_accumulated_dirty_box = canvas_stroke_box(m_dirty_box[i]),
.previous_pass_dirty_box = canvas_stroke_box(box_face[i]),
.sample_dirty_box = canvas_stroke_box(box_sample),
.previous_accumulated_dirty_box = m_dirty_box[i],
.previous_pass_dirty_box = box_face[i],
.sample_dirty_box = box_sample,
.include_in_committed_dirty_box = true,
});
m_dirty_box[i] = glm_box(dirty_update.accumulated_dirty_box);
box_face[i] = glm_box(dirty_update.pass_dirty_box);
m_dirty_box[i] = dirty_update.accumulated_dirty_box;
box_face[i] = dirty_update.pass_dirty_box;
// TODO: maybe average color?
pad_color = f.col;
}
@@ -891,16 +891,16 @@ void Canvas::stroke_draw()
m_tmp_dual[i].unbindFramebuffer();
// this mode overflows the main brush boundries
const auto dirty_update = pp::paint_renderer::plan_canvas_stroke_face_dirty_update(
pp::paint_renderer::CanvasStrokeFaceDirtyUpdateRequest {
const auto dirty_update = pp::panopainter::plan_legacy_canvas_stroke_face_dirty_update(
pp::panopainter::LegacyCanvasStrokeFaceDirtyRequest {
.extent = stroke_extent,
.previous_accumulated_dirty_box = canvas_stroke_box(m_dirty_box[i]),
.previous_pass_dirty_box = canvas_stroke_box(box_sample),
.sample_dirty_box = canvas_stroke_box(box_sample),
.previous_accumulated_dirty_box = m_dirty_box[i],
.previous_pass_dirty_box = box_sample,
.sample_dirty_box = box_sample,
.include_in_committed_dirty_box =
stroke_material.composite_pass.dual_blend_mode == 0,
});
m_dirty_box[i] = glm_box(dirty_update.accumulated_dirty_box);
m_dirty_box[i] = dirty_update.accumulated_dirty_box;
}
}
}

View File

@@ -2,6 +2,7 @@
#include "paint_renderer/compositor.h"
#include <algorithm>
#include <array>
#include <functional>
#include <string_view>
@@ -45,6 +46,12 @@ struct LegacyCanvasStrokeCommitResult {
int committed_faces = 0;
};
[[nodiscard]] inline std::size_t legacy_canvas_stroke_commit_step_count(
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence) noexcept
{
return std::min(sequence.step_count, sequence.steps.size());
}
[[nodiscard]] inline bool legacy_canvas_stroke_commit_callbacks_ready(
const LegacyCanvasStrokeCommitCallbacks& callbacks) noexcept
{
@@ -85,7 +92,8 @@ struct LegacyCanvasStrokeCommitResult {
request.callbacks.bind_layer_framebuffer(face.index);
for (std::size_t step_index = 0; step_index < request.sequence.step_count; ++step_index) {
const auto step_count = legacy_canvas_stroke_commit_step_count(request.sequence);
for (std::size_t step_index = 0; step_index < step_count; ++step_index) {
switch (request.sequence.steps[step_index]) {
case pp::paint_renderer::CanvasStrokeCommitStep::readback_history_region:
request.callbacks.capture_history_region(face.index);

View File

@@ -30,6 +30,60 @@ struct LegacyStrokeSampleExecutionResult {
glm::vec4 dirty_bounds {};
};
struct LegacyCanvasStrokeFaceDirtyRequest {
pp::renderer::Extent2D extent {};
glm::vec4 previous_accumulated_dirty_box {};
glm::vec4 previous_pass_dirty_box {};
glm::vec4 sample_dirty_box {};
bool include_in_committed_dirty_box = true;
};
struct LegacyCanvasStrokeFaceDirtyResult {
glm::vec4 accumulated_dirty_box {};
glm::vec4 pass_dirty_box {};
bool has_dirty_pixels = false;
bool committed_dirty = false;
bool pass_dirty = false;
};
[[nodiscard]] inline pp::paint_renderer::CanvasStrokeBox legacy_canvas_stroke_box(glm::vec4 box) noexcept
{
return pp::paint_renderer::CanvasStrokeBox {
.min_x = box.x,
.min_y = box.y,
.max_x = box.z,
.max_y = box.w,
};
}
[[nodiscard]] inline glm::vec4 legacy_canvas_stroke_glm_box(
pp::paint_renderer::CanvasStrokeBox box) noexcept
{
return glm::vec4(box.min_x, box.min_y, box.max_x, box.max_y);
}
[[nodiscard]] inline LegacyCanvasStrokeFaceDirtyResult plan_legacy_canvas_stroke_face_dirty_update(
const LegacyCanvasStrokeFaceDirtyRequest& request) noexcept
{
const auto plan = pp::paint_renderer::plan_canvas_stroke_face_dirty_update(
pp::paint_renderer::CanvasStrokeFaceDirtyUpdateRequest {
.extent = request.extent,
.previous_accumulated_dirty_box =
legacy_canvas_stroke_box(request.previous_accumulated_dirty_box),
.previous_pass_dirty_box = legacy_canvas_stroke_box(request.previous_pass_dirty_box),
.sample_dirty_box = legacy_canvas_stroke_box(request.sample_dirty_box),
.include_in_committed_dirty_box = request.include_in_committed_dirty_box,
});
return LegacyCanvasStrokeFaceDirtyResult {
.accumulated_dirty_box = legacy_canvas_stroke_glm_box(plan.accumulated_dirty_box),
.pass_dirty_box = legacy_canvas_stroke_glm_box(plan.pass_dirty_box),
.has_dirty_pixels = plan.has_dirty_pixels,
.committed_dirty = plan.committed_dirty,
.pass_dirty = plan.pass_dirty,
};
}
[[nodiscard]] inline LegacyStrokeSampleExecutionResult execute_legacy_canvas_stroke_sample(
const LegacyStrokeSampleExecutionRequest& request)
{

View File

@@ -0,0 +1,46 @@
#pragma once
#include "paint_renderer/compositor.h"
#include "renderer_api/renderer_api.h"
#include <algorithm>
#include <cstdint>
namespace pp::panopainter {
[[nodiscard]] inline pp::paint_renderer::CanvasStrokeFeedbackPlan plan_legacy_node_stroke_preview_feedback(
pp::renderer::RenderDeviceFeatures features,
int width,
int height) noexcept
{
const auto plan = pp::paint_renderer::plan_canvas_stroke_feedback(
features,
pp::renderer::Extent2D {
.width = static_cast<std::uint32_t>(std::max(width, 0)),
.height = static_cast<std::uint32_t>(std::max(height, 0)),
});
if (plan) {
return plan.value();
}
pp::paint_renderer::CanvasStrokeFeedbackPlan fallback;
fallback.compatibility_fallback = true;
fallback.path = pp::paint_renderer::StrokeCompositePath::ping_pong_textures;
fallback.requires_auxiliary_texture = true;
return fallback;
}
[[nodiscard]] inline pp::paint_renderer::StrokePreviewCompositePlan plan_legacy_node_stroke_preview_composite(
bool uses_mixer,
bool uses_dual,
bool uses_pattern) noexcept
{
return pp::paint_renderer::plan_stroke_preview_composite(
pp::paint_renderer::StrokePreviewCompositeRequest {
.uses_mixer = uses_mixer,
.uses_dual = uses_dual,
.uses_pattern = uses_pattern,
});
}
} // namespace pp::panopainter

View File

@@ -12,11 +12,11 @@
#include "legacy_canvas_stroke_preview_services.h"
#include "legacy_canvas_stroke_shader_services.h"
#include "legacy_canvas_stroke_services.h"
#include "legacy_node_stroke_preview_execution_services.h"
#include "legacy_ui_gl_dispatch.h"
#include "paint_renderer/compositor.h"
#include "renderer_gl/opengl_capabilities.h"
#include "util.h"
#include <algorithm>
#include <array>
#include <cstdint>
@@ -31,21 +31,10 @@ pp::paint_renderer::CanvasStrokeFeedbackPlan stroke_preview_destination_feedback
int width,
int height) noexcept
{
const auto plan = pp::paint_renderer::plan_canvas_stroke_feedback(
return pp::panopainter::plan_legacy_node_stroke_preview_feedback(
stroke_preview_render_device_features(),
pp::renderer::Extent2D {
.width = static_cast<std::uint32_t>(std::max(width, 0)),
.height = static_cast<std::uint32_t>(std::max(height, 0)),
});
if (plan) {
return plan.value();
}
pp::paint_renderer::CanvasStrokeFeedbackPlan fallback;
fallback.compatibility_fallback = true;
fallback.path = pp::paint_renderer::StrokeCompositePath::ping_pong_textures;
fallback.requires_auxiliary_texture = true;
return fallback;
width,
height);
}
pp::paint_renderer::CanvasStrokeMaterialPlan stroke_preview_material_plan(
@@ -452,12 +441,10 @@ void NodeStrokePreview::draw_stroke_immediate()
const auto stroke_feedback = stroke_preview_destination_feedback_plan(m_rtt.getWidth(), m_rtt.getHeight());
const bool copy_stroke_destination = !stroke_feedback.reads_destination_color;
const auto material = stroke_preview_material_plan(*b, copy_stroke_destination);
const auto preview_composite_plan = pp::paint_renderer::plan_stroke_preview_composite(
pp::paint_renderer::StrokePreviewCompositeRequest {
.uses_mixer = b->m_tip_mix > 0.0f,
.uses_dual = material.composite_pass.use_dual,
.uses_pattern = material.composite_pass.use_pattern,
});
const auto preview_composite_plan = pp::panopainter::plan_legacy_node_stroke_preview_composite(
b->m_tip_mix > 0.0f,
material.composite_pass.use_dual,
material.composite_pass.use_pattern);
pp::panopainter::setup_legacy_stroke_shader(
pp::panopainter::LegacyStrokeShaderSetupUniforms {
.resolution = size,