Files
panopainter/src/paint_renderer/compositor.h

292 lines
10 KiB
C++

#pragma once
#include "document/document.h"
#include "foundation/result.h"
#include "paint/blend.h"
#include "renderer_api/renderer_api.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <vector>
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;
bool visible = true;
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;
};
struct CanvasBlendGateRequest {
pp::renderer::Extent2D extent {};
std::span<const int> layer_blend_modes;
bool has_stroke_blend_mode = false;
int stroke_blend_mode = 0;
bool dual_brush_blend = false;
bool pattern_blend = false;
};
struct CanvasBlendGatePlan {
bool shader_blend = false;
bool complex_blend = false;
bool compatibility_fallback = false;
bool stroke_complex = false;
bool dual_brush_complex = false;
bool pattern_complex = false;
int first_complex_layer_index = -1;
StrokeCompositePath path = StrokeCompositePath::fixed_function_blend;
bool reads_destination_color = false;
bool requires_auxiliary_texture = false;
bool requires_texture_copy = false;
bool requires_render_target_blit = false;
};
struct CanvasStrokeFeedbackPlan {
StrokeCompositePath path = StrokeCompositePath::fixed_function_blend;
bool reads_destination_color = false;
bool requires_auxiliary_texture = false;
bool requires_texture_copy = false;
bool requires_render_target_blit = false;
bool compatibility_fallback = false;
};
struct DocumentFaceCompositeRequest {
const pp::document::CanvasDocument* document = nullptr;
std::size_t frame_index = 0;
std::uint32_t face_index = 0;
pp::paint::Rgba clear_color {};
};
struct DocumentFaceCompositeResult {
pp::renderer::Extent2D extent {};
std::vector<pp::paint::Rgba> pixels;
std::size_t visited_layer_count = 0;
std::size_t composited_layer_count = 0;
std::size_t face_payload_count = 0;
};
struct DocumentFrameCompositeRequest {
const pp::document::CanvasDocument* document = nullptr;
std::size_t frame_index = 0;
pp::paint::Rgba clear_color {};
};
struct DocumentFrameCompositeResult {
pp::renderer::Extent2D extent {};
std::array<DocumentFaceCompositeResult, pp::document::cube_face_count> faces {};
std::size_t visited_layer_count = 0;
std::size_t composited_layer_face_count = 0;
std::size_t face_payload_count = 0;
};
struct DocumentFrameUploadRequest {
const pp::document::CanvasDocument* document = nullptr;
std::size_t frame_index = 0;
pp::paint::Rgba clear_color {};
bool transition_to_shader_read = true;
};
struct DocumentFrameUploadResult {
DocumentFrameCompositeResult composite {};
std::array<std::unique_ptr<pp::renderer::ITexture2D>, pp::document::cube_face_count> face_textures {};
std::size_t texture_count = 0;
std::size_t transition_count = 0;
std::uint64_t uploaded_bytes = 0;
};
struct RecordedDocumentFrameUploadResult {
DocumentFrameUploadResult upload {};
std::size_t command_count = 0;
std::size_t upload_command_count = 0;
std::size_t transition_command_count = 0;
};
struct DocumentFrameFacePngExportResult {
DocumentFrameCompositeResult composite {};
std::array<std::vector<std::byte>, pp::document::cube_face_count> face_pngs {};
std::size_t face_count = 0;
std::uint64_t encoded_bytes = 0;
};
struct DocumentFrameEquirectangularPngExportResult {
pp::renderer::Extent2D face_extent {};
pp::renderer::Extent2D equirectangular_extent {};
std::vector<std::byte> png;
std::uint64_t encoded_bytes = 0;
std::size_t face_payload_count = 0;
std::size_t composited_layer_face_count = 0;
};
struct DocumentDepthExportRenderPlanRequest {
const pp::document::CanvasDocument* document = nullptr;
std::size_t frame_index = 0;
pp::renderer::Extent2D output_extent {
.width = 1024,
.height = 1024,
};
};
struct DocumentDepthExportRenderPlan {
pp::renderer::Extent2D output_extent {
.width = 1024,
.height = 1024,
};
std::size_t merged_face_draw_count = 0;
std::size_t layer_depth_draw_count = 0;
std::size_t visited_layer_count = 0;
std::size_t visible_layer_count = 0;
std::size_t face_payload_count = 0;
bool uses_perspective_camera = true;
bool requires_renderer_readback = true;
};
struct DocumentLayerEquirectangularPngExportRequest {
const pp::document::CanvasDocument* document = nullptr;
std::size_t frame_index = 0;
pp::paint::Rgba clear_color {};
};
struct DocumentLayerEquirectangularPng {
std::size_t layer_index = 0;
std::string layer_name;
pp::renderer::Extent2D face_extent {};
pp::renderer::Extent2D equirectangular_extent {};
std::vector<std::byte> png;
std::uint64_t encoded_bytes = 0;
std::size_t face_payload_count = 0;
std::size_t composited_layer_face_count = 0;
};
struct DocumentLayerEquirectangularPngExportResult {
std::vector<DocumentLayerEquirectangularPng> layers;
std::uint64_t encoded_bytes = 0;
std::size_t layer_count = 0;
};
struct DocumentAnimationFrameEquirectangularPngExportRequest {
const pp::document::CanvasDocument* document = nullptr;
pp::paint::Rgba clear_color {};
};
struct DocumentAnimationFrameEquirectangularPng {
std::size_t frame_index = 0;
pp::renderer::Extent2D face_extent {};
pp::renderer::Extent2D equirectangular_extent {};
std::vector<std::byte> png;
std::uint64_t encoded_bytes = 0;
std::size_t face_payload_count = 0;
std::size_t composited_layer_face_count = 0;
};
struct DocumentAnimationFrameEquirectangularPngExportResult {
std::vector<DocumentAnimationFrameEquirectangularPng> frames;
std::uint64_t encoded_bytes = 0;
std::size_t frame_count = 0;
};
struct DocumentFrameExportReadinessResult {
RecordedDocumentFrameUploadResult recorded_upload {};
DocumentFrameFacePngExportResult face_pngs {};
};
[[nodiscard]] pp::foundation::Status composite_layer(
std::span<pp::paint::Rgba> destination,
pp::renderer::Extent2D extent,
LayerCompositeView layer) noexcept;
[[nodiscard]] pp::foundation::Result<DocumentFaceCompositeResult> composite_document_face(
DocumentFaceCompositeRequest request);
[[nodiscard]] pp::foundation::Result<DocumentFrameCompositeResult> composite_document_frame(
DocumentFrameCompositeRequest request);
[[nodiscard]] pp::foundation::Result<DocumentFrameUploadResult> upload_document_frame_faces(
pp::renderer::IRenderDevice& device,
DocumentFrameUploadRequest request);
[[nodiscard]] pp::foundation::Result<RecordedDocumentFrameUploadResult> record_document_frame_upload(
DocumentFrameUploadRequest request);
[[nodiscard]] pp::foundation::Result<DocumentFrameFacePngExportResult> export_document_frame_face_pngs(
DocumentFrameCompositeRequest request);
[[nodiscard]] pp::foundation::Result<DocumentFrameEquirectangularPngExportResult>
export_document_frame_equirectangular_png(const DocumentFrameCompositeResult& composite);
[[nodiscard]] pp::foundation::Result<DocumentFrameEquirectangularPngExportResult>
export_document_frame_equirectangular_png(DocumentFrameCompositeRequest request);
[[nodiscard]] pp::foundation::Result<DocumentDepthExportRenderPlan> plan_document_depth_export_render(
DocumentDepthExportRenderPlanRequest request) noexcept;
[[nodiscard]] pp::foundation::Result<DocumentLayerEquirectangularPngExportResult>
export_document_layers_equirectangular_pngs(DocumentLayerEquirectangularPngExportRequest request);
[[nodiscard]] pp::foundation::Result<DocumentAnimationFrameEquirectangularPngExportResult>
export_document_animation_frames_equirectangular_pngs(
DocumentAnimationFrameEquirectangularPngExportRequest request);
[[nodiscard]] pp::foundation::Result<DocumentFrameExportReadinessResult> prepare_document_frame_export_readiness(
DocumentFrameCompositeRequest request);
[[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]] pp::foundation::Result<CanvasBlendGatePlan> plan_canvas_blend_gate(
pp::renderer::RenderDeviceFeatures features,
CanvasBlendGateRequest request) noexcept;
[[nodiscard]] pp::foundation::Result<CanvasStrokeFeedbackPlan> plan_canvas_stroke_feedback(
pp::renderer::RenderDeviceFeatures features,
pp::renderer::Extent2D extent) noexcept;
[[nodiscard]] const char* stroke_composite_path_name(StrokeCompositePath path) noexcept;
}