Route RTT region readbacks through backend

This commit is contained in:
2026-06-04 21:01:13 +02:00
parent b9dbcd10d7
commit 15c58bfb21
8 changed files with 86 additions and 58 deletions

View File

@@ -325,18 +325,14 @@ void Canvas::pick_update(int plane)
draw_merge(true, faces);
int i = plane;
m_layers_merge.rtt(i).bindFramebuffer();
if (!m_pick_data[plane])
m_pick_data[plane] = std::make_unique<glm::u8vec4[]>(m_width * m_height);
glReadPixels(
m_layers_merge.rtt(i).readPixelsRgba8(
0,
0,
m_width,
m_height,
rgba_pixel_format(),
unsigned_byte_component_type(),
m_pick_data[plane].get());
m_layers_merge.rtt(i).unbindFramebuffer();
});
m_pick_ready[plane] = true;
@@ -1030,13 +1026,11 @@ void Canvas::stroke_commit()
// save image before commit
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
glReadPixels(
m_dirty_box[i].x,
m_dirty_box[i].y,
box_sz.x,
box_sz.y,
rgba_pixel_format(),
unsigned_byte_component_type(),
m_layers[m_current_layer_idx]->rtt(i).readPixelsRgba8(
static_cast<int>(m_dirty_box[i].x),
static_cast<int>(m_dirty_box[i].y),
static_cast<int>(box_sz.x),
static_cast<int>(box_sz.y),
action->m_image[i].get());
action->m_box[i] = m_dirty_box[i];
@@ -3105,7 +3099,12 @@ void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm:
if (has_data)
{
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
glReadPixels(bounds.x, bounds.y, box_sz.x, box_sz.y, rgba_pixel_format(), unsigned_byte_component_type(), action->m_image[i].get());
layer.rtt(i, frame).readPixelsRgba8(
static_cast<int>(bounds.x),
static_cast<int>(bounds.y),
static_cast<int>(box_sz.x),
static_cast<int>(box_sz.y),
action->m_image[i].get());
action->m_box[i] = bounds;
}
action->m_old_box[i] = layer.box(i, frame);

View File

@@ -92,22 +92,12 @@ Action* ActionStroke::get_redo()
{
action->m_image[i] = std::make_unique<uint8_t[]>(
static_cast<size_t>((int)box_sz.x) * static_cast<size_t>((int)box_sz.y) * 4U);
App::I->render_task([&]
{
const auto pixel_format = pp::renderer::gl::rgba_pixel_format();
const auto component_type = pp::renderer::gl::unsigned_byte_component_type();
layer->rtt(i, m_frame_idx).bindFramebuffer();
glReadPixels(
(int)box_or.x,
(int)box_or.y,
(int)box_sz.x,
(int)box_sz.y,
pixel_format,
component_type,
action->m_image[i].get());
layer->rtt(i, m_frame_idx).unbindFramebuffer();
});
layer->rtt(i, m_frame_idx).readPixelsRgba8(
static_cast<int>(box_or.x),
static_cast<int>(box_or.y),
static_cast<int>(box_sz.x),
static_cast<int>(box_sz.y),
action->m_image[i].get());
}
else
{

View File

@@ -561,14 +561,12 @@ LayerFrame::Snapshot LayerFrame::snapshot(std::array<glm::vec4, 6>* dirty_box /*
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
m_rtt[i].bindFramebuffer();
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
glReadPixels(static_cast<int>(snap.m_dirty_box[i].x), static_cast<int>(snap.m_dirty_box[i].y),
m_rtt[i].readPixelsRgba8(
static_cast<int>(snap.m_dirty_box[i].x),
static_cast<int>(snap.m_dirty_box[i].y),
static_cast<int>(box_sz.x), static_cast<int>(box_sz.y),
pp::renderer::gl::rgba_pixel_format(),
pp::renderer::gl::unsigned_byte_component_type(),
snap.image[i].get());
m_rtt[i].unbindFramebuffer();
}
});
return snap;

View File

@@ -1321,13 +1321,11 @@ void CanvasModeTransform::enter(kCanvasMode prev)
ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 0 });
layer->rtt(i).bindFramebuffer();
// copy framebuffer to action data
glReadPixels(
bb_min.x,
bb_min.y,
bb_sz.x,
bb_sz.y,
pp::renderer::gl::rgba_pixel_format(),
pp::renderer::gl::unsigned_byte_component_type(),
layer->rtt(i).readPixelsRgba8(
static_cast<int>(bb_min.x),
static_cast<int>(bb_min.y),
static_cast<int>(bb_sz.x),
static_cast<int>(bb_sz.y),
action->m_image[i].get());
for (int j = 0; j < 6; j++)
m_shape[j].draw_fill();
@@ -1426,13 +1424,11 @@ void CanvasModeTransform::leave(kCanvasMode next)
glViewport(0, 0, layer->rtt(i).getWidth(), layer->rtt(i).getHeight());
// save fb content for history
glReadPixels(
bb_min.x,
bb_min.y,
bb_sz.x,
bb_sz.y,
pp::renderer::gl::rgba_pixel_format(),
pp::renderer::gl::unsigned_byte_component_type(),
layer->rtt(i).readPixelsRgba8(
static_cast<int>(bb_min.x),
static_cast<int>(bb_min.y),
static_cast<int>(bb_sz.x),
static_cast<int>(bb_sz.y),
action->m_image[i].get());
// copy fb content to texture for blending
set_active_texture_unit(0);

View File

@@ -503,6 +503,38 @@ glm::ivec4 RTT::calc_bounds() const noexcept
return { bbmin, bbmax };
}
bool RTT::readPixelsRgba8(int x, int y, int width, int height, void* buffer) const noexcept
{
if (!valid() || buffer == nullptr)
return false;
bool ret = true;
App::I->render_task([&]
{
const auto readback = pp::renderer::gl::rgba8_readback_format();
const auto status = pp::renderer::gl::readback_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferReadback {
.framebuffer = static_cast<std::uint32_t>(fboID),
.x = x,
.y = y,
.width = width,
.height = height,
.format = readback,
.pixels = buffer,
},
pp::renderer::gl::OpenGlFramebufferReadbackDispatch {
.get_integer = query_opengl_integer,
.bind_framebuffer = bind_opengl_framebuffer,
.read_pixels = read_opengl_pixels,
});
if (!status.ok()) {
LOG("RTT::readPixelsRgba8() failed because: %s", status.message);
ret = false;
}
});
return ret;
}
uint8_t* RTT::readTextureData(uint8_t* buffer) const noexcept
{
if (!valid())

View File

@@ -68,6 +68,7 @@ public:
void clear(glm::vec4 color = glm::vec4(0));
void clear_mask(glm::bool4 mask, glm::vec4 color = glm::vec4(0));
glm::ivec4 calc_bounds() const noexcept;
bool readPixelsRgba8(int x, int y, int width, int height, void* buffer) const noexcept;
uint8_t* readTextureData(uint8_t* buffer = nullptr) const noexcept;
float* readTextureDataFloat(float* buffer = nullptr) const noexcept;
uint8_t* createBuffer() const noexcept;