Route RTT lifecycle through GL backend

This commit is contained in:
2026-06-04 21:47:19 +02:00
parent fc20851462
commit ce787ce186
7 changed files with 569 additions and 77 deletions

View File

@@ -748,6 +748,33 @@ pp::foundation::Status update_opengl_texture_2d(
return pp::foundation::Status::success();
}
pp::foundation::Status set_opengl_texture_2d_parameters(
std::uint32_t texture_id,
std::span<const OpenGlTextureParameter> parameters,
OpenGlTexture2DParameterDispatch dispatch) noexcept
{
if (dispatch.bind_texture == nullptr || dispatch.tex_parameter_f == nullptr) {
return pp::foundation::Status::invalid_argument("OpenGL texture parameter dispatch callbacks must not be null");
}
if (texture_id == 0U || parameters.empty()) {
return pp::foundation::Status::invalid_argument("OpenGL texture parameter request is invalid");
}
for (const auto parameter : parameters) {
if (parameter.name == 0U) {
return pp::foundation::Status::invalid_argument("OpenGL texture parameter name is invalid");
}
}
dispatch.bind_texture(texture_2d_target(), texture_id);
for (const auto parameter : parameters) {
dispatch.tex_parameter_f(texture_2d_target(), parameter.name, static_cast<float>(parameter.value));
}
dispatch.bind_texture(texture_2d_target(), default_framebuffer_id());
return pp::foundation::Status::success();
}
pp::foundation::Status copy_opengl_framebuffer_to_texture_2d(
OpenGlTexture2DFramebufferCopy copy,
OpenGlTexture2DFramebufferCopyDispatch dispatch) noexcept
@@ -969,6 +996,78 @@ pp::foundation::Status restore_opengl_framebuffer_binding(
return pp::foundation::Status::success();
}
pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult> allocate_opengl_render_target_framebuffer(
std::uint32_t texture_id,
std::uint32_t depth_renderbuffer_id,
OpenGlRenderTargetFramebufferAllocationDispatch dispatch) noexcept
{
if (dispatch.gen_framebuffers == nullptr
|| dispatch.get_integer == nullptr
|| dispatch.bind_framebuffer == nullptr
|| dispatch.framebuffer_texture_2d == nullptr
|| dispatch.framebuffer_renderbuffer == nullptr
|| dispatch.check_framebuffer_status == nullptr) {
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
pp::foundation::Status::invalid_argument(
"OpenGL render-target framebuffer allocation dispatch callbacks must not be null"));
}
if (texture_id == 0U) {
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
pp::foundation::Status::invalid_argument("OpenGL render-target framebuffer texture id is invalid"));
}
std::int32_t old_framebuffer = 0;
dispatch.get_integer(draw_framebuffer_binding_query(), &old_framebuffer);
std::uint32_t framebuffer_id = 0U;
dispatch.gen_framebuffers(1U, &framebuffer_id);
if (framebuffer_id == 0U) {
dispatch.bind_framebuffer(framebuffer_target(), static_cast<std::uint32_t>(old_framebuffer));
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
pp::foundation::Status::out_of_range("OpenGL render-target framebuffer allocation returned id 0"));
}
dispatch.bind_framebuffer(framebuffer_target(), framebuffer_id);
dispatch.framebuffer_texture_2d(
framebuffer_target(),
framebuffer_color_attachment(),
texture_2d_target(),
texture_id,
0);
if (depth_renderbuffer_id != 0U) {
dispatch.framebuffer_renderbuffer(
framebuffer_target(),
framebuffer_depth_attachment(),
renderbuffer_target(),
depth_renderbuffer_id);
}
const auto framebuffer_status = dispatch.check_framebuffer_status(framebuffer_target());
dispatch.bind_framebuffer(framebuffer_target(), static_cast<std::uint32_t>(old_framebuffer));
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::success(
OpenGlRenderTargetFramebufferAllocationResult {
.framebuffer_id = framebuffer_id,
.framebuffer_status = framebuffer_status,
});
}
pp::foundation::Status delete_opengl_framebuffer(
std::uint32_t framebuffer_id,
OpenGlFramebufferDeleteDispatch dispatch) noexcept
{
if (dispatch.delete_framebuffers == nullptr) {
return pp::foundation::Status::invalid_argument("OpenGL framebuffer delete dispatch callback must not be null");
}
if (framebuffer_id == 0U) {
return pp::foundation::Status::success();
}
dispatch.delete_framebuffers(1U, &framebuffer_id);
return pp::foundation::Status::success();
}
pp::foundation::Result<std::uint32_t> allocate_opengl_pixel_buffer(
OpenGlPixelBufferAllocationDispatch dispatch) noexcept
{

View File

@@ -172,6 +172,11 @@ struct OpenGlTexture2DReadbackResult {
bool pixels_read = false;
};
struct OpenGlRenderTargetFramebufferAllocationResult {
std::uint32_t framebuffer_id = 0;
std::uint32_t framebuffer_status = 0;
};
struct OpenGlShaderCompileInfo {
std::uint32_t shader_id = 0;
std::int32_t compile_status = 0;
@@ -442,6 +447,7 @@ using OpenGlTexSubImage2DFn = void (*)(
std::uint32_t pixel_format,
std::uint32_t component_type,
const void* data) noexcept;
using OpenGlTexParameterfFn = void (*)(std::uint32_t target, std::uint32_t parameter, float value) noexcept;
using OpenGlCopyTexSubImage2DFn = void (*)(
std::uint32_t target,
std::int32_t level,
@@ -607,6 +613,11 @@ struct OpenGlTexture2DUpdateDispatch {
OpenGlTexSubImage2DFn tex_sub_image_2d = nullptr;
};
struct OpenGlTexture2DParameterDispatch {
OpenGlBindTextureFn bind_texture = nullptr;
OpenGlTexParameterfFn tex_parameter_f = nullptr;
};
struct OpenGlTexture2DFramebufferCopyDispatch {
OpenGlCopyTexSubImage2DFn copy_tex_sub_image_2d = nullptr;
};
@@ -648,6 +659,19 @@ struct OpenGlFramebufferRestoreDispatch {
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
};
struct OpenGlRenderTargetFramebufferAllocationDispatch {
OpenGlGenObjectsFn gen_framebuffers = nullptr;
OpenGlGetIntegerFn get_integer = nullptr;
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
OpenGlFramebufferTexture2DFn framebuffer_texture_2d = nullptr;
OpenGlFramebufferRenderbufferFn framebuffer_renderbuffer = nullptr;
OpenGlCheckFramebufferStatusFn check_framebuffer_status = nullptr;
};
struct OpenGlFramebufferDeleteDispatch {
OpenGlDeleteObjectsFn delete_framebuffers = nullptr;
};
struct OpenGlPixelBufferAllocationDispatch {
OpenGlGenObjectsFn gen_buffers = nullptr;
};
@@ -874,6 +898,10 @@ struct OpenGlMeshDeleteDispatch {
[[nodiscard]] pp::foundation::Status update_opengl_texture_2d(
OpenGlTexture2DUpdate update,
OpenGlTexture2DUpdateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_texture_2d_parameters(
std::uint32_t texture_id,
std::span<const OpenGlTextureParameter> parameters,
OpenGlTexture2DParameterDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status copy_opengl_framebuffer_to_texture_2d(
OpenGlTexture2DFramebufferCopy copy,
OpenGlTexture2DFramebufferCopyDispatch dispatch) noexcept;
@@ -895,6 +923,13 @@ struct OpenGlMeshDeleteDispatch {
[[nodiscard]] pp::foundation::Status restore_opengl_framebuffer_binding(
OpenGlFramebufferBindingState binding,
OpenGlFramebufferRestoreDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult> allocate_opengl_render_target_framebuffer(
std::uint32_t texture_id,
std::uint32_t depth_renderbuffer_id,
OpenGlRenderTargetFramebufferAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_framebuffer(
std::uint32_t framebuffer_id,
OpenGlFramebufferDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_pixel_buffer(
OpenGlPixelBufferAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> readback_opengl_framebuffer_to_pixel_buffer(

View File

@@ -34,6 +34,120 @@ void bind_opengl_framebuffer(std::uint32_t target, std::uint32_t framebuffer) no
glBindFramebuffer(static_cast<GLenum>(target), static_cast<GLuint>(framebuffer));
}
void gen_opengl_textures(std::uint32_t count, std::uint32_t* ids) noexcept
{
glGenTextures(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
}
void delete_opengl_textures(std::uint32_t count, const std::uint32_t* ids) noexcept
{
glDeleteTextures(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
}
void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
{
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
}
void set_opengl_texture_2d_image(
std::uint32_t target,
std::int32_t level,
std::int32_t internal_format,
std::int32_t width,
std::int32_t height,
std::int32_t border,
std::uint32_t pixel_format,
std::uint32_t component_type,
const void* data) noexcept
{
glTexImage2D(
static_cast<GLenum>(target),
static_cast<GLint>(level),
static_cast<GLint>(internal_format),
static_cast<GLsizei>(width),
static_cast<GLsizei>(height),
static_cast<GLint>(border),
static_cast<GLenum>(pixel_format),
static_cast<GLenum>(component_type),
data);
}
void set_opengl_texture_parameter_f(std::uint32_t target, std::uint32_t parameter, float value) noexcept
{
glTexParameterf(static_cast<GLenum>(target), static_cast<GLenum>(parameter), static_cast<GLfloat>(value));
}
void gen_opengl_renderbuffers(std::uint32_t count, std::uint32_t* ids) noexcept
{
glGenRenderbuffers(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
}
void delete_opengl_renderbuffers(std::uint32_t count, const std::uint32_t* ids) noexcept
{
glDeleteRenderbuffers(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
}
void bind_opengl_renderbuffer(std::uint32_t target, std::uint32_t renderbuffer) noexcept
{
glBindRenderbuffer(static_cast<GLenum>(target), static_cast<GLuint>(renderbuffer));
}
void set_opengl_renderbuffer_storage(
std::uint32_t target,
std::uint32_t internal_format,
std::int32_t width,
std::int32_t height) noexcept
{
glRenderbufferStorage(
static_cast<GLenum>(target),
static_cast<GLenum>(internal_format),
static_cast<GLsizei>(width),
static_cast<GLsizei>(height));
}
void gen_opengl_framebuffers(std::uint32_t count, std::uint32_t* ids) noexcept
{
glGenFramebuffers(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
}
void delete_opengl_framebuffers(std::uint32_t count, const std::uint32_t* ids) noexcept
{
glDeleteFramebuffers(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
}
void attach_opengl_framebuffer_texture_2d(
std::uint32_t target,
std::uint32_t attachment,
std::uint32_t texture_target,
std::uint32_t texture,
std::int32_t level) noexcept
{
glFramebufferTexture2D(
static_cast<GLenum>(target),
static_cast<GLenum>(attachment),
static_cast<GLenum>(texture_target),
static_cast<GLuint>(texture),
static_cast<GLint>(level));
}
void attach_opengl_framebuffer_renderbuffer(
std::uint32_t target,
std::uint32_t attachment,
std::uint32_t renderbuffer_target,
std::uint32_t renderbuffer) noexcept
{
glFramebufferRenderbuffer(
static_cast<GLenum>(target),
static_cast<GLenum>(attachment),
static_cast<GLenum>(renderbuffer_target),
static_cast<GLuint>(renderbuffer));
}
std::uint32_t check_opengl_framebuffer_status(std::uint32_t target) noexcept
{
return static_cast<std::uint32_t>(glCheckFramebufferStatus(static_cast<GLenum>(target)));
}
void blit_opengl_framebuffer(
std::int32_t source_x0,
std::int32_t source_y0,
@@ -243,18 +357,36 @@ void RTT::destroy()
{
if (rboID)
{
glDeleteRenderbuffers(1, &rboID);
const auto status = pp::renderer::gl::delete_opengl_renderbuffer(
static_cast<std::uint32_t>(rboID),
pp::renderer::gl::OpenGlRenderbufferDeleteDispatch {
.delete_renderbuffers = delete_opengl_renderbuffers,
});
if (!status.ok())
LOG("RTT::destroy renderbuffer delete failed because: %s", status.message);
}
if (texID)
{
//unbindTexture();
glDeleteTextures(1, &texID);
const auto status = pp::renderer::gl::delete_opengl_texture_2d(
static_cast<std::uint32_t>(texID),
pp::renderer::gl::OpenGlTexture2DDeleteDispatch {
.delete_textures = delete_opengl_textures,
});
if (!status.ok())
LOG("RTT::destroy texture delete failed because: %s", status.message);
//LOG("TEX rtt destroy %d", texID)
}
if (fboID)
{
//unbindFramebuffer();
glDeleteFramebuffers(1, &fboID);
const auto status = pp::renderer::gl::delete_opengl_framebuffer(
static_cast<std::uint32_t>(fboID),
pp::renderer::gl::OpenGlFramebufferDeleteDispatch {
.delete_framebuffers = delete_opengl_framebuffers,
});
if (!status.ok())
LOG("RTT::destroy framebuffer delete failed because: %s", status.message);
//LOG("RTT DESTROY %d", fboID);
}
});
@@ -354,7 +486,7 @@ bool RTT::create(int width, int height, int tex)
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
{
GLenum status = 0;
std::uint32_t status = 0;
App::I->render_task([&]
{
// Destroy any previously created object
@@ -366,7 +498,28 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
if (tex == -1)
{
glGenTextures(1, &texID);
const auto texture = pp::renderer::gl::allocate_opengl_texture_2d(
pp::renderer::gl::OpenGlTexture2DAllocation {
.width = width,
.height = height,
.internal_format = internal_format,
.pixel_format = pp::renderer::gl::rgba_pixel_format(),
.component_type = pp::renderer::gl::texture_upload_type_for_internal_format(
static_cast<std::uint32_t>(internal_format)),
.data = nullptr,
},
pp::renderer::gl::OpenGlTexture2DAllocationDispatch {
.gen_textures = gen_opengl_textures,
.bind_texture = bind_opengl_texture,
.tex_image_2d = set_opengl_texture_2d_image,
});
if (!texture.ok())
{
LOG("RTT::create texture allocation failed because: %s", texture.status().message);
status = 0;
return;
}
texID = static_cast<GLuint>(texture.value());
//LOG("TEX rtt create %d", texID);
}
else
@@ -374,81 +527,72 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
texID = tex;
}
const auto ifmt = static_cast<GLenum>(
pp::renderer::gl::texture_upload_type_for_internal_format(static_cast<std::uint32_t>(internal_format)));
glBindTexture(texture_2d_target(), texID);
if (tex == -1)
glTexImage2D(
texture_2d_target(),
0,
internal_format,
width,
height,
0,
static_cast<GLenum>(pp::renderer::gl::rgba_pixel_format()),
ifmt,
0);
for (const auto parameter : pp::renderer::gl::default_render_target_texture_parameters())
const auto parameter_status = pp::renderer::gl::set_opengl_texture_2d_parameters(
static_cast<std::uint32_t>(texID),
pp::renderer::gl::default_render_target_texture_parameters(),
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
.bind_texture = bind_opengl_texture,
.tex_parameter_f = set_opengl_texture_parameter_f,
});
if (!parameter_status.ok())
{
glTexParameterf(
texture_2d_target(),
static_cast<GLenum>(parameter.name),
static_cast<GLfloat>(parameter.value));
LOG("RTT::create texture parameter setup failed because: %s", parameter_status.message);
status = 0;
return;
}
glBindTexture(texture_2d_target(), 0);
// Create a renderbuffer object to store depth info
if (depth_buffer)
{
glGenRenderbuffers(1, &rboID);
glBindRenderbuffer(renderbuffer_target(), rboID);
glRenderbufferStorage(
renderbuffer_target(),
static_cast<GLenum>(pp::renderer::gl::depth_component24_format()),
const auto renderbuffer = pp::renderer::gl::allocate_opengl_depth_renderbuffer(
width,
height);
glBindRenderbuffer(renderbuffer_target(), 0);
height,
pp::renderer::gl::OpenGlDepthRenderbufferAllocationDispatch {
.gen_renderbuffers = gen_opengl_renderbuffers,
.bind_renderbuffer = bind_opengl_renderbuffer,
.renderbuffer_storage = set_opengl_renderbuffer_storage,
});
if (!renderbuffer.ok())
{
LOG("RTT::create depth renderbuffer allocation failed because: %s", renderbuffer.status().message);
status = 0;
return;
}
rboID = static_cast<GLuint>(renderbuffer.value());
}
GLint oldFboID;
glGetIntegerv(static_cast<GLenum>(pp::renderer::gl::draw_framebuffer_binding_query()), &oldFboID);
// Create a framebuffer object
glGenFramebuffers(1, &fboID);
glBindFramebuffer(framebuffer_target(), fboID);
const auto framebuffer = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
static_cast<std::uint32_t>(texID),
static_cast<std::uint32_t>(rboID),
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
.gen_framebuffers = gen_opengl_framebuffers,
.get_integer = query_opengl_integer,
.bind_framebuffer = bind_opengl_framebuffer,
.framebuffer_texture_2d = attach_opengl_framebuffer_texture_2d,
.framebuffer_renderbuffer = attach_opengl_framebuffer_renderbuffer,
.check_framebuffer_status = check_opengl_framebuffer_status,
});
if (!framebuffer.ok())
{
LOG("RTT::create framebuffer allocation failed because: %s", framebuffer.status().message);
status = 0;
return;
}
fboID = static_cast<GLuint>(framebuffer.value().framebuffer_id);
status = framebuffer.value().framebuffer_status;
//LOG("RTT CREATE %d - tex %d", fboID, texID);
// Attach the texture to FBO color attachment point
glFramebufferTexture2D(
framebuffer_target(),
static_cast<GLenum>(pp::renderer::gl::framebuffer_color_attachment()),
texture_2d_target(),
texID,
0);
if (depth_buffer)
{
// Attach the renderbuffer to depth attachment point
glFramebufferRenderbuffer(
framebuffer_target(),
static_cast<GLenum>(pp::renderer::gl::framebuffer_depth_attachment()),
renderbuffer_target(),
rboID);
}
// Check FBO status
status = glCheckFramebufferStatus(framebuffer_target());
if (status != static_cast<GLenum>(pp::renderer::gl::framebuffer_complete_status()))
if (status != pp::renderer::gl::framebuffer_complete_status())
LOG("RTT::create failed because: %s",
pp::renderer::gl::framebuffer_status_name(static_cast<std::uint32_t>(status)));
pp::renderer::gl::framebuffer_status_name(status));
// Switch back to window-system-provided framebuffer
glBindFramebuffer(framebuffer_target(), oldFboID);
oldRFboID = 0;
oldDFboID = 0;
});
return status == static_cast<GLenum>(pp::renderer::gl::framebuffer_complete_status());
return status == pp::renderer::gl::framebuffer_complete_status();
}
void RTT::bindFramebuffer()