Route RTT framebuffer binding through renderer GL
This commit is contained in:
@@ -468,9 +468,10 @@ Known local toolchain state:
|
|||||||
setup, tested saved-state snapshot/restore dispatch consumed by the retained
|
setup, tested saved-state snapshot/restore dispatch consumed by the retained
|
||||||
`gl_state` utility, tested texture lifecycle/readback dispatch consumed by
|
`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, plus renderer API to
|
consumed by retained `RTT` resize/copy/readback paths, tested framebuffer
|
||||||
OpenGL token mapping and command-planning contracts used by the OpenGL parity
|
bind/restore dispatch consumed by retained `RTT` render-target pass entry
|
||||||
work.
|
and exit paths, plus renderer API to OpenGL token mapping and command-planning
|
||||||
|
contracts used by the OpenGL parity work.
|
||||||
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability,
|
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability,
|
||||||
new-document warning, publish prompt, and save-before-upload planning as JSON;
|
new-document warning, publish prompt, and save-before-upload planning as JSON;
|
||||||
the live cloud upload command consumes the same start contract before
|
the live cloud upload command consumes the same start contract before
|
||||||
|
|||||||
@@ -547,6 +547,9 @@ 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::bindFramebuffer` and `RTT::unbindFramebuffer` now use tested
|
||||||
|
`pp_renderer_gl` draw/read framebuffer binding snapshot and restore contracts,
|
||||||
|
moving render-target pass entry/exit state management behind the backend.
|
||||||
Windows RenderDoc frame capture hooks now also dispatch through
|
Windows RenderDoc frame capture hooks now also dispatch through
|
||||||
`PlatformServices`, keeping capture integration in the platform service while
|
`PlatformServices`, keeping capture integration in the platform service while
|
||||||
leaving non-Windows adapters as no-ops.
|
leaving non-Windows adapters as no-ops.
|
||||||
|
|||||||
@@ -684,6 +684,36 @@ pp::foundation::Status readback_opengl_framebuffer(
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<OpenGlFramebufferBindingState> bind_opengl_framebuffer_for_draw_read(
|
||||||
|
std::uint32_t framebuffer,
|
||||||
|
OpenGlFramebufferBindDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.get_integer == nullptr || dispatch.bind_framebuffer == nullptr) {
|
||||||
|
return pp::foundation::Result<OpenGlFramebufferBindingState>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL framebuffer bind dispatch callbacks must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlFramebufferBindingState binding {};
|
||||||
|
dispatch.get_integer(draw_framebuffer_binding_query(), &binding.draw_framebuffer);
|
||||||
|
dispatch.get_integer(read_framebuffer_binding_query(), &binding.read_framebuffer);
|
||||||
|
dispatch.bind_framebuffer(draw_framebuffer_target(), framebuffer);
|
||||||
|
dispatch.bind_framebuffer(read_framebuffer_target(), framebuffer);
|
||||||
|
return pp::foundation::Result<OpenGlFramebufferBindingState>::success(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status restore_opengl_framebuffer_binding(
|
||||||
|
OpenGlFramebufferBindingState binding,
|
||||||
|
OpenGlFramebufferRestoreDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.bind_framebuffer == nullptr) {
|
||||||
|
return pp::foundation::Status::invalid_argument("OpenGL framebuffer restore dispatch callback must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.bind_framebuffer(draw_framebuffer_target(), static_cast<std::uint32_t>(binding.draw_framebuffer));
|
||||||
|
dispatch.bind_framebuffer(read_framebuffer_target(), static_cast<std::uint32_t>(binding.read_framebuffer));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
std::uint32_t extension_count_query() noexcept
|
std::uint32_t extension_count_query() noexcept
|
||||||
{
|
{
|
||||||
return gl_num_extensions;
|
return gl_num_extensions;
|
||||||
|
|||||||
@@ -167,6 +167,11 @@ struct OpenGlFramebufferReadback {
|
|||||||
void* pixels = nullptr;
|
void* pixels = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlFramebufferBindingState {
|
||||||
|
std::int32_t draw_framebuffer = 0;
|
||||||
|
std::int32_t read_framebuffer = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct OpenGlWindowsWglContextConfig {
|
struct OpenGlWindowsWglContextConfig {
|
||||||
std::array<std::int32_t, 9> context_attributes {};
|
std::array<std::int32_t, 9> context_attributes {};
|
||||||
std::array<std::int32_t, 15> pixel_format_attributes {};
|
std::array<std::int32_t, 15> pixel_format_attributes {};
|
||||||
@@ -381,6 +386,15 @@ struct OpenGlFramebufferReadbackDispatch {
|
|||||||
OpenGlReadPixelsFn read_pixels = nullptr;
|
OpenGlReadPixelsFn read_pixels = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlFramebufferBindDispatch {
|
||||||
|
OpenGlGetIntegerFn get_integer = nullptr;
|
||||||
|
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlFramebufferRestoreDispatch {
|
||||||
|
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
[[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;
|
||||||
@@ -437,6 +451,12 @@ struct OpenGlFramebufferReadbackDispatch {
|
|||||||
[[nodiscard]] pp::foundation::Status readback_opengl_framebuffer(
|
[[nodiscard]] pp::foundation::Status readback_opengl_framebuffer(
|
||||||
OpenGlFramebufferReadback readback,
|
OpenGlFramebufferReadback readback,
|
||||||
OpenGlFramebufferReadbackDispatch dispatch) noexcept;
|
OpenGlFramebufferReadbackDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<OpenGlFramebufferBindingState> bind_opengl_framebuffer_for_draw_read(
|
||||||
|
std::uint32_t framebuffer,
|
||||||
|
OpenGlFramebufferBindDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Status restore_opengl_framebuffer_binding(
|
||||||
|
OpenGlFramebufferBindingState binding,
|
||||||
|
OpenGlFramebufferRestoreDispatch dispatch) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] std::uint32_t extension_count_query() noexcept;
|
[[nodiscard]] std::uint32_t extension_count_query() noexcept;
|
||||||
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
|
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
|
||||||
|
|||||||
52
src/rtt.cpp
52
src/rtt.cpp
@@ -24,26 +24,6 @@ namespace {
|
|||||||
return static_cast<GLenum>(pp::renderer::gl::framebuffer_target());
|
return static_cast<GLenum>(pp::renderer::gl::framebuffer_target());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] GLenum draw_framebuffer_target() noexcept
|
|
||||||
{
|
|
||||||
return static_cast<GLenum>(pp::renderer::gl::draw_framebuffer_target());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] GLenum read_framebuffer_target() noexcept
|
|
||||||
{
|
|
||||||
return static_cast<GLenum>(pp::renderer::gl::read_framebuffer_target());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] GLenum draw_framebuffer_binding_query() noexcept
|
|
||||||
{
|
|
||||||
return static_cast<GLenum>(pp::renderer::gl::draw_framebuffer_binding_query());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] GLenum read_framebuffer_binding_query() noexcept
|
|
||||||
{
|
|
||||||
return static_cast<GLenum>(pp::renderer::gl::read_framebuffer_binding_query());
|
|
||||||
}
|
|
||||||
|
|
||||||
void query_opengl_integer(std::uint32_t name, std::int32_t* value) noexcept
|
void query_opengl_integer(std::uint32_t name, std::int32_t* value) noexcept
|
||||||
{
|
{
|
||||||
glGetIntegerv(static_cast<GLenum>(name), reinterpret_cast<GLint*>(value));
|
glGetIntegerv(static_cast<GLenum>(name), reinterpret_cast<GLint*>(value));
|
||||||
@@ -437,10 +417,19 @@ void RTT::bindFramebuffer()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
glGetIntegerv(draw_framebuffer_binding_query(), &oldDFboID);
|
const auto binding = pp::renderer::gl::bind_opengl_framebuffer_for_draw_read(
|
||||||
glGetIntegerv(read_framebuffer_binding_query(), &oldRFboID);
|
static_cast<std::uint32_t>(fboID),
|
||||||
glBindFramebuffer(draw_framebuffer_target(), fboID);
|
pp::renderer::gl::OpenGlFramebufferBindDispatch {
|
||||||
glBindFramebuffer(read_framebuffer_target(), fboID);
|
.get_integer = query_opengl_integer,
|
||||||
|
.bind_framebuffer = bind_opengl_framebuffer,
|
||||||
|
});
|
||||||
|
if (!binding.ok()) {
|
||||||
|
LOG("RTT::bindFramebuffer() failed because: %s", binding.status().message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldDFboID = static_cast<GLint>(binding.value().draw_framebuffer);
|
||||||
|
oldRFboID = static_cast<GLint>(binding.value().read_framebuffer);
|
||||||
bound = true;
|
bound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,8 +438,19 @@ void RTT::unbindFramebuffer()
|
|||||||
assert(App::I->is_render_thread());
|
assert(App::I->is_render_thread());
|
||||||
if (!bound)
|
if (!bound)
|
||||||
return;
|
return;
|
||||||
glBindFramebuffer(draw_framebuffer_target(), oldDFboID);
|
const auto status = pp::renderer::gl::restore_opengl_framebuffer_binding(
|
||||||
glBindFramebuffer(read_framebuffer_target(), oldRFboID);
|
pp::renderer::gl::OpenGlFramebufferBindingState {
|
||||||
|
.draw_framebuffer = oldDFboID,
|
||||||
|
.read_framebuffer = oldRFboID,
|
||||||
|
},
|
||||||
|
pp::renderer::gl::OpenGlFramebufferRestoreDispatch {
|
||||||
|
.bind_framebuffer = bind_opengl_framebuffer,
|
||||||
|
});
|
||||||
|
if (!status.ok()) {
|
||||||
|
LOG("RTT::unbindFramebuffer() failed because: %s", status.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
oldRFboID = 0;
|
oldRFboID = 0;
|
||||||
oldDFboID = 0;
|
oldDFboID = 0;
|
||||||
bound = false;
|
bound = false;
|
||||||
|
|||||||
@@ -1939,6 +1939,69 @@ void rejects_invalid_framebuffer_readbacks(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, missing_pixels.code == pp::foundation::StatusCode::invalid_argument);
|
PP_EXPECT(h, missing_pixels.code == pp::foundation::StatusCode::invalid_argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void binds_framebuffer_draw_read_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_integer_queries.clear();
|
||||||
|
recorded_binding_calls.clear();
|
||||||
|
|
||||||
|
const auto binding = pp::renderer::gl::bind_opengl_framebuffer_for_draw_read(
|
||||||
|
29U,
|
||||||
|
pp::renderer::gl::OpenGlFramebufferBindDispatch {
|
||||||
|
.get_integer = record_get_integer,
|
||||||
|
.bind_framebuffer = record_bind_framebuffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, binding.ok());
|
||||||
|
PP_EXPECT(h, binding.value().draw_framebuffer == 7);
|
||||||
|
PP_EXPECT(h, binding.value().read_framebuffer == 9);
|
||||||
|
PP_EXPECT(h, recorded_integer_queries.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_integer_queries[0] == 0x8CA6U);
|
||||||
|
PP_EXPECT(h, recorded_integer_queries[1] == 0x8CAAU);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8CA9U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].second == 29U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8CA8U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].second == 29U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void restores_framebuffer_draw_read_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_binding_calls.clear();
|
||||||
|
|
||||||
|
const auto status = pp::renderer::gl::restore_opengl_framebuffer_binding(
|
||||||
|
pp::renderer::gl::OpenGlFramebufferBindingState {
|
||||||
|
.draw_framebuffer = 31,
|
||||||
|
.read_framebuffer = 37,
|
||||||
|
},
|
||||||
|
pp::renderer::gl::OpenGlFramebufferRestoreDispatch {
|
||||||
|
.bind_framebuffer = record_bind_framebuffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, status.ok());
|
||||||
|
PP_EXPECT(h, recorded_binding_calls.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8CA9U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].second == 31U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8CA8U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].second == 37U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_incomplete_framebuffer_binding_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto binding = pp::renderer::gl::bind_opengl_framebuffer_for_draw_read(
|
||||||
|
29U,
|
||||||
|
pp::renderer::gl::OpenGlFramebufferBindDispatch {
|
||||||
|
.get_integer = record_get_integer,
|
||||||
|
});
|
||||||
|
const auto restore = pp::renderer::gl::restore_opengl_framebuffer_binding(
|
||||||
|
pp::renderer::gl::OpenGlFramebufferBindingState {},
|
||||||
|
pp::renderer::gl::OpenGlFramebufferRestoreDispatch {});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !binding.ok());
|
||||||
|
PP_EXPECT(h, binding.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !restore.ok());
|
||||||
|
PP_EXPECT(h, restore.code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
void maps_renderer_viewports_and_scissors(pp::tests::Harness& h)
|
void maps_renderer_viewports_and_scissors(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
const auto viewport = pp::renderer::gl::viewport_for_renderer_viewport(
|
const auto viewport = pp::renderer::gl::viewport_for_renderer_viewport(
|
||||||
@@ -2345,6 +2408,9 @@ int main()
|
|||||||
harness.run("rejects_invalid_framebuffer_blits", rejects_invalid_framebuffer_blits);
|
harness.run("rejects_invalid_framebuffer_blits", rejects_invalid_framebuffer_blits);
|
||||||
harness.run("reads_back_framebuffer_through_dispatch", reads_back_framebuffer_through_dispatch);
|
harness.run("reads_back_framebuffer_through_dispatch", reads_back_framebuffer_through_dispatch);
|
||||||
harness.run("rejects_invalid_framebuffer_readbacks", rejects_invalid_framebuffer_readbacks);
|
harness.run("rejects_invalid_framebuffer_readbacks", rejects_invalid_framebuffer_readbacks);
|
||||||
|
harness.run("binds_framebuffer_draw_read_through_dispatch", binds_framebuffer_draw_read_through_dispatch);
|
||||||
|
harness.run("restores_framebuffer_draw_read_through_dispatch", restores_framebuffer_draw_read_through_dispatch);
|
||||||
|
harness.run("rejects_incomplete_framebuffer_binding_dispatch", rejects_incomplete_framebuffer_binding_dispatch);
|
||||||
harness.run("maps_renderer_viewports_and_scissors", maps_renderer_viewports_and_scissors);
|
harness.run("maps_renderer_viewports_and_scissors", maps_renderer_viewports_and_scissors);
|
||||||
harness.run("maps_renderer_blend_state_tokens", maps_renderer_blend_state_tokens);
|
harness.run("maps_renderer_blend_state_tokens", maps_renderer_blend_state_tokens);
|
||||||
harness.run("maps_renderer_color_write_masks", maps_renderer_color_write_masks);
|
harness.run("maps_renderer_color_write_masks", maps_renderer_color_write_masks);
|
||||||
|
|||||||
Reference in New Issue
Block a user