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

@@ -10,9 +10,11 @@ using pp::paint::BlendMode;
using pp::paint::Rgba;
using pp::paint::StrokeBlendMode;
using pp::paint_renderer::LayerCompositeView;
using pp::paint_renderer::CanvasBlendGateRequest;
using pp::paint_renderer::StrokeCompositePath;
using pp::paint_renderer::StrokeCompositeRequest;
using pp::paint_renderer::composite_layer;
using pp::paint_renderer::plan_canvas_blend_gate;
using pp::paint_renderer::plan_stroke_composite;
using pp::paint_renderer::stroke_composite_path_name;
using pp::paint_renderer::stroke_composite_requires_feedback;
@@ -259,6 +261,108 @@ void rejects_bad_stroke_composite_plans(pp::tests::Harness& h)
PP_EXPECT(h, stroke_composite_path_name(static_cast<StrokeCompositePath>(255)) == std::string_view("unknown"));
}
void plans_canvas_blend_gate_from_persisted_indices(pp::tests::Harness& h)
{
const std::vector<int> normal_layers { 0, 0, 0 };
const auto normal = plan_canvas_blend_gate(
RenderDeviceFeatures {},
CanvasBlendGateRequest {
.extent = Extent2D { .width = 0, .height = 0 },
.layer_blend_modes = normal_layers,
.has_stroke_blend_mode = true,
.stroke_blend_mode = 0,
});
PP_EXPECT(h, normal);
if (normal) {
PP_EXPECT(h, !normal.value().shader_blend);
PP_EXPECT(h, !normal.value().complex_blend);
PP_EXPECT(h, !normal.value().compatibility_fallback);
}
const std::vector<int> layer_blend { 0, 4 };
const auto layer = plan_canvas_blend_gate(
RenderDeviceFeatures { .framebuffer_fetch = true },
CanvasBlendGateRequest {
.extent = Extent2D { .width = 32, .height = 16 },
.layer_blend_modes = layer_blend,
});
PP_EXPECT(h, layer);
if (layer) {
PP_EXPECT(h, layer.value().shader_blend);
PP_EXPECT(h, layer.value().complex_blend);
PP_EXPECT(h, layer.value().first_complex_layer_index == 1);
PP_EXPECT(h, layer.value().path == StrokeCompositePath::framebuffer_fetch);
PP_EXPECT(h, layer.value().reads_destination_color);
}
const auto stroke = plan_canvas_blend_gate(
RenderDeviceFeatures { .texture_copy = true },
CanvasBlendGateRequest {
.extent = Extent2D { .width = 32, .height = 16 },
.layer_blend_modes = normal_layers,
.has_stroke_blend_mode = true,
.stroke_blend_mode = 10,
});
PP_EXPECT(h, stroke);
if (stroke) {
PP_EXPECT(h, stroke.value().shader_blend);
PP_EXPECT(h, stroke.value().stroke_complex);
PP_EXPECT(h, stroke.value().first_complex_layer_index == -1);
PP_EXPECT(h, stroke.value().path == StrokeCompositePath::ping_pong_textures);
PP_EXPECT(h, stroke.value().requires_texture_copy);
}
}
void canvas_blend_gate_preserves_legacy_fallbacks(pp::tests::Harness& h)
{
const std::vector<int> unknown_layer { 0, 99 };
const auto unknown = plan_canvas_blend_gate(
RenderDeviceFeatures {},
CanvasBlendGateRequest {
.extent = Extent2D { .width = 32, .height = 16 },
.layer_blend_modes = unknown_layer,
});
PP_EXPECT(h, unknown);
if (unknown) {
PP_EXPECT(h, unknown.value().shader_blend);
PP_EXPECT(h, unknown.value().complex_blend);
PP_EXPECT(h, unknown.value().compatibility_fallback);
PP_EXPECT(h, unknown.value().first_complex_layer_index == 1);
}
const std::vector<int> normal_layers { 0 };
const auto unsupported = plan_canvas_blend_gate(
RenderDeviceFeatures {},
CanvasBlendGateRequest {
.extent = Extent2D { .width = 32, .height = 16 },
.layer_blend_modes = normal_layers,
.has_stroke_blend_mode = true,
.stroke_blend_mode = 10,
});
PP_EXPECT(h, unsupported);
if (unsupported) {
PP_EXPECT(h, unsupported.value().shader_blend);
PP_EXPECT(h, unsupported.value().stroke_complex);
PP_EXPECT(h, unsupported.value().compatibility_fallback);
}
const auto dual_pattern = plan_canvas_blend_gate(
RenderDeviceFeatures { .render_target_blit = true },
CanvasBlendGateRequest {
.extent = Extent2D { .width = 16, .height = 16 },
.layer_blend_modes = normal_layers,
.dual_brush_blend = true,
.pattern_blend = true,
});
PP_EXPECT(h, dual_pattern);
if (dual_pattern) {
PP_EXPECT(h, dual_pattern.value().shader_blend);
PP_EXPECT(h, dual_pattern.value().dual_brush_complex);
PP_EXPECT(h, dual_pattern.value().pattern_complex);
PP_EXPECT(h, dual_pattern.value().requires_render_target_blit);
}
}
}
int main()
@@ -270,5 +374,7 @@ int main()
harness.run("detects_feedback_requirements", detects_feedback_requirements);
harness.run("plans_stroke_composite_paths", plans_stroke_composite_paths);
harness.run("rejects_bad_stroke_composite_plans", rejects_bad_stroke_composite_plans);
harness.run("plans_canvas_blend_gate_from_persisted_indices", plans_canvas_blend_gate_from_persisted_indices);
harness.run("canvas_blend_gate_preserves_legacy_fallbacks", canvas_blend_gate_preserves_legacy_fallbacks);
return harness.finish();
}