Move readback format mapping to renderer gl
This commit is contained in:
@@ -129,7 +129,8 @@ Known local toolchain state:
|
|||||||
GLES float/half-float extensions, WebGL exclusion behavior, and the
|
GLES float/half-float extensions, WebGL exclusion behavior, and the
|
||||||
upload-type mapping used by legacy `Texture2D` and `RTT` creation. It also
|
upload-type mapping used by legacy `Texture2D` and `RTT` creation. It also
|
||||||
validates image channel-count to OpenGL texture format mapping, including
|
validates image channel-count to OpenGL texture format mapping, including
|
||||||
invalid channel counts rejected by `Texture2D::create(Image)`, and
|
invalid channel counts rejected by `Texture2D::create(Image)`, RGBA8/RGBA32F
|
||||||
|
readback formats and byte-count math used by `RTT` and `PBO` readbacks, and
|
||||||
framebuffer status naming used by `RTT` diagnostics. It also owns and
|
framebuffer status naming used by `RTT` diagnostics. It also owns and
|
||||||
validates framebuffer blit color mask and linear/nearest filters used by
|
validates framebuffer blit color mask and linear/nearest filters used by
|
||||||
`RTT::resize` and `RTT::copy`, plus the default linear clamp-to-edge
|
`RTT::resize` and `RTT::copy`, plus the default linear clamp-to-edge
|
||||||
|
|||||||
@@ -390,9 +390,11 @@ OpenGL capability detection for framebuffer fetch, map-buffer alignment, and
|
|||||||
float texture support. It also owns the OpenGL texture upload-type mapping used
|
float texture support. It also owns the OpenGL texture upload-type mapping used
|
||||||
by legacy `Texture2D` and `RTT` creation, plus image channel-count to texture
|
by legacy `Texture2D` and `RTT` creation, plus image channel-count to texture
|
||||||
format mapping for `Texture2D` image uploads and framebuffer status naming for
|
format mapping for `Texture2D` image uploads and framebuffer status naming for
|
||||||
`RTT` diagnostics. The framebuffer blit color mask and linear/nearest filter
|
`RTT` diagnostics. RGBA8/RGBA32F readback formats and byte-count math used by
|
||||||
tokens used by `RTT::resize` and `RTT::copy`, plus the default render-target
|
`RTT` and `PBO` readbacks now live in `pp_renderer_gl`. The framebuffer blit
|
||||||
texture parameters used by `RTT::create`, also live in `pp_renderer_gl`.
|
color mask and linear/nearest filter tokens used by `RTT::resize` and
|
||||||
|
`RTT::copy`, plus the default render-target texture parameters used by
|
||||||
|
`RTT::create`, also live in `pp_renderer_gl`.
|
||||||
Mesh index-type and primitive-mode
|
Mesh index-type and primitive-mode
|
||||||
decisions used by legacy `Shape` drawing and the PanoPainter cube-face to
|
decisions used by legacy `Shape` drawing and the PanoPainter cube-face to
|
||||||
OpenGL texture-target mapping used by `TextureCube` also live in
|
OpenGL texture-target mapping used by `TextureCube` also live in
|
||||||
@@ -646,8 +648,9 @@ Results:
|
|||||||
alignment, desktop GL core float support, GLES float/half-float extensions,
|
alignment, desktop GL core float support, GLES float/half-float extensions,
|
||||||
WebGL exclusion behavior, upload types for RGBA8/RGBA16F/RGBA32F internal
|
WebGL exclusion behavior, upload types for RGBA8/RGBA16F/RGBA32F internal
|
||||||
formats, image channel-count format mapping including invalid counts, and
|
formats, image channel-count format mapping including invalid counts, and
|
||||||
framebuffer status names, framebuffer blit color mask and linear/nearest
|
RGBA8/RGBA32F readback format and byte-count mapping, framebuffer status
|
||||||
filters, plus Shape index-type and fill/stroke primitive mode mapping,
|
names, framebuffer blit color mask and linear/nearest filters, plus Shape
|
||||||
|
index-type and fill/stroke primitive mode mapping,
|
||||||
PanoPainter cube-face texture-target order, and the linear clamp-to-edge
|
PanoPainter cube-face texture-target order, and the linear clamp-to-edge
|
||||||
render-target texture parameter set used by `RTT::create`.
|
render-target texture parameter set used by `RTT::create`.
|
||||||
Sampler parameter validation covers wrap S/T/R plus min/mag filter ordering
|
Sampler parameter validation covers wrap S/T/R plus min/mag filter ordering
|
||||||
|
|||||||
@@ -123,6 +123,32 @@ OpenGlPixelFormat texture_format_for_channel_count(std::uint32_t channel_count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGlReadbackFormat rgba8_readback_format() noexcept
|
||||||
|
{
|
||||||
|
return OpenGlReadbackFormat {
|
||||||
|
.pixel_format = gl_rgba,
|
||||||
|
.component_type = gl_unsigned_byte,
|
||||||
|
.bytes_per_pixel = 4U,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlReadbackFormat rgba32f_readback_format() noexcept
|
||||||
|
{
|
||||||
|
return OpenGlReadbackFormat {
|
||||||
|
.pixel_format = gl_rgba,
|
||||||
|
.component_type = gl_float,
|
||||||
|
.bytes_per_pixel = 16U,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t readback_byte_count(
|
||||||
|
OpenGlReadbackFormat format,
|
||||||
|
std::uint32_t width,
|
||||||
|
std::uint32_t height) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint64_t>(width) * height * format.bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
const char* framebuffer_status_name(std::uint32_t status) noexcept
|
const char* framebuffer_status_name(std::uint32_t status) noexcept
|
||||||
{
|
{
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|||||||
@@ -32,12 +32,24 @@ struct OpenGlTextureParameter {
|
|||||||
std::uint32_t value = 0;
|
std::uint32_t value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlReadbackFormat {
|
||||||
|
std::uint32_t pixel_format = 0;
|
||||||
|
std::uint32_t component_type = 0;
|
||||||
|
std::uint32_t bytes_per_pixel = 0;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
|
[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
|
||||||
std::span<const std::string_view> extensions,
|
std::span<const std::string_view> extensions,
|
||||||
OpenGlRuntime runtime) noexcept;
|
OpenGlRuntime runtime) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] std::uint32_t texture_upload_type_for_internal_format(std::uint32_t internal_format) noexcept;
|
[[nodiscard]] std::uint32_t texture_upload_type_for_internal_format(std::uint32_t internal_format) noexcept;
|
||||||
[[nodiscard]] OpenGlPixelFormat texture_format_for_channel_count(std::uint32_t channel_count) noexcept;
|
[[nodiscard]] OpenGlPixelFormat texture_format_for_channel_count(std::uint32_t channel_count) noexcept;
|
||||||
|
[[nodiscard]] OpenGlReadbackFormat rgba8_readback_format() noexcept;
|
||||||
|
[[nodiscard]] OpenGlReadbackFormat rgba32f_readback_format() noexcept;
|
||||||
|
[[nodiscard]] std::uint64_t readback_byte_count(
|
||||||
|
OpenGlReadbackFormat format,
|
||||||
|
std::uint32_t width,
|
||||||
|
std::uint32_t height) noexcept;
|
||||||
[[nodiscard]] const char* framebuffer_status_name(std::uint32_t status) noexcept;
|
[[nodiscard]] const char* framebuffer_status_name(std::uint32_t status) noexcept;
|
||||||
[[nodiscard]] std::uint32_t framebuffer_color_buffer_mask() noexcept;
|
[[nodiscard]] std::uint32_t framebuffer_color_buffer_mask() noexcept;
|
||||||
[[nodiscard]] std::uint32_t framebuffer_blit_filter(bool linear) noexcept;
|
[[nodiscard]] std::uint32_t framebuffer_blit_filter(bool linear) noexcept;
|
||||||
|
|||||||
59
src/rtt.cpp
59
src/rtt.cpp
@@ -358,10 +358,18 @@ uint8_t* RTT::readTextureData(uint8_t* buffer) const noexcept
|
|||||||
buffer = createBuffer();
|
buffer = createBuffer();
|
||||||
App::I->render_task([&]
|
App::I->render_task([&]
|
||||||
{
|
{
|
||||||
|
const auto readback = pp::renderer::gl::rgba8_readback_format();
|
||||||
GLint old;
|
GLint old;
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
glReadPixels(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
static_cast<GLenum>(readback.pixel_format),
|
||||||
|
static_cast<GLenum>(readback.component_type),
|
||||||
|
buffer);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||||
});
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -375,10 +383,18 @@ float* RTT::readTextureDataFloat(float* buffer) const noexcept
|
|||||||
buffer = createBufferFloat();
|
buffer = createBufferFloat();
|
||||||
App::I->render_task([&]
|
App::I->render_task([&]
|
||||||
{
|
{
|
||||||
|
const auto readback = pp::renderer::gl::rgba32f_readback_format();
|
||||||
GLint old;
|
GLint old;
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
glReadPixels(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
static_cast<GLenum>(readback.pixel_format),
|
||||||
|
static_cast<GLenum>(readback.component_type),
|
||||||
|
buffer);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||||
});
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -386,12 +402,21 @@ float* RTT::readTextureDataFloat(float* buffer) const noexcept
|
|||||||
|
|
||||||
uint8_t* RTT::createBuffer() const noexcept
|
uint8_t* RTT::createBuffer() const noexcept
|
||||||
{
|
{
|
||||||
return new uint8_t[w * h * 4];
|
const auto readback = pp::renderer::gl::rgba8_readback_format();
|
||||||
|
return new uint8_t[pp::renderer::gl::readback_byte_count(
|
||||||
|
readback,
|
||||||
|
static_cast<std::uint32_t>(w),
|
||||||
|
static_cast<std::uint32_t>(h))];
|
||||||
}
|
}
|
||||||
|
|
||||||
float * RTT::createBufferFloat() const noexcept
|
float * RTT::createBufferFloat() const noexcept
|
||||||
{
|
{
|
||||||
return new float[w * h * 4];
|
const auto readback = pp::renderer::gl::rgba32f_readback_format();
|
||||||
|
return new float[pp::renderer::gl::readback_byte_count(
|
||||||
|
readback,
|
||||||
|
static_cast<std::uint32_t>(w),
|
||||||
|
static_cast<std::uint32_t>(h))
|
||||||
|
/ sizeof(float)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTT::bindTexture()
|
void RTT::bindTexture()
|
||||||
@@ -467,11 +492,26 @@ bool PBO::create(RTT& rtt) noexcept
|
|||||||
App::I->render_task([this, &rtt] {
|
App::I->render_task([this, &rtt] {
|
||||||
width = rtt.getWidth();
|
width = rtt.getWidth();
|
||||||
height = rtt.getHeight();
|
height = rtt.getHeight();
|
||||||
|
const auto readback = pp::renderer::gl::rgba8_readback_format();
|
||||||
rtt.bindFramebuffer();
|
rtt.bindFramebuffer();
|
||||||
glGenBuffers(1, &buffer_id);
|
glGenBuffers(1, &buffer_id);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_id);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_id);
|
||||||
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4, 0, GL_STREAM_READ);
|
glBufferData(
|
||||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
GL_PIXEL_PACK_BUFFER,
|
||||||
|
static_cast<GLsizeiptr>(pp::renderer::gl::readback_byte_count(
|
||||||
|
readback,
|
||||||
|
static_cast<std::uint32_t>(width),
|
||||||
|
static_cast<std::uint32_t>(height))),
|
||||||
|
0,
|
||||||
|
GL_STREAM_READ);
|
||||||
|
glReadPixels(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
static_cast<GLenum>(readback.pixel_format),
|
||||||
|
static_cast<GLenum>(readback.component_type),
|
||||||
|
0);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||||
rtt.unbindFramebuffer();
|
rtt.unbindFramebuffer();
|
||||||
});
|
});
|
||||||
@@ -513,9 +553,14 @@ void PBO::unbind() noexcept
|
|||||||
glm::uint8_t* PBO::map() noexcept
|
glm::uint8_t* PBO::map() noexcept
|
||||||
{
|
{
|
||||||
App::I->render_task([this] {
|
App::I->render_task([this] {
|
||||||
|
const auto readback = pp::renderer::gl::rgba8_readback_format();
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_id);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_id);
|
||||||
mapped_ptr = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
mapped_ptr = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
||||||
width * height * 4, GL_MAP_READ_BIT);
|
static_cast<GLsizeiptr>(pp::renderer::gl::readback_byte_count(
|
||||||
|
readback,
|
||||||
|
static_cast<std::uint32_t>(width),
|
||||||
|
static_cast<std::uint32_t>(height))),
|
||||||
|
GL_MAP_READ_BIT);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||||
});
|
});
|
||||||
return mapped_ptr;
|
return mapped_ptr;
|
||||||
|
|||||||
@@ -116,6 +116,22 @@ void maps_image_channel_count_to_texture_format(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, invalid.pixel_format == 0U);
|
PP_EXPECT(h, invalid.pixel_format == 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void maps_readback_formats(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto rgba8 = pp::renderer::gl::rgba8_readback_format();
|
||||||
|
const auto rgba32f = pp::renderer::gl::rgba32f_readback_format();
|
||||||
|
|
||||||
|
PP_EXPECT(h, rgba8.pixel_format == 0x1908U);
|
||||||
|
PP_EXPECT(h, rgba8.component_type == 0x1401U);
|
||||||
|
PP_EXPECT(h, rgba8.bytes_per_pixel == 4U);
|
||||||
|
PP_EXPECT(h, pp::renderer::gl::readback_byte_count(rgba8, 3U, 5U) == 60U);
|
||||||
|
|
||||||
|
PP_EXPECT(h, rgba32f.pixel_format == 0x1908U);
|
||||||
|
PP_EXPECT(h, rgba32f.component_type == 0x1406U);
|
||||||
|
PP_EXPECT(h, rgba32f.bytes_per_pixel == 16U);
|
||||||
|
PP_EXPECT(h, pp::renderer::gl::readback_byte_count(rgba32f, 3U, 5U) == 240U);
|
||||||
|
}
|
||||||
|
|
||||||
void names_framebuffer_status_codes(pp::tests::Harness& h)
|
void names_framebuffer_status_codes(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
PP_EXPECT(h, pp::renderer::gl::framebuffer_status_name(0x8CD5U) == std::string_view("GL_FRAMEBUFFER_COMPLETE"));
|
PP_EXPECT(h, pp::renderer::gl::framebuffer_status_name(0x8CD5U) == std::string_view("GL_FRAMEBUFFER_COMPLETE"));
|
||||||
@@ -322,6 +338,7 @@ int main()
|
|||||||
harness.run("ignores_gles_texture_extensions_for_webgl_runtime", ignores_gles_texture_extensions_for_webgl_runtime);
|
harness.run("ignores_gles_texture_extensions_for_webgl_runtime", ignores_gles_texture_extensions_for_webgl_runtime);
|
||||||
harness.run("selects_texture_upload_type_from_internal_format", selects_texture_upload_type_from_internal_format);
|
harness.run("selects_texture_upload_type_from_internal_format", selects_texture_upload_type_from_internal_format);
|
||||||
harness.run("maps_image_channel_count_to_texture_format", maps_image_channel_count_to_texture_format);
|
harness.run("maps_image_channel_count_to_texture_format", maps_image_channel_count_to_texture_format);
|
||||||
|
harness.run("maps_readback_formats", maps_readback_formats);
|
||||||
harness.run("names_framebuffer_status_codes", names_framebuffer_status_codes);
|
harness.run("names_framebuffer_status_codes", names_framebuffer_status_codes);
|
||||||
harness.run("maps_framebuffer_blit_parameters", maps_framebuffer_blit_parameters);
|
harness.run("maps_framebuffer_blit_parameters", maps_framebuffer_blit_parameters);
|
||||||
harness.run("maps_shape_index_and_primitive_modes", maps_shape_index_and_primitive_modes);
|
harness.run("maps_shape_index_and_primitive_modes", maps_shape_index_and_primitive_modes);
|
||||||
|
|||||||
Reference in New Issue
Block a user