Route RTT region readbacks through backend
This commit is contained in:
@@ -290,7 +290,9 @@ Known local toolchain state:
|
|||||||
allocation/storage/delete and framebuffer depth attach/detach also execute
|
allocation/storage/delete and framebuffer depth attach/detach also execute
|
||||||
through tested dispatch contracts here. Renderer API render-pass color/depth/stencil
|
through tested dispatch contracts here. Renderer API render-pass color/depth/stencil
|
||||||
clear-mask and clear-value mapping, and color-write-mask query tokens. `RTT` no longer
|
clear-mask and clear-value mapping, and color-write-mask query tokens. `RTT` no longer
|
||||||
spells GL enum names directly. It also
|
spells GL enum names directly. `RTT` also exposes a retained RGBA8
|
||||||
|
region-readback helper that uses the tested framebuffer readback dispatch for
|
||||||
|
canvas pick/history/snapshot and transform history paths. It also
|
||||||
validates renderer API primitive-topology to OpenGL draw-mode mapping, Shape
|
validates renderer API primitive-topology to OpenGL draw-mode mapping, Shape
|
||||||
index-type, fill/stroke primitive-mode, buffer target, static upload usage,
|
index-type, fill/stroke primitive-mode, buffer target, static upload usage,
|
||||||
and vertex attribute component/normalization mapping used by
|
and vertex attribute component/normalization mapping used by
|
||||||
@@ -410,12 +412,14 @@ Known local toolchain state:
|
|||||||
formats for cube-strip imports. Clamp-to-border sampler wrap is now part of
|
formats for cube-strip imports. Clamp-to-border sampler wrap is now part of
|
||||||
the backend capability catalog and test coverage.
|
the backend capability catalog and test coverage.
|
||||||
Early canvas draw helpers also consume backend-owned pick readback
|
Early canvas draw helpers also consume backend-owned pick readback
|
||||||
format/type, stroke mixer depth/scissor/blend state, saved viewport and
|
format/type and RTT-backed region-readback execution, stroke mixer
|
||||||
clear-state queries, active texture units, fallback 2D texture unbind
|
depth/scissor/blend state, saved viewport and clear-state queries, active
|
||||||
targets, and stroke background copy targets.
|
texture units, fallback 2D texture unbind targets, and stroke background copy
|
||||||
|
targets.
|
||||||
Canvas stroke commit also consumes backend-owned saved viewport/clear/blend
|
Canvas stroke commit also consumes backend-owned saved viewport/clear/blend
|
||||||
state, history readback format/type, active texture units, fallback 2D
|
state, history readback format/type and RTT-backed region-readback execution,
|
||||||
texture unbind targets, and layer compositing copy targets.
|
active texture units, fallback 2D texture unbind targets, and layer
|
||||||
|
compositing copy targets.
|
||||||
Canvas layer merge rendering and explicit layer-merge compositing also consume
|
Canvas layer merge rendering and explicit layer-merge compositing also consume
|
||||||
backend-owned depth/blend state, active texture units, fallback 2D texture
|
backend-owned depth/blend state, active texture units, fallback 2D texture
|
||||||
unbind targets, and merge framebuffer copy targets.
|
unbind targets, and merge framebuffer copy targets.
|
||||||
@@ -610,7 +614,8 @@ Known local toolchain state:
|
|||||||
VR draw state setup and restore, tested saved-state snapshot/restore dispatch
|
VR draw state setup and restore, tested saved-state snapshot/restore dispatch
|
||||||
consumed by the retained `gl_state` utility, tested texture lifecycle/readback dispatch consumed by
|
consumed by the retained `gl_state` utility, tested texture lifecycle/readback dispatch consumed by
|
||||||
the retained `Texture2D` utility, tested framebuffer blit/readback dispatch
|
the retained `Texture2D` utility, tested framebuffer blit/readback dispatch
|
||||||
consumed by retained `RTT` resize/copy/readback paths, tested framebuffer
|
consumed by retained `RTT` resize/copy/readback and RGBA8 region-readback
|
||||||
|
paths, tested framebuffer
|
||||||
bind/restore dispatch consumed by retained `RTT` render-target pass entry
|
bind/restore dispatch consumed by retained `RTT` render-target pass entry
|
||||||
and exit paths, tested depth renderbuffer allocation/delete and framebuffer
|
and exit paths, tested depth renderbuffer allocation/delete and framebuffer
|
||||||
depth attach/detach dispatch consumed by canvas object-drawing helpers,
|
depth attach/detach dispatch consumed by canvas object-drawing helpers,
|
||||||
|
|||||||
@@ -810,6 +810,10 @@ resource lifecycle path behind the renderer backend boundary.
|
|||||||
Legacy `RTT` resize/copy blits and byte/float framebuffer readbacks now execute
|
Legacy `RTT` resize/copy blits and byte/float framebuffer readbacks now execute
|
||||||
through tested `pp_renderer_gl` framebuffer dispatch contracts with draw/read
|
through tested `pp_renderer_gl` framebuffer dispatch contracts with draw/read
|
||||||
framebuffer binding restore handled by the backend helper.
|
framebuffer binding restore handled by the backend helper.
|
||||||
|
Legacy `RTT` also exposes an RGBA8 region-readback helper that uses the same
|
||||||
|
backend framebuffer readback dispatch; canvas pick/history/snapshot and
|
||||||
|
transform history paths now call that helper instead of binding an RTT and
|
||||||
|
calling `glReadPixels` directly.
|
||||||
Legacy `RTT::bindFramebuffer` and `RTT::unbindFramebuffer` now use tested
|
Legacy `RTT::bindFramebuffer` and `RTT::unbindFramebuffer` now use tested
|
||||||
`pp_renderer_gl` draw/read framebuffer binding snapshot and restore contracts,
|
`pp_renderer_gl` draw/read framebuffer binding snapshot and restore contracts,
|
||||||
moving render-target pass entry/exit state management behind the backend.
|
moving render-target pass entry/exit state management behind the backend.
|
||||||
@@ -1975,8 +1979,9 @@ Results:
|
|||||||
and fallback 2D texture unbinds through the renderer GL backend mapping;
|
and fallback 2D texture unbinds through the renderer GL backend mapping;
|
||||||
platform VR SDK bridges remain isolated for later platform-shell extraction.
|
platform VR SDK bridges remain isolated for later platform-shell extraction.
|
||||||
- Canvas mode overlay, mask, and transform paths now route generic OpenGL
|
- Canvas mode overlay, mask, and transform paths now route generic OpenGL
|
||||||
blend/depth state, active texture units, 2D copy targets, and RGBA8
|
blend/depth state, active texture units, 2D copy targets, RGBA8 readback
|
||||||
readback formats through the renderer GL backend mapping.
|
formats, and RTT-backed transform history region readbacks through the
|
||||||
|
renderer GL backend mapping.
|
||||||
- `NodeCanvas` panorama UI rendering now routes sampler defaults, saved
|
- `NodeCanvas` panorama UI rendering now routes sampler defaults, saved
|
||||||
viewport/clear/blend/depth/scissor state, color clears, active texture units,
|
viewport/clear/blend/depth/scissor state, color clears, active texture units,
|
||||||
fallback 2D texture unbinds, copy targets, and RGBA8 render-target formats
|
fallback 2D texture unbinds, copy targets, and RGBA8 render-target formats
|
||||||
@@ -1992,7 +1997,9 @@ Results:
|
|||||||
renderer GL backend mapping.
|
renderer GL backend mapping.
|
||||||
- Canvas stroke commit now routes saved viewport/clear/blend state, history
|
- Canvas stroke commit now routes saved viewport/clear/blend state, history
|
||||||
readbacks, active texture units, fallback 2D texture unbinds, and layer
|
readbacks, active texture units, fallback 2D texture unbinds, and layer
|
||||||
compositing copy targets through the renderer GL backend mapping.
|
compositing copy targets through the renderer GL backend mapping; the
|
||||||
|
RTT-backed dirty-region readbacks now execute through the retained `RTT`
|
||||||
|
region-readback helper rather than direct `glReadPixels`.
|
||||||
- Canvas layer merge rendering and explicit layer-merge compositing now route
|
- Canvas layer merge rendering and explicit layer-merge compositing now route
|
||||||
depth/blend state, active texture units, fallback 2D texture unbinds, and
|
depth/blend state, active texture units, fallback 2D texture unbinds, and
|
||||||
merge framebuffer copy targets through the renderer GL backend mapping.
|
merge framebuffer copy targets through the renderer GL backend mapping.
|
||||||
|
|||||||
@@ -325,18 +325,14 @@ void Canvas::pick_update(int plane)
|
|||||||
draw_merge(true, faces);
|
draw_merge(true, faces);
|
||||||
|
|
||||||
int i = plane;
|
int i = plane;
|
||||||
m_layers_merge.rtt(i).bindFramebuffer();
|
|
||||||
if (!m_pick_data[plane])
|
if (!m_pick_data[plane])
|
||||||
m_pick_data[plane] = std::make_unique<glm::u8vec4[]>(m_width * m_height);
|
m_pick_data[plane] = std::make_unique<glm::u8vec4[]>(m_width * m_height);
|
||||||
glReadPixels(
|
m_layers_merge.rtt(i).readPixelsRgba8(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
m_width,
|
m_width,
|
||||||
m_height,
|
m_height,
|
||||||
rgba_pixel_format(),
|
|
||||||
unsigned_byte_component_type(),
|
|
||||||
m_pick_data[plane].get());
|
m_pick_data[plane].get());
|
||||||
m_layers_merge.rtt(i).unbindFramebuffer();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_pick_ready[plane] = true;
|
m_pick_ready[plane] = true;
|
||||||
@@ -1030,13 +1026,11 @@ void Canvas::stroke_commit()
|
|||||||
// save image before commit
|
// save image before commit
|
||||||
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
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);
|
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
|
||||||
glReadPixels(
|
m_layers[m_current_layer_idx]->rtt(i).readPixelsRgba8(
|
||||||
m_dirty_box[i].x,
|
static_cast<int>(m_dirty_box[i].x),
|
||||||
m_dirty_box[i].y,
|
static_cast<int>(m_dirty_box[i].y),
|
||||||
box_sz.x,
|
static_cast<int>(box_sz.x),
|
||||||
box_sz.y,
|
static_cast<int>(box_sz.y),
|
||||||
rgba_pixel_format(),
|
|
||||||
unsigned_byte_component_type(),
|
|
||||||
action->m_image[i].get());
|
action->m_image[i].get());
|
||||||
|
|
||||||
action->m_box[i] = m_dirty_box[i];
|
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)
|
if (has_data)
|
||||||
{
|
{
|
||||||
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
|
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_box[i] = bounds;
|
||||||
}
|
}
|
||||||
action->m_old_box[i] = layer.box(i, frame);
|
action->m_old_box[i] = layer.box(i, frame);
|
||||||
|
|||||||
@@ -92,22 +92,12 @@ Action* ActionStroke::get_redo()
|
|||||||
{
|
{
|
||||||
action->m_image[i] = std::make_unique<uint8_t[]>(
|
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);
|
static_cast<size_t>((int)box_sz.x) * static_cast<size_t>((int)box_sz.y) * 4U);
|
||||||
App::I->render_task([&]
|
layer->rtt(i, m_frame_idx).readPixelsRgba8(
|
||||||
{
|
static_cast<int>(box_or.x),
|
||||||
const auto pixel_format = pp::renderer::gl::rgba_pixel_format();
|
static_cast<int>(box_or.y),
|
||||||
const auto component_type = pp::renderer::gl::unsigned_byte_component_type();
|
static_cast<int>(box_sz.x),
|
||||||
|
static_cast<int>(box_sz.y),
|
||||||
layer->rtt(i, m_frame_idx).bindFramebuffer();
|
action->m_image[i].get());
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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());
|
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]);
|
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),
|
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());
|
snap.image[i].get());
|
||||||
m_rtt[i].unbindFramebuffer();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return snap;
|
return snap;
|
||||||
|
|||||||
@@ -1321,13 +1321,11 @@ void CanvasModeTransform::enter(kCanvasMode prev)
|
|||||||
ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 0 });
|
ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 0 });
|
||||||
layer->rtt(i).bindFramebuffer();
|
layer->rtt(i).bindFramebuffer();
|
||||||
// copy framebuffer to action data
|
// copy framebuffer to action data
|
||||||
glReadPixels(
|
layer->rtt(i).readPixelsRgba8(
|
||||||
bb_min.x,
|
static_cast<int>(bb_min.x),
|
||||||
bb_min.y,
|
static_cast<int>(bb_min.y),
|
||||||
bb_sz.x,
|
static_cast<int>(bb_sz.x),
|
||||||
bb_sz.y,
|
static_cast<int>(bb_sz.y),
|
||||||
pp::renderer::gl::rgba_pixel_format(),
|
|
||||||
pp::renderer::gl::unsigned_byte_component_type(),
|
|
||||||
action->m_image[i].get());
|
action->m_image[i].get());
|
||||||
for (int j = 0; j < 6; j++)
|
for (int j = 0; j < 6; j++)
|
||||||
m_shape[j].draw_fill();
|
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());
|
glViewport(0, 0, layer->rtt(i).getWidth(), layer->rtt(i).getHeight());
|
||||||
|
|
||||||
// save fb content for history
|
// save fb content for history
|
||||||
glReadPixels(
|
layer->rtt(i).readPixelsRgba8(
|
||||||
bb_min.x,
|
static_cast<int>(bb_min.x),
|
||||||
bb_min.y,
|
static_cast<int>(bb_min.y),
|
||||||
bb_sz.x,
|
static_cast<int>(bb_sz.x),
|
||||||
bb_sz.y,
|
static_cast<int>(bb_sz.y),
|
||||||
pp::renderer::gl::rgba_pixel_format(),
|
|
||||||
pp::renderer::gl::unsigned_byte_component_type(),
|
|
||||||
action->m_image[i].get());
|
action->m_image[i].get());
|
||||||
// copy fb content to texture for blending
|
// copy fb content to texture for blending
|
||||||
set_active_texture_unit(0);
|
set_active_texture_unit(0);
|
||||||
|
|||||||
32
src/rtt.cpp
32
src/rtt.cpp
@@ -503,6 +503,38 @@ glm::ivec4 RTT::calc_bounds() const noexcept
|
|||||||
return { bbmin, bbmax };
|
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
|
uint8_t* RTT::readTextureData(uint8_t* buffer) const noexcept
|
||||||
{
|
{
|
||||||
if (!valid())
|
if (!valid())
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public:
|
|||||||
void clear(glm::vec4 color = glm::vec4(0));
|
void clear(glm::vec4 color = glm::vec4(0));
|
||||||
void clear_mask(glm::bool4 mask, glm::vec4 color = glm::vec4(0));
|
void clear_mask(glm::bool4 mask, glm::vec4 color = glm::vec4(0));
|
||||||
glm::ivec4 calc_bounds() const noexcept;
|
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;
|
uint8_t* readTextureData(uint8_t* buffer = nullptr) const noexcept;
|
||||||
float* readTextureDataFloat(float* buffer = nullptr) const noexcept;
|
float* readTextureDataFloat(float* buffer = nullptr) const noexcept;
|
||||||
uint8_t* createBuffer() const noexcept;
|
uint8_t* createBuffer() const noexcept;
|
||||||
|
|||||||
Reference in New Issue
Block a user