Files
panopainter/src/legacy_canvas_stroke_commit_services.h

227 lines
8.2 KiB
C++

#pragma once
#include "paint_renderer/compositor.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <string_view>
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;
};
[[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 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