310 lines
12 KiB
C++
310 lines
12 KiB
C++
#pragma once
|
|
|
|
#include "paint_renderer/compositor.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string_view>
|
|
#include <utility>
|
|
|
|
namespace pp::panopainter {
|
|
|
|
struct LegacyCanvasStrokeCommitFace {
|
|
int index = 0;
|
|
bool dirty = false;
|
|
};
|
|
|
|
struct LegacyCanvasStrokeCommitCallbacks {
|
|
std::function<void()> mark_commit_started;
|
|
std::function<void()> capture_render_state;
|
|
std::function<void()> prepare_render_state;
|
|
std::function<void()> restore_render_state;
|
|
std::function<void()> publish_history;
|
|
std::function<void()> capture_timelapse_frame;
|
|
|
|
std::function<void(int)> bind_layer_framebuffer;
|
|
std::function<void(int)> capture_history_region;
|
|
std::function<void(int)> apply_layer_dirty_region;
|
|
std::function<void(int)> copy_layer_to_commit_destination;
|
|
std::function<void(int)> bind_commit_inputs;
|
|
std::function<void(int)> execute_erase_composite;
|
|
std::function<void(int)> execute_paint_composite;
|
|
std::function<void(int)> copy_committed_to_dilate_source;
|
|
std::function<void(int)> execute_commit_dilate;
|
|
std::function<void(int)> unbind_layer_framebuffer;
|
|
};
|
|
|
|
struct LegacyCanvasStrokeCommitRequest {
|
|
std::string_view context;
|
|
std::array<LegacyCanvasStrokeCommitFace, 6> faces {};
|
|
pp::paint_renderer::CanvasStrokeCommitSequencePlan sequence;
|
|
LegacyCanvasStrokeCommitCallbacks callbacks;
|
|
};
|
|
|
|
struct LegacyCanvasStrokeCommitResult {
|
|
bool ok = false;
|
|
int committed_faces = 0;
|
|
};
|
|
|
|
struct LegacyCanvasStrokeCommitCopyExtent {
|
|
int width = 0;
|
|
int height = 0;
|
|
};
|
|
|
|
template <
|
|
typename MarkCommitStarted,
|
|
typename CaptureRenderState,
|
|
typename PrepareRenderState,
|
|
typename RestoreRenderState,
|
|
typename PublishHistory,
|
|
typename CaptureTimelapseFrame,
|
|
typename BindLayerFramebuffer,
|
|
typename CaptureHistoryRegion,
|
|
typename ApplyLayerDirtyRegion,
|
|
typename CopyLayerToCommitDestination,
|
|
typename BindCommitInputs,
|
|
typename ExecuteEraseComposite,
|
|
typename ExecutePaintComposite,
|
|
typename CopyCommittedToDilateSource,
|
|
typename ExecuteCommitDilate,
|
|
typename UnbindLayerFramebuffer>
|
|
[[nodiscard]] inline LegacyCanvasStrokeCommitCallbacks make_legacy_canvas_stroke_commit_callbacks(
|
|
MarkCommitStarted&& mark_commit_started,
|
|
CaptureRenderState&& capture_render_state,
|
|
PrepareRenderState&& prepare_render_state,
|
|
RestoreRenderState&& restore_render_state,
|
|
PublishHistory&& publish_history,
|
|
CaptureTimelapseFrame&& capture_timelapse_frame,
|
|
BindLayerFramebuffer&& bind_layer_framebuffer,
|
|
CaptureHistoryRegion&& capture_history_region,
|
|
ApplyLayerDirtyRegion&& apply_layer_dirty_region,
|
|
CopyLayerToCommitDestination&& copy_layer_to_commit_destination,
|
|
BindCommitInputs&& bind_commit_inputs,
|
|
ExecuteEraseComposite&& execute_erase_composite,
|
|
ExecutePaintComposite&& execute_paint_composite,
|
|
CopyCommittedToDilateSource&& copy_committed_to_dilate_source,
|
|
ExecuteCommitDilate&& execute_commit_dilate,
|
|
UnbindLayerFramebuffer&& unbind_layer_framebuffer)
|
|
{
|
|
return LegacyCanvasStrokeCommitCallbacks {
|
|
.mark_commit_started = std::forward<MarkCommitStarted>(mark_commit_started),
|
|
.capture_render_state = std::forward<CaptureRenderState>(capture_render_state),
|
|
.prepare_render_state = std::forward<PrepareRenderState>(prepare_render_state),
|
|
.restore_render_state = std::forward<RestoreRenderState>(restore_render_state),
|
|
.publish_history = std::forward<PublishHistory>(publish_history),
|
|
.capture_timelapse_frame = std::forward<CaptureTimelapseFrame>(capture_timelapse_frame),
|
|
.bind_layer_framebuffer = std::forward<BindLayerFramebuffer>(bind_layer_framebuffer),
|
|
.capture_history_region = std::forward<CaptureHistoryRegion>(capture_history_region),
|
|
.apply_layer_dirty_region = std::forward<ApplyLayerDirtyRegion>(apply_layer_dirty_region),
|
|
.copy_layer_to_commit_destination = std::forward<CopyLayerToCommitDestination>(copy_layer_to_commit_destination),
|
|
.bind_commit_inputs = std::forward<BindCommitInputs>(bind_commit_inputs),
|
|
.execute_erase_composite = std::forward<ExecuteEraseComposite>(execute_erase_composite),
|
|
.execute_paint_composite = std::forward<ExecutePaintComposite>(execute_paint_composite),
|
|
.copy_committed_to_dilate_source = std::forward<CopyCommittedToDilateSource>(copy_committed_to_dilate_source),
|
|
.execute_commit_dilate = std::forward<ExecuteCommitDilate>(execute_commit_dilate),
|
|
.unbind_layer_framebuffer = std::forward<UnbindLayerFramebuffer>(unbind_layer_framebuffer),
|
|
};
|
|
}
|
|
|
|
[[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 std::size_t legacy_canvas_stroke_commit_texture_binding_count(
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence) noexcept
|
|
{
|
|
return std::min(sequence.texture_binding_count, sequence.texture_bindings.size());
|
|
}
|
|
|
|
[[nodiscard]] inline int legacy_canvas_stroke_commit_texture_slot(
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
|
pp::paint_renderer::CanvasStrokeCommitTextureRole role) noexcept
|
|
{
|
|
const auto binding_count = legacy_canvas_stroke_commit_texture_binding_count(sequence);
|
|
for (std::size_t binding_index = 0; binding_index < binding_count; ++binding_index) {
|
|
const auto& binding = sequence.texture_bindings[binding_index];
|
|
if (binding.role == role) {
|
|
return static_cast<int>(binding.slot);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
template <typename SetActiveTextureUnit, typename BindTextureRole, typename BindSamplerRole>
|
|
inline void bind_legacy_canvas_stroke_commit_inputs(
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
|
SetActiveTextureUnit&& set_active_texture_unit,
|
|
BindTextureRole&& bind_texture_role,
|
|
BindSamplerRole&& bind_sampler_role)
|
|
{
|
|
const auto binding_count = legacy_canvas_stroke_commit_texture_binding_count(sequence);
|
|
for (std::size_t binding_index = 0; binding_index < binding_count; ++binding_index) {
|
|
const auto& binding = sequence.texture_bindings[binding_index];
|
|
set_active_texture_unit(static_cast<int>(binding.slot));
|
|
bind_texture_role(binding.role);
|
|
bind_sampler_role(binding.role, static_cast<int>(binding.slot));
|
|
}
|
|
}
|
|
|
|
template <typename SetActiveTextureUnit, typename BindFaceTextureRole, typename BindFaceSamplerRole>
|
|
inline void bind_legacy_canvas_stroke_commit_face_inputs(
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
|
SetActiveTextureUnit&& set_active_texture_unit,
|
|
BindFaceTextureRole&& bind_face_texture_role,
|
|
BindFaceSamplerRole&& bind_face_sampler_role)
|
|
{
|
|
bind_legacy_canvas_stroke_commit_inputs(
|
|
sequence,
|
|
std::forward<SetActiveTextureUnit>(set_active_texture_unit),
|
|
std::forward<BindFaceTextureRole>(bind_face_texture_role),
|
|
std::forward<BindFaceSamplerRole>(bind_face_sampler_role));
|
|
}
|
|
|
|
[[nodiscard]] inline LegacyCanvasStrokeCommitRequest make_legacy_canvas_stroke_commit_request(
|
|
const std::array<LegacyCanvasStrokeCommitFace, 6>& faces,
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
|
const LegacyCanvasStrokeCommitCallbacks& callbacks)
|
|
{
|
|
return LegacyCanvasStrokeCommitRequest {
|
|
.context = "Canvas::stroke_commit",
|
|
.faces = faces,
|
|
.sequence = sequence,
|
|
.callbacks = callbacks,
|
|
};
|
|
}
|
|
|
|
template <typename SetupShader, typename DrawPlane>
|
|
inline void execute_legacy_canvas_stroke_commit_erase(
|
|
SetupShader&& setup_shader,
|
|
DrawPlane&& draw_plane)
|
|
{
|
|
setup_shader();
|
|
draw_plane();
|
|
}
|
|
|
|
template <typename SetupShader, typename DrawPlane>
|
|
inline void execute_legacy_canvas_stroke_commit_paint(
|
|
SetupShader&& setup_shader,
|
|
DrawPlane&& draw_plane)
|
|
{
|
|
setup_shader();
|
|
draw_plane();
|
|
}
|
|
|
|
template <typename SetupShader, typename SetActiveTextureUnit, typename BindLayerScratch, typename CopyFramebufferToTexture>
|
|
inline void copy_legacy_canvas_stroke_commit_to_dilate_source(
|
|
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
|
SetupShader&& setup_shader,
|
|
SetActiveTextureUnit&& set_active_texture_unit,
|
|
BindLayerScratch&& bind_layer_scratch,
|
|
CopyFramebufferToTexture&& copy_framebuffer_to_texture,
|
|
LegacyCanvasStrokeCommitCopyExtent extent)
|
|
{
|
|
const auto layer_scratch_slot = legacy_canvas_stroke_commit_texture_slot(
|
|
sequence,
|
|
pp::paint_renderer::CanvasStrokeCommitTextureRole::layer_scratch);
|
|
if (layer_scratch_slot < 0 || extent.width <= 0 || extent.height <= 0) {
|
|
return;
|
|
}
|
|
|
|
setup_shader();
|
|
set_active_texture_unit(layer_scratch_slot);
|
|
bind_layer_scratch();
|
|
copy_framebuffer_to_texture(0, 0, 0, 0, extent.width, extent.height);
|
|
}
|
|
|
|
template <typename DrawPlane>
|
|
inline void execute_legacy_canvas_stroke_commit_dilate(DrawPlane&& draw_plane)
|
|
{
|
|
draw_plane();
|
|
}
|
|
|
|
[[nodiscard]] inline bool legacy_canvas_stroke_commit_callbacks_ready(
|
|
const LegacyCanvasStrokeCommitCallbacks& callbacks) noexcept
|
|
{
|
|
return callbacks.mark_commit_started &&
|
|
callbacks.capture_render_state &&
|
|
callbacks.prepare_render_state &&
|
|
callbacks.restore_render_state &&
|
|
callbacks.publish_history &&
|
|
callbacks.capture_timelapse_frame &&
|
|
callbacks.bind_layer_framebuffer &&
|
|
callbacks.capture_history_region &&
|
|
callbacks.apply_layer_dirty_region &&
|
|
callbacks.copy_layer_to_commit_destination &&
|
|
callbacks.bind_commit_inputs &&
|
|
callbacks.execute_erase_composite &&
|
|
callbacks.execute_paint_composite &&
|
|
callbacks.copy_committed_to_dilate_source &&
|
|
callbacks.execute_commit_dilate &&
|
|
callbacks.unbind_layer_framebuffer;
|
|
}
|
|
|
|
[[nodiscard]] inline LegacyCanvasStrokeCommitResult execute_legacy_canvas_stroke_commit_sequence(
|
|
const LegacyCanvasStrokeCommitRequest& request)
|
|
{
|
|
LegacyCanvasStrokeCommitResult result;
|
|
if (!legacy_canvas_stroke_commit_callbacks_ready(request.callbacks)) {
|
|
return result;
|
|
}
|
|
|
|
request.callbacks.mark_commit_started();
|
|
request.callbacks.capture_render_state();
|
|
request.callbacks.prepare_render_state();
|
|
|
|
for (const auto& face : request.faces) {
|
|
if (!face.dirty) {
|
|
continue;
|
|
}
|
|
|
|
request.callbacks.bind_layer_framebuffer(face.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);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::update_layer_dirty_state:
|
|
request.callbacks.apply_layer_dirty_region(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::copy_layer_rtt_to_scratch:
|
|
request.callbacks.copy_layer_to_commit_destination(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::bind_commit_inputs:
|
|
request.callbacks.bind_commit_inputs(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::erase_draw:
|
|
request.callbacks.execute_erase_composite(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::composite_draw:
|
|
request.callbacks.execute_paint_composite(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::copy_committed_rtt_to_scratch:
|
|
request.callbacks.copy_committed_to_dilate_source(face.index);
|
|
break;
|
|
case pp::paint_renderer::CanvasStrokeCommitStep::dilate_edges_draw:
|
|
request.callbacks.execute_commit_dilate(face.index);
|
|
break;
|
|
}
|
|
}
|
|
|
|
request.callbacks.unbind_layer_framebuffer(face.index);
|
|
++result.committed_faces;
|
|
}
|
|
|
|
request.callbacks.restore_render_state();
|
|
request.callbacks.publish_history();
|
|
request.callbacks.capture_timelapse_frame();
|
|
|
|
result.ok = true;
|
|
return result;
|
|
}
|
|
|
|
} // namespace pp::panopainter
|