Upload document frame faces through renderer API

This commit is contained in:
2026-06-05 17:37:21 +02:00
parent 7c6c5f3e36
commit d0e023556b
9 changed files with 278 additions and 17 deletions

View File

@@ -1,5 +1,6 @@
#include "paint_renderer/compositor.h"
#include <algorithm>
#include <limits>
#include <utility>
@@ -105,6 +106,24 @@ namespace {
};
}
[[nodiscard]] std::byte rgba8_channel(float value) noexcept
{
const auto clamped = std::clamp(value, 0.0F, 1.0F);
return static_cast<std::byte>(static_cast<std::uint8_t>(clamped * 255.0F + 0.5F));
}
void append_rgba8_bytes(std::vector<std::byte>& bytes, std::span<const pp::paint::Rgba> pixels)
{
bytes.clear();
bytes.reserve(pixels.size() * pp::document::rgba8_components);
for (const auto& pixel : pixels) {
bytes.push_back(rgba8_channel(pixel.r));
bytes.push_back(rgba8_channel(pixel.g));
bytes.push_back(rgba8_channel(pixel.b));
bytes.push_back(rgba8_channel(pixel.a));
}
}
[[nodiscard]] pp::foundation::Status composite_face_payload(
std::span<pp::paint::Rgba> destination,
pp::renderer::Extent2D extent,
@@ -327,6 +346,72 @@ pp::foundation::Result<DocumentFrameCompositeResult> composite_document_frame(
return pp::foundation::Result<DocumentFrameCompositeResult>::success(std::move(result));
}
pp::foundation::Result<DocumentFrameUploadResult> upload_document_frame_faces(
pp::renderer::IRenderDevice& device,
DocumentFrameUploadRequest request)
{
auto composite = composite_document_frame(DocumentFrameCompositeRequest {
.document = request.document,
.frame_index = request.frame_index,
.clear_color = request.clear_color,
});
if (!composite) {
return pp::foundation::Result<DocumentFrameUploadResult>::failure(composite.status());
}
DocumentFrameUploadResult result;
result.composite = std::move(composite.value());
std::vector<std::byte> upload_bytes;
for (std::size_t face_index = 0; face_index < result.composite.faces.size(); ++face_index) {
const pp::renderer::TextureDesc desc {
.extent = result.composite.extent,
.format = pp::renderer::TextureFormat::rgba8,
.usage = pp::renderer::TextureUsage::sampled
| pp::renderer::TextureUsage::upload_destination
| pp::renderer::TextureUsage::readback_source
| pp::renderer::TextureUsage::copy_source,
.debug_name = "document-frame-face",
};
auto texture = device.create_texture(desc);
if (!texture) {
return pp::foundation::Result<DocumentFrameUploadResult>::failure(texture.status());
}
append_rgba8_bytes(upload_bytes, result.composite.faces[face_index].pixels);
auto& context = device.immediate_context();
const auto upload_status = context.upload_texture(
*texture.value(),
pp::renderer::ReadbackRegion {
.x = 0,
.y = 0,
.width = result.composite.extent.width,
.height = result.composite.extent.height,
},
upload_bytes);
if (!upload_status.ok()) {
return pp::foundation::Result<DocumentFrameUploadResult>::failure(upload_status);
}
result.uploaded_bytes += static_cast<std::uint64_t>(upload_bytes.size());
if (request.transition_to_shader_read && device.features().explicit_texture_transitions) {
const auto transition_status = context.transition_texture(
*texture.value(),
pp::renderer::TextureState::upload_destination,
pp::renderer::TextureState::shader_read);
if (!transition_status.ok()) {
return pp::foundation::Result<DocumentFrameUploadResult>::failure(transition_status);
}
++result.transition_count;
}
result.face_textures[face_index] = std::move(texture.value());
++result.texture_count;
}
return pp::foundation::Result<DocumentFrameUploadResult>::success(std::move(result));
}
bool stroke_composite_requires_feedback(
pp::paint::BlendMode layer_blend_mode,
pp::paint::StrokeBlendMode stroke_blend_mode,

View File

@@ -8,6 +8,7 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <span>
#include <vector>
@@ -116,6 +117,21 @@ struct DocumentFrameCompositeResult {
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;
};
[[nodiscard]] pp::foundation::Status composite_layer(
std::span<pp::paint::Rgba> destination,
pp::renderer::Extent2D extent,
@@ -127,6 +143,10 @@ struct DocumentFrameCompositeResult {
[[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]] bool stroke_composite_requires_feedback(
pp::paint::BlendMode layer_blend_mode,
pp::paint::StrokeBlendMode stroke_blend_mode,