Centralize canvas blend gate planning

This commit is contained in:
2026-06-03 18:20:01 +02:00
parent a89f5e6cf2
commit 1369a9048e
8 changed files with 327 additions and 86 deletions

View File

@@ -1,6 +1,9 @@
#include "pch.h"
#include <algorithm>
#include <cstdint>
#include <memory>
#include <vector>
#include "app_core/canvas_tool_ui.h"
#include "app_core/history_ui.h"
@@ -8,6 +11,7 @@
#include "log.h"
#include "node_canvas.h"
#include "node_image_texture.h"
#include "paint_renderer/compositor.h"
#include "settings.h"
#include "renderer_gl/opengl_capabilities.h"
@@ -23,6 +27,43 @@ void unbind_texture_2d()
glBindTexture(pp::renderer::gl::texture_2d_target(), 0);
}
pp::renderer::RenderDeviceFeatures node_canvas_stroke_composite_features() noexcept
{
return pp::renderer::RenderDeviceFeatures {
.framebuffer_fetch = ShaderManager::ext_framebuffer_fetch,
.texture_copy = !ShaderManager::ext_framebuffer_fetch,
};
}
bool node_canvas_needs_shader_blend(
int width,
int height,
const std::vector<std::shared_ptr<Layer>>& layers,
const Brush* brush) noexcept
{
std::vector<int> layer_blend_modes;
layer_blend_modes.reserve(layers.size());
for (const auto& layer : layers) {
if (!layer) {
continue;
}
layer_blend_modes.push_back(layer->m_blend_mode);
}
const auto plan = pp::paint_renderer::plan_canvas_blend_gate(
node_canvas_stroke_composite_features(),
pp::paint_renderer::CanvasBlendGateRequest {
.extent = pp::renderer::Extent2D {
.width = static_cast<std::uint32_t>(std::max(width, 0)),
.height = static_cast<std::uint32_t>(std::max(height, 0)),
},
.layer_blend_modes = layer_blend_modes,
.has_stroke_blend_mode = brush != nullptr,
.stroke_blend_mode = brush ? brush->m_blend_mode : 0,
});
return plan ? plan.value().shader_blend : true;
}
void run_history_undo_if_available()
{
const auto plan = pp::app::plan_history_undo(static_cast<int>(ActionManager::I.m_actions.size()));
@@ -252,14 +293,11 @@ void NodeCanvas::draw()
}
else
{
// check if any layer use blend, otherwise draw directly on main framebuffer
bool use_blend = false;
for (size_t i = 0; i < m_canvas->m_layers.size(); i++)
{
use_blend |= m_canvas->m_layers[i]->m_blend_mode != 0;
}
if (Canvas::I->m_current_stroke)
use_blend |= Canvas::I->m_current_stroke->m_brush->m_blend_mode != 0;
const bool use_blend = node_canvas_needs_shader_blend(
m_cache_rtt.getWidth(),
m_cache_rtt.getHeight(),
m_canvas->m_layers,
m_canvas->m_current_stroke ? m_canvas->m_current_stroke->m_brush.get() : nullptr);
if (use_blend)
{