Add stroke composite feedback planner
This commit is contained in:
@@ -6,6 +6,40 @@ namespace pp::paint_renderer {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool is_valid_blend_mode(pp::paint::BlendMode mode) noexcept
|
||||
{
|
||||
switch (mode) {
|
||||
case pp::paint::BlendMode::normal:
|
||||
case pp::paint::BlendMode::multiply:
|
||||
case pp::paint::BlendMode::screen:
|
||||
case pp::paint::BlendMode::color_dodge:
|
||||
case pp::paint::BlendMode::overlay:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_valid_stroke_blend_mode(pp::paint::StrokeBlendMode mode) noexcept
|
||||
{
|
||||
switch (mode) {
|
||||
case pp::paint::StrokeBlendMode::normal:
|
||||
case pp::paint::StrokeBlendMode::multiply:
|
||||
case pp::paint::StrokeBlendMode::subtract:
|
||||
case pp::paint::StrokeBlendMode::darken:
|
||||
case pp::paint::StrokeBlendMode::overlay:
|
||||
case pp::paint::StrokeBlendMode::color_dodge:
|
||||
case pp::paint::StrokeBlendMode::color_burn:
|
||||
case pp::paint::StrokeBlendMode::linear_burn:
|
||||
case pp::paint::StrokeBlendMode::hard_mix:
|
||||
case pp::paint::StrokeBlendMode::linear_height:
|
||||
case pp::paint::StrokeBlendMode::height:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<std::size_t> expected_pixel_count(pp::renderer::Extent2D extent) noexcept
|
||||
{
|
||||
const auto extent_status = pp::renderer::validate_extent(extent);
|
||||
@@ -29,6 +63,20 @@ namespace {
|
||||
return pp::foundation::Result<std::size_t>::success(static_cast<std::size_t>(count));
|
||||
}
|
||||
|
||||
[[nodiscard]] StrokeCompositePath composite_path_from_feedback(pp::renderer::PaintFeedbackPath path) noexcept
|
||||
{
|
||||
switch (path) {
|
||||
case pp::renderer::PaintFeedbackPath::none:
|
||||
return StrokeCompositePath::fixed_function_blend;
|
||||
case pp::renderer::PaintFeedbackPath::framebuffer_fetch:
|
||||
return StrokeCompositePath::framebuffer_fetch;
|
||||
case pp::renderer::PaintFeedbackPath::ping_pong_textures:
|
||||
return StrokeCompositePath::ping_pong_textures;
|
||||
}
|
||||
|
||||
return StrokeCompositePath::fixed_function_blend;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pp::foundation::Status composite_layer(
|
||||
@@ -62,4 +110,78 @@ pp::foundation::Status composite_layer(
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
bool stroke_composite_requires_feedback(
|
||||
pp::paint::BlendMode layer_blend_mode,
|
||||
pp::paint::StrokeBlendMode stroke_blend_mode,
|
||||
bool dual_brush_blend,
|
||||
bool pattern_blend) noexcept
|
||||
{
|
||||
return layer_blend_mode != pp::paint::BlendMode::normal
|
||||
|| stroke_blend_mode != pp::paint::StrokeBlendMode::normal
|
||||
|| dual_brush_blend
|
||||
|| pattern_blend;
|
||||
}
|
||||
|
||||
pp::foundation::Result<StrokeCompositePlan> plan_stroke_composite(
|
||||
pp::renderer::RenderDeviceFeatures features,
|
||||
StrokeCompositeRequest request) noexcept
|
||||
{
|
||||
if (!is_valid_blend_mode(request.layer_blend_mode)) {
|
||||
return pp::foundation::Result<StrokeCompositePlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("unknown layer blend mode"));
|
||||
}
|
||||
|
||||
if (!is_valid_stroke_blend_mode(request.stroke_blend_mode)) {
|
||||
return pp::foundation::Result<StrokeCompositePlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("unknown stroke blend mode"));
|
||||
}
|
||||
|
||||
const pp::renderer::TextureDesc target_desc {
|
||||
.extent = request.extent,
|
||||
.format = request.target_format,
|
||||
.usage = request.target_usage,
|
||||
.debug_name = "stroke-composite-target",
|
||||
};
|
||||
const auto complex_blend = stroke_composite_requires_feedback(
|
||||
request.layer_blend_mode,
|
||||
request.stroke_blend_mode,
|
||||
request.dual_brush_blend,
|
||||
request.pattern_blend);
|
||||
const auto feedback = pp::renderer::plan_paint_feedback(features, target_desc, complex_blend);
|
||||
if (!feedback) {
|
||||
return pp::foundation::Result<StrokeCompositePlan>::failure(feedback.status());
|
||||
}
|
||||
|
||||
StrokeCompositePlan plan;
|
||||
plan.path = composite_path_from_feedback(feedback.value().path);
|
||||
plan.feedback = feedback.value();
|
||||
plan.target_desc = target_desc;
|
||||
plan.target_bytes = feedback.value().target_bytes;
|
||||
plan.auxiliary_bytes = feedback.value().requires_auxiliary_texture
|
||||
? feedback.value().target_bytes
|
||||
: 0U;
|
||||
plan.estimated_working_bytes = plan.target_bytes + plan.auxiliary_bytes;
|
||||
plan.complex_blend = complex_blend;
|
||||
plan.reads_destination_color = feedback.value().reads_destination_color;
|
||||
plan.requires_auxiliary_texture = feedback.value().requires_auxiliary_texture;
|
||||
plan.requires_texture_copy = feedback.value().requires_texture_copy;
|
||||
plan.requires_render_target_blit = feedback.value().requires_render_target_blit;
|
||||
plan.requires_explicit_transition = feedback.value().requires_explicit_transition;
|
||||
return pp::foundation::Result<StrokeCompositePlan>::success(plan);
|
||||
}
|
||||
|
||||
const char* stroke_composite_path_name(StrokeCompositePath path) noexcept
|
||||
{
|
||||
switch (path) {
|
||||
case StrokeCompositePath::fixed_function_blend:
|
||||
return "fixed_function_blend";
|
||||
case StrokeCompositePath::framebuffer_fetch:
|
||||
return "framebuffer_fetch";
|
||||
case StrokeCompositePath::ping_pong_textures:
|
||||
return "ping_pong_textures";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
#include "paint/blend.h"
|
||||
#include "renderer_api/renderer_api.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
namespace pp::paint_renderer {
|
||||
|
||||
enum class StrokeCompositePath : std::uint8_t {
|
||||
fixed_function_blend,
|
||||
framebuffer_fetch,
|
||||
ping_pong_textures,
|
||||
};
|
||||
|
||||
struct LayerCompositeView {
|
||||
std::span<const pp::paint::Rgba> pixels;
|
||||
float opacity = 1.0F;
|
||||
@@ -15,9 +22,49 @@ struct LayerCompositeView {
|
||||
pp::paint::BlendMode blend_mode = pp::paint::BlendMode::normal;
|
||||
};
|
||||
|
||||
struct StrokeCompositeRequest {
|
||||
pp::renderer::Extent2D extent {};
|
||||
pp::renderer::TextureFormat target_format = pp::renderer::TextureFormat::rgba8;
|
||||
pp::renderer::TextureUsage target_usage = pp::renderer::TextureUsage::render_target
|
||||
| pp::renderer::TextureUsage::sampled
|
||||
| pp::renderer::TextureUsage::copy_source
|
||||
| pp::renderer::TextureUsage::copy_destination;
|
||||
pp::paint::BlendMode layer_blend_mode = pp::paint::BlendMode::normal;
|
||||
pp::paint::StrokeBlendMode stroke_blend_mode = pp::paint::StrokeBlendMode::normal;
|
||||
bool dual_brush_blend = false;
|
||||
bool pattern_blend = false;
|
||||
};
|
||||
|
||||
struct StrokeCompositePlan {
|
||||
StrokeCompositePath path = StrokeCompositePath::fixed_function_blend;
|
||||
pp::renderer::PaintFeedbackPlan feedback {};
|
||||
pp::renderer::TextureDesc target_desc {};
|
||||
std::uint64_t target_bytes = 0;
|
||||
std::uint64_t auxiliary_bytes = 0;
|
||||
std::uint64_t estimated_working_bytes = 0;
|
||||
bool complex_blend = false;
|
||||
bool reads_destination_color = false;
|
||||
bool requires_auxiliary_texture = false;
|
||||
bool requires_texture_copy = false;
|
||||
bool requires_render_target_blit = false;
|
||||
bool requires_explicit_transition = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] pp::foundation::Status composite_layer(
|
||||
std::span<pp::paint::Rgba> destination,
|
||||
pp::renderer::Extent2D extent,
|
||||
LayerCompositeView layer) noexcept;
|
||||
|
||||
[[nodiscard]] bool stroke_composite_requires_feedback(
|
||||
pp::paint::BlendMode layer_blend_mode,
|
||||
pp::paint::StrokeBlendMode stroke_blend_mode,
|
||||
bool dual_brush_blend,
|
||||
bool pattern_blend) noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<StrokeCompositePlan> plan_stroke_composite(
|
||||
pp::renderer::RenderDeviceFeatures features,
|
||||
StrokeCompositeRequest request) noexcept;
|
||||
|
||||
[[nodiscard]] const char* stroke_composite_path_name(StrokeCompositePath path) noexcept;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user