Route GL state snapshot through renderer GL
This commit is contained in:
@@ -465,8 +465,9 @@ Known local toolchain state:
|
|||||||
color/buffer dispatch consumed by `App::clear`, tested app UI
|
color/buffer dispatch consumed by `App::clear`, tested app UI
|
||||||
viewport/scissor dispatch consumed by `App::draw` and `App::vr_draw_ui`,
|
viewport/scissor dispatch consumed by `App::draw` and `App::vr_draw_ui`,
|
||||||
tested generic capability/buffer-clear dispatch consumed by VR draw state
|
tested generic capability/buffer-clear dispatch consumed by VR draw state
|
||||||
setup, plus renderer API to OpenGL token mapping and command-planning
|
setup, tested saved-state snapshot/restore dispatch consumed by the retained
|
||||||
contracts used by the OpenGL parity work.
|
`gl_state` utility, 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
|
||||||
|
|||||||
@@ -535,6 +535,11 @@ VR draw blend/depth state transitions and depth-buffer clears now use generic
|
|||||||
tested `pp_renderer_gl` capability and clear dispatch contracts, reducing
|
tested `pp_renderer_gl` capability and clear dispatch contracts, reducing
|
||||||
direct OpenGL execution in the retained VR app path without changing state
|
direct OpenGL execution in the retained VR app path without changing state
|
||||||
restore behavior.
|
restore behavior.
|
||||||
|
The retained `gl_state` save/restore utility now snapshots and restores through
|
||||||
|
tested `pp_renderer_gl` saved-state dispatch contracts, covering capability
|
||||||
|
state, viewport, clear color, framebuffer/program bindings, active texture,
|
||||||
|
2D texture slots, samplers, and cube-map binding without changing the legacy
|
||||||
|
utility's public fields.
|
||||||
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.
|
||||||
|
|||||||
@@ -245,6 +245,73 @@ pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispa
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<OpenGlSavedState> snapshot_opengl_state(OpenGlStateSnapshotDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.is_enabled == nullptr
|
||||||
|
|| dispatch.get_integer == nullptr
|
||||||
|
|| dispatch.get_float == nullptr
|
||||||
|
|| dispatch.active_texture == nullptr) {
|
||||||
|
return pp::foundation::Result<OpenGlSavedState>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL state snapshot dispatch callbacks must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlSavedState state {};
|
||||||
|
state.blend_enabled = dispatch.is_enabled(blend_state());
|
||||||
|
state.depth_test_enabled = dispatch.is_enabled(depth_test_state());
|
||||||
|
state.scissor_test_enabled = dispatch.is_enabled(scissor_test_state());
|
||||||
|
dispatch.get_integer(viewport_query(), state.viewport.data());
|
||||||
|
dispatch.get_float(color_clear_value_query(), state.clear_color.data());
|
||||||
|
dispatch.get_integer(current_program_query(), &state.program);
|
||||||
|
dispatch.get_integer(draw_framebuffer_binding_query(), &state.draw_framebuffer);
|
||||||
|
dispatch.get_integer(read_framebuffer_binding_query(), &state.read_framebuffer);
|
||||||
|
dispatch.get_integer(active_texture_query(), &state.active_texture);
|
||||||
|
dispatch.get_integer(texture_binding_cube_map_query(), &state.cube_map_binding);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < state.texture_2d_bindings.size(); ++i) {
|
||||||
|
dispatch.active_texture(active_texture_unit(static_cast<std::uint32_t>(i)));
|
||||||
|
dispatch.get_integer(texture_binding_2d_query(), &state.texture_2d_bindings[i]);
|
||||||
|
dispatch.get_integer(sampler_binding_query(), &state.sampler_bindings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Result<OpenGlSavedState>::success(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status restore_opengl_state(
|
||||||
|
const OpenGlSavedState& state,
|
||||||
|
OpenGlStateRestoreDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.enable == nullptr
|
||||||
|
|| dispatch.disable == nullptr
|
||||||
|
|| dispatch.viewport == nullptr
|
||||||
|
|| dispatch.clear_color == nullptr
|
||||||
|
|| dispatch.bind_framebuffer == nullptr
|
||||||
|
|| dispatch.use_program == nullptr
|
||||||
|
|| dispatch.active_texture == nullptr
|
||||||
|
|| dispatch.bind_texture == nullptr
|
||||||
|
|| dispatch.bind_sampler == nullptr) {
|
||||||
|
return pp::foundation::Status::invalid_argument("OpenGL state restore dispatch callbacks must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
(state.blend_enabled != 0U ? dispatch.enable : dispatch.disable)(blend_state());
|
||||||
|
(state.depth_test_enabled != 0U ? dispatch.enable : dispatch.disable)(depth_test_state());
|
||||||
|
(state.scissor_test_enabled != 0U ? dispatch.enable : dispatch.disable)(scissor_test_state());
|
||||||
|
dispatch.viewport(state.viewport[0], state.viewport[1], state.viewport[2], state.viewport[3]);
|
||||||
|
dispatch.clear_color(state.clear_color[0], state.clear_color[1], state.clear_color[2], state.clear_color[3]);
|
||||||
|
dispatch.bind_framebuffer(draw_framebuffer_target(), static_cast<std::uint32_t>(state.draw_framebuffer));
|
||||||
|
dispatch.bind_framebuffer(read_framebuffer_target(), static_cast<std::uint32_t>(state.read_framebuffer));
|
||||||
|
dispatch.use_program(static_cast<std::uint32_t>(state.program));
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < state.texture_2d_bindings.size(); ++i) {
|
||||||
|
dispatch.active_texture(active_texture_unit(static_cast<std::uint32_t>(i)));
|
||||||
|
dispatch.bind_texture(texture_2d_target(), static_cast<std::uint32_t>(state.texture_2d_bindings[i]));
|
||||||
|
dispatch.bind_sampler(static_cast<std::uint32_t>(i), static_cast<std::uint32_t>(state.sampler_bindings[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.active_texture(static_cast<std::uint32_t>(state.active_texture));
|
||||||
|
dispatch.bind_texture(texture_cube_map_target(), static_cast<std::uint32_t>(state.cube_map_binding));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Result<OpenGlRuntimeInfo> query_opengl_runtime_info(
|
pp::foundation::Result<OpenGlRuntimeInfo> query_opengl_runtime_info(
|
||||||
OpenGlRuntimeInfoDispatch dispatch) noexcept
|
OpenGlRuntimeInfoDispatch dispatch) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -124,9 +124,36 @@ struct OpenGlInitialState {
|
|||||||
std::uint32_t alpha_equation = 0;
|
std::uint32_t alpha_equation = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlSavedState {
|
||||||
|
std::uint8_t blend_enabled = 0;
|
||||||
|
std::uint8_t depth_test_enabled = 0;
|
||||||
|
std::uint8_t scissor_test_enabled = 0;
|
||||||
|
std::array<std::int32_t, 4> viewport {};
|
||||||
|
std::array<float, 4> clear_color {};
|
||||||
|
std::array<std::int32_t, 10> texture_2d_bindings {};
|
||||||
|
std::array<std::int32_t, 10> sampler_bindings {};
|
||||||
|
std::int32_t cube_map_binding = 0;
|
||||||
|
std::int32_t program = 0;
|
||||||
|
std::int32_t draw_framebuffer = 0;
|
||||||
|
std::int32_t read_framebuffer = 0;
|
||||||
|
std::int32_t active_texture = 0;
|
||||||
|
};
|
||||||
|
|
||||||
using OpenGlCapabilityFn = void (*)(std::uint32_t state) noexcept;
|
using OpenGlCapabilityFn = void (*)(std::uint32_t state) noexcept;
|
||||||
|
using OpenGlIsEnabledFn = std::uint8_t (*)(std::uint32_t state) noexcept;
|
||||||
|
using OpenGlGetIntegerFn = void (*)(std::uint32_t name, std::int32_t* value) noexcept;
|
||||||
|
using OpenGlGetFloatFn = void (*)(std::uint32_t name, float* value) noexcept;
|
||||||
|
using OpenGlActiveTextureFn = void (*)(std::uint32_t texture_unit) noexcept;
|
||||||
|
using OpenGlClearColorFn = void (*)(float r, float g, float b, float a) noexcept;
|
||||||
|
using OpenGlClearFn = void (*)(std::uint32_t mask) noexcept;
|
||||||
|
using OpenGlViewportFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
|
||||||
|
using OpenGlScissorFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
|
||||||
using OpenGlBlendFuncFn = void (*)(std::uint32_t source_factor, std::uint32_t destination_factor) noexcept;
|
using OpenGlBlendFuncFn = void (*)(std::uint32_t source_factor, std::uint32_t destination_factor) noexcept;
|
||||||
using OpenGlBlendEquationSeparateFn = void (*)(std::uint32_t color_equation, std::uint32_t alpha_equation) noexcept;
|
using OpenGlBlendEquationSeparateFn = void (*)(std::uint32_t color_equation, std::uint32_t alpha_equation) noexcept;
|
||||||
|
using OpenGlUseProgramFn = void (*)(std::uint32_t program) noexcept;
|
||||||
|
using OpenGlBindFramebufferFn = void (*)(std::uint32_t target, std::uint32_t framebuffer) noexcept;
|
||||||
|
using OpenGlBindTextureFn = void (*)(std::uint32_t target, std::uint32_t texture) noexcept;
|
||||||
|
using OpenGlBindSamplerFn = void (*)(std::uint32_t unit, std::uint32_t sampler) noexcept;
|
||||||
|
|
||||||
struct OpenGlStateDispatch {
|
struct OpenGlStateDispatch {
|
||||||
OpenGlCapabilityFn enable = nullptr;
|
OpenGlCapabilityFn enable = nullptr;
|
||||||
@@ -135,6 +162,25 @@ struct OpenGlStateDispatch {
|
|||||||
OpenGlBlendEquationSeparateFn blend_equation_separate = nullptr;
|
OpenGlBlendEquationSeparateFn blend_equation_separate = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlStateSnapshotDispatch {
|
||||||
|
OpenGlIsEnabledFn is_enabled = nullptr;
|
||||||
|
OpenGlGetIntegerFn get_integer = nullptr;
|
||||||
|
OpenGlGetFloatFn get_float = nullptr;
|
||||||
|
OpenGlActiveTextureFn active_texture = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlStateRestoreDispatch {
|
||||||
|
OpenGlCapabilityFn enable = nullptr;
|
||||||
|
OpenGlCapabilityFn disable = nullptr;
|
||||||
|
OpenGlViewportFn viewport = nullptr;
|
||||||
|
OpenGlClearColorFn clear_color = nullptr;
|
||||||
|
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
|
||||||
|
OpenGlUseProgramFn use_program = nullptr;
|
||||||
|
OpenGlActiveTextureFn active_texture = nullptr;
|
||||||
|
OpenGlBindTextureFn bind_texture = nullptr;
|
||||||
|
OpenGlBindSamplerFn bind_sampler = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct OpenGlRuntimeInfo {
|
struct OpenGlRuntimeInfo {
|
||||||
const char* version = "";
|
const char* version = "";
|
||||||
const char* vendor = "";
|
const char* vendor = "";
|
||||||
@@ -153,11 +199,6 @@ struct OpenGlDefaultClear {
|
|||||||
std::uint32_t mask = 0;
|
std::uint32_t mask = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using OpenGlClearColorFn = void (*)(float r, float g, float b, float a) noexcept;
|
|
||||||
using OpenGlClearFn = void (*)(std::uint32_t mask) noexcept;
|
|
||||||
using OpenGlViewportFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
|
|
||||||
using OpenGlScissorFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
|
|
||||||
|
|
||||||
struct OpenGlClearDispatch {
|
struct OpenGlClearDispatch {
|
||||||
OpenGlClearColorFn clear_color = nullptr;
|
OpenGlClearColorFn clear_color = nullptr;
|
||||||
OpenGlClearFn clear = nullptr;
|
OpenGlClearFn clear = nullptr;
|
||||||
@@ -194,6 +235,11 @@ struct OpenGlBufferClearDispatch {
|
|||||||
OpenGlCapabilities capabilities) noexcept;
|
OpenGlCapabilities capabilities) noexcept;
|
||||||
[[nodiscard]] OpenGlInitialState panopainter_initial_state() noexcept;
|
[[nodiscard]] OpenGlInitialState panopainter_initial_state() noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispatch) noexcept;
|
[[nodiscard]] pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<OpenGlSavedState> snapshot_opengl_state(
|
||||||
|
OpenGlStateSnapshotDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Status restore_opengl_state(
|
||||||
|
const OpenGlSavedState& state,
|
||||||
|
OpenGlStateRestoreDispatch dispatch) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Result<OpenGlRuntimeInfo> query_opengl_runtime_info(
|
[[nodiscard]] pp::foundation::Result<OpenGlRuntimeInfo> query_opengl_runtime_info(
|
||||||
OpenGlRuntimeInfoDispatch dispatch) noexcept;
|
OpenGlRuntimeInfoDispatch dispatch) noexcept;
|
||||||
[[nodiscard]] OpenGlDefaultClear panopainter_default_clear() noexcept;
|
[[nodiscard]] OpenGlDefaultClear panopainter_default_clear() noexcept;
|
||||||
|
|||||||
156
src/util.cpp
156
src/util.cpp
@@ -5,6 +5,70 @@
|
|||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "renderer_gl/opengl_capabilities.h"
|
#include "renderer_gl/opengl_capabilities.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::uint8_t is_opengl_enabled(std::uint32_t state) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint8_t>(glIsEnabled(static_cast<GLenum>(state)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_opengl_integer(std::uint32_t name, std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
glGetIntegerv(static_cast<GLenum>(name), reinterpret_cast<GLint*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_opengl_float(std::uint32_t name, float* value) noexcept
|
||||||
|
{
|
||||||
|
glGetFloatv(static_cast<GLenum>(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_opengl_active_texture(std::uint32_t texture_unit) noexcept
|
||||||
|
{
|
||||||
|
glActiveTexture(static_cast<GLenum>(texture_unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_opengl_state(std::uint32_t state) noexcept
|
||||||
|
{
|
||||||
|
glEnable(static_cast<GLenum>(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable_opengl_state(std::uint32_t state) noexcept
|
||||||
|
{
|
||||||
|
glDisable(static_cast<GLenum>(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_opengl_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept
|
||||||
|
{
|
||||||
|
glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_opengl_clear_color(float r, float g, float b, float a) noexcept
|
||||||
|
{
|
||||||
|
glClearColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_opengl_framebuffer(std::uint32_t target, std::uint32_t framebuffer) noexcept
|
||||||
|
{
|
||||||
|
glBindFramebuffer(static_cast<GLenum>(target), static_cast<GLuint>(framebuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void use_opengl_program(std::uint32_t program) noexcept
|
||||||
|
{
|
||||||
|
glUseProgram(static_cast<GLuint>(program));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
|
||||||
|
{
|
||||||
|
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_opengl_sampler(std::uint32_t unit, std::uint32_t sampler) noexcept
|
||||||
|
{
|
||||||
|
glBindSampler(static_cast<GLuint>(unit), static_cast<GLuint>(sampler));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance)
|
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance)
|
||||||
{
|
{
|
||||||
@@ -727,41 +791,73 @@ void parallel_for(size_t nb_elements, std::function<void(size_t i)> functor, boo
|
|||||||
void gl_state::save()
|
void gl_state::save()
|
||||||
{
|
{
|
||||||
assert(App::I->is_render_thread());
|
assert(App::I->is_render_thread());
|
||||||
blend = glIsEnabled(pp::renderer::gl::blend_state());
|
|
||||||
depth_test = glIsEnabled(pp::renderer::gl::depth_test_state());
|
const auto snapshot = pp::renderer::gl::snapshot_opengl_state(
|
||||||
scissor_test = glIsEnabled(pp::renderer::gl::scissor_test_state());
|
pp::renderer::gl::OpenGlStateSnapshotDispatch {
|
||||||
glGetIntegerv(pp::renderer::gl::viewport_query(), vp);
|
.is_enabled = is_opengl_enabled,
|
||||||
glGetFloatv(pp::renderer::gl::color_clear_value_query(), cc);
|
.get_integer = query_opengl_integer,
|
||||||
glGetIntegerv(pp::renderer::gl::current_program_query(), &program);
|
.get_float = query_opengl_float,
|
||||||
glGetIntegerv(pp::renderer::gl::draw_framebuffer_binding_query(), &fbd);
|
.active_texture = set_opengl_active_texture,
|
||||||
glGetIntegerv(pp::renderer::gl::read_framebuffer_binding_query(), &fbr);
|
});
|
||||||
glGetIntegerv(pp::renderer::gl::active_texture_query(), &active_tex);
|
if (!snapshot.ok()) {
|
||||||
glGetIntegerv(pp::renderer::gl::texture_binding_cube_map_query(), &cube);
|
LOG("OpenGL state snapshot failed: %s", snapshot.status().message);
|
||||||
for (int i = 0; i < 10; ++i)
|
return;
|
||||||
{
|
|
||||||
glActiveTexture(pp::renderer::gl::active_texture_unit(static_cast<std::uint32_t>(i)));
|
|
||||||
glGetIntegerv(pp::renderer::gl::texture_binding_2d_query(), tex + i);
|
|
||||||
glGetIntegerv(pp::renderer::gl::sampler_binding_query(), sampler + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& state = snapshot.value();
|
||||||
|
blend = static_cast<GLboolean>(state.blend_enabled);
|
||||||
|
depth_test = static_cast<GLboolean>(state.depth_test_enabled);
|
||||||
|
scissor_test = static_cast<GLboolean>(state.scissor_test_enabled);
|
||||||
|
for (std::size_t i = 0; i < state.viewport.size(); ++i) {
|
||||||
|
vp[i] = static_cast<GLint>(state.viewport[i]);
|
||||||
|
cc[i] = state.clear_color[i];
|
||||||
|
}
|
||||||
|
for (std::size_t i = 0; i < state.texture_2d_bindings.size(); ++i) {
|
||||||
|
tex[i] = static_cast<GLint>(state.texture_2d_bindings[i]);
|
||||||
|
sampler[i] = static_cast<GLint>(state.sampler_bindings[i]);
|
||||||
|
}
|
||||||
|
cube = static_cast<GLint>(state.cube_map_binding);
|
||||||
|
program = static_cast<GLint>(state.program);
|
||||||
|
fbd = static_cast<GLint>(state.draw_framebuffer);
|
||||||
|
fbr = static_cast<GLint>(state.read_framebuffer);
|
||||||
|
active_tex = static_cast<GLint>(state.active_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_state::restore()
|
void gl_state::restore()
|
||||||
{
|
{
|
||||||
assert(App::I->is_render_thread());
|
assert(App::I->is_render_thread());
|
||||||
blend ? glEnable(pp::renderer::gl::blend_state()) : glDisable(pp::renderer::gl::blend_state());
|
|
||||||
depth_test ? glEnable(pp::renderer::gl::depth_test_state()) : glDisable(pp::renderer::gl::depth_test_state());
|
pp::renderer::gl::OpenGlSavedState state {};
|
||||||
scissor_test ? glEnable(pp::renderer::gl::scissor_test_state()) : glDisable(pp::renderer::gl::scissor_test_state());
|
state.blend_enabled = blend;
|
||||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
state.depth_test_enabled = depth_test;
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
state.scissor_test_enabled = scissor_test;
|
||||||
glBindFramebuffer(pp::renderer::gl::draw_framebuffer_target(), fbd);
|
for (std::size_t i = 0; i < state.viewport.size(); ++i) {
|
||||||
glBindFramebuffer(pp::renderer::gl::read_framebuffer_target(), fbr);
|
state.viewport[i] = static_cast<std::int32_t>(vp[i]);
|
||||||
glUseProgram(program);
|
state.clear_color[i] = cc[i];
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
{
|
|
||||||
glActiveTexture(pp::renderer::gl::active_texture_unit(static_cast<std::uint32_t>(i)));
|
|
||||||
glBindTexture(pp::renderer::gl::texture_2d_target(), tex[i]);
|
|
||||||
glBindSampler(i, sampler[i]);
|
|
||||||
}
|
}
|
||||||
glActiveTexture(active_tex);
|
for (std::size_t i = 0; i < state.texture_2d_bindings.size(); ++i) {
|
||||||
glBindTexture(pp::renderer::gl::texture_cube_map_target(), cube);
|
state.texture_2d_bindings[i] = static_cast<std::int32_t>(tex[i]);
|
||||||
|
state.sampler_bindings[i] = static_cast<std::int32_t>(sampler[i]);
|
||||||
|
}
|
||||||
|
state.cube_map_binding = static_cast<std::int32_t>(cube);
|
||||||
|
state.program = static_cast<std::int32_t>(program);
|
||||||
|
state.draw_framebuffer = static_cast<std::int32_t>(fbd);
|
||||||
|
state.read_framebuffer = static_cast<std::int32_t>(fbr);
|
||||||
|
state.active_texture = static_cast<std::int32_t>(active_tex);
|
||||||
|
|
||||||
|
const auto status = pp::renderer::gl::restore_opengl_state(
|
||||||
|
state,
|
||||||
|
pp::renderer::gl::OpenGlStateRestoreDispatch {
|
||||||
|
.enable = enable_opengl_state,
|
||||||
|
.disable = disable_opengl_state,
|
||||||
|
.viewport = set_opengl_viewport,
|
||||||
|
.clear_color = set_opengl_clear_color,
|
||||||
|
.bind_framebuffer = bind_opengl_framebuffer,
|
||||||
|
.use_program = use_opengl_program,
|
||||||
|
.active_texture = set_opengl_active_texture,
|
||||||
|
.bind_texture = bind_opengl_texture,
|
||||||
|
.bind_sampler = bind_opengl_sampler,
|
||||||
|
});
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("OpenGL state restore failed: %s", status.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,29 @@ struct RecordedOpenGlStateCall {
|
|||||||
std::uint32_t second = 0;
|
std::uint32_t second = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RecordedOpenGlBindingCall {
|
||||||
|
enum class Kind {
|
||||||
|
bind_framebuffer,
|
||||||
|
use_program,
|
||||||
|
active_texture,
|
||||||
|
bind_texture,
|
||||||
|
bind_sampler,
|
||||||
|
};
|
||||||
|
|
||||||
|
Kind kind = Kind::bind_framebuffer;
|
||||||
|
std::uint32_t first = 0;
|
||||||
|
std::uint32_t second = 0;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<RecordedOpenGlStateCall> recorded_state_calls;
|
std::vector<RecordedOpenGlStateCall> recorded_state_calls;
|
||||||
std::vector<std::uint32_t> recorded_string_queries;
|
std::vector<std::uint32_t> recorded_string_queries;
|
||||||
std::vector<pp::renderer::gl::OpenGlDefaultClear> recorded_clear_calls;
|
std::vector<pp::renderer::gl::OpenGlDefaultClear> recorded_clear_calls;
|
||||||
std::vector<pp::renderer::gl::OpenGlViewportRect> recorded_viewport_calls;
|
std::vector<pp::renderer::gl::OpenGlViewportRect> recorded_viewport_calls;
|
||||||
std::vector<pp::renderer::gl::OpenGlScissorRect> recorded_scissor_calls;
|
std::vector<pp::renderer::gl::OpenGlScissorRect> recorded_scissor_calls;
|
||||||
|
std::vector<std::uint32_t> recorded_integer_queries;
|
||||||
|
std::vector<std::uint32_t> recorded_float_queries;
|
||||||
|
std::vector<std::uint32_t> recorded_active_texture_calls;
|
||||||
|
std::vector<RecordedOpenGlBindingCall> recorded_binding_calls;
|
||||||
|
|
||||||
void record_enable(std::uint32_t state) noexcept
|
void record_enable(std::uint32_t state) noexcept
|
||||||
{
|
{
|
||||||
@@ -116,6 +134,108 @@ void record_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint8_t record_is_enabled(std::uint32_t state) noexcept
|
||||||
|
{
|
||||||
|
if (state == 0x0BE2U) {
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
if (state == 0x0B71U) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
if (state == 0x0C11U) {
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_integer(std::uint32_t name, std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
recorded_integer_queries.push_back(name);
|
||||||
|
switch (name) {
|
||||||
|
case 0x0BA2U:
|
||||||
|
value[0] = 2;
|
||||||
|
value[1] = 4;
|
||||||
|
value[2] = 640;
|
||||||
|
value[3] = 320;
|
||||||
|
break;
|
||||||
|
case 0x8B8DU:
|
||||||
|
*value = 42;
|
||||||
|
break;
|
||||||
|
case 0x8CA6U:
|
||||||
|
*value = 7;
|
||||||
|
break;
|
||||||
|
case 0x8CAAU:
|
||||||
|
*value = 9;
|
||||||
|
break;
|
||||||
|
case 0x84E0U:
|
||||||
|
*value = 0x84C4;
|
||||||
|
break;
|
||||||
|
case 0x8514U:
|
||||||
|
*value = 88;
|
||||||
|
break;
|
||||||
|
case 0x8069U:
|
||||||
|
*value = 100 + static_cast<std::int32_t>(recorded_active_texture_calls.size());
|
||||||
|
break;
|
||||||
|
case 0x8919U:
|
||||||
|
*value = 200 + static_cast<std::int32_t>(recorded_active_texture_calls.size());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*value = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_float(std::uint32_t name, float* value) noexcept
|
||||||
|
{
|
||||||
|
recorded_float_queries.push_back(name);
|
||||||
|
if (name == 0x0C22U) {
|
||||||
|
value[0] = 0.25F;
|
||||||
|
value[1] = 0.5F;
|
||||||
|
value[2] = 0.75F;
|
||||||
|
value[3] = 1.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_active_texture(std::uint32_t texture_unit) noexcept
|
||||||
|
{
|
||||||
|
recorded_active_texture_calls.push_back(texture_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_bind_framebuffer(std::uint32_t target, std::uint32_t framebuffer) noexcept
|
||||||
|
{
|
||||||
|
recorded_binding_calls.push_back(RecordedOpenGlBindingCall {
|
||||||
|
.kind = RecordedOpenGlBindingCall::Kind::bind_framebuffer,
|
||||||
|
.first = target,
|
||||||
|
.second = framebuffer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_use_program(std::uint32_t program) noexcept
|
||||||
|
{
|
||||||
|
recorded_binding_calls.push_back(RecordedOpenGlBindingCall {
|
||||||
|
.kind = RecordedOpenGlBindingCall::Kind::use_program,
|
||||||
|
.first = program,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_bind_texture(std::uint32_t target, std::uint32_t texture) noexcept
|
||||||
|
{
|
||||||
|
recorded_binding_calls.push_back(RecordedOpenGlBindingCall {
|
||||||
|
.kind = RecordedOpenGlBindingCall::Kind::bind_texture,
|
||||||
|
.first = target,
|
||||||
|
.second = texture,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_bind_sampler(std::uint32_t unit, std::uint32_t sampler) noexcept
|
||||||
|
{
|
||||||
|
recorded_binding_calls.push_back(RecordedOpenGlBindingCall {
|
||||||
|
.kind = RecordedOpenGlBindingCall::Kind::bind_sampler,
|
||||||
|
.first = unit,
|
||||||
|
.second = sampler,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void detects_common_extension_capabilities(pp::tests::Harness& h)
|
void detects_common_extension_capabilities(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
constexpr std::array<std::string_view, 2> extensions {
|
constexpr std::array<std::string_view, 2> extensions {
|
||||||
@@ -794,6 +914,146 @@ void rejects_incomplete_app_initialization_state_dispatch(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, status.code == pp::foundation::StatusCode::invalid_argument);
|
PP_EXPECT(h, status.code == pp::foundation::StatusCode::invalid_argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void snapshots_legacy_gl_state(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_integer_queries.clear();
|
||||||
|
recorded_float_queries.clear();
|
||||||
|
recorded_active_texture_calls.clear();
|
||||||
|
|
||||||
|
const auto result = pp::renderer::gl::snapshot_opengl_state(
|
||||||
|
pp::renderer::gl::OpenGlStateSnapshotDispatch {
|
||||||
|
.is_enabled = record_is_enabled,
|
||||||
|
.get_integer = record_get_integer,
|
||||||
|
.get_float = record_get_float,
|
||||||
|
.active_texture = record_active_texture,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, result.ok());
|
||||||
|
const auto& state = result.value();
|
||||||
|
PP_EXPECT(h, state.blend_enabled == 1U);
|
||||||
|
PP_EXPECT(h, state.depth_test_enabled == 0U);
|
||||||
|
PP_EXPECT(h, state.scissor_test_enabled == 1U);
|
||||||
|
PP_EXPECT(h, state.viewport[0] == 2);
|
||||||
|
PP_EXPECT(h, state.viewport[1] == 4);
|
||||||
|
PP_EXPECT(h, state.viewport[2] == 640);
|
||||||
|
PP_EXPECT(h, state.viewport[3] == 320);
|
||||||
|
PP_EXPECT(h, state.clear_color[0] == 0.25F);
|
||||||
|
PP_EXPECT(h, state.clear_color[1] == 0.5F);
|
||||||
|
PP_EXPECT(h, state.clear_color[2] == 0.75F);
|
||||||
|
PP_EXPECT(h, state.clear_color[3] == 1.0F);
|
||||||
|
PP_EXPECT(h, state.program == 42);
|
||||||
|
PP_EXPECT(h, state.draw_framebuffer == 7);
|
||||||
|
PP_EXPECT(h, state.read_framebuffer == 9);
|
||||||
|
PP_EXPECT(h, state.active_texture == 0x84C4);
|
||||||
|
PP_EXPECT(h, state.cube_map_binding == 88);
|
||||||
|
PP_EXPECT(h, state.texture_2d_bindings[0] == 101);
|
||||||
|
PP_EXPECT(h, state.texture_2d_bindings[9] == 110);
|
||||||
|
PP_EXPECT(h, state.sampler_bindings[0] == 201);
|
||||||
|
PP_EXPECT(h, state.sampler_bindings[9] == 210);
|
||||||
|
PP_EXPECT(h, recorded_float_queries.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls.size() == 10U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls[0] == 0x84C0U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls[9] == 0x84C9U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_incomplete_gl_state_snapshot_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto result = pp::renderer::gl::snapshot_opengl_state(
|
||||||
|
pp::renderer::gl::OpenGlStateSnapshotDispatch {
|
||||||
|
.is_enabled = record_is_enabled,
|
||||||
|
.get_integer = record_get_integer,
|
||||||
|
.get_float = record_get_float,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !result.ok());
|
||||||
|
PP_EXPECT(h, result.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void restores_legacy_gl_state(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_state_calls.clear();
|
||||||
|
recorded_viewport_calls.clear();
|
||||||
|
recorded_clear_calls.clear();
|
||||||
|
recorded_active_texture_calls.clear();
|
||||||
|
recorded_binding_calls.clear();
|
||||||
|
|
||||||
|
pp::renderer::gl::OpenGlSavedState state {};
|
||||||
|
state.blend_enabled = 1U;
|
||||||
|
state.depth_test_enabled = 0U;
|
||||||
|
state.scissor_test_enabled = 1U;
|
||||||
|
state.viewport = { 3, 6, 800, 600 };
|
||||||
|
state.clear_color = { 0.1F, 0.2F, 0.3F, 0.4F };
|
||||||
|
state.program = 12;
|
||||||
|
state.draw_framebuffer = 21;
|
||||||
|
state.read_framebuffer = 22;
|
||||||
|
state.active_texture = 0x84C7;
|
||||||
|
state.cube_map_binding = 77;
|
||||||
|
for (std::size_t i = 0; i < state.texture_2d_bindings.size(); ++i) {
|
||||||
|
state.texture_2d_bindings[i] = 300 + static_cast<std::int32_t>(i);
|
||||||
|
state.sampler_bindings[i] = 400 + static_cast<std::int32_t>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto status = pp::renderer::gl::restore_opengl_state(
|
||||||
|
state,
|
||||||
|
pp::renderer::gl::OpenGlStateRestoreDispatch {
|
||||||
|
.enable = record_enable,
|
||||||
|
.disable = record_disable,
|
||||||
|
.viewport = record_viewport,
|
||||||
|
.clear_color = record_clear_color,
|
||||||
|
.bind_framebuffer = record_bind_framebuffer,
|
||||||
|
.use_program = record_use_program,
|
||||||
|
.active_texture = record_active_texture,
|
||||||
|
.bind_texture = record_bind_texture,
|
||||||
|
.bind_sampler = record_bind_sampler,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, status.ok());
|
||||||
|
PP_EXPECT(h, recorded_state_calls.size() == 3U);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[0].kind == RecordedOpenGlStateCall::Kind::enable);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[0].first == 0x0BE2U);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[1].kind == RecordedOpenGlStateCall::Kind::disable);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[1].first == 0x0B71U);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[2].kind == RecordedOpenGlStateCall::Kind::enable);
|
||||||
|
PP_EXPECT(h, recorded_state_calls[2].first == 0x0C11U);
|
||||||
|
PP_EXPECT(h, recorded_viewport_calls.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_viewport_calls[0].width == 800);
|
||||||
|
PP_EXPECT(h, recorded_clear_calls.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_clear_calls[0].color[2] == 0.3F);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls.size() == 24U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].kind == RecordedOpenGlBindingCall::Kind::bind_framebuffer);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8CA9U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[0].second == 21U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].kind == RecordedOpenGlBindingCall::Kind::bind_framebuffer);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8CA8U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[1].second == 22U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[2].kind == RecordedOpenGlBindingCall::Kind::use_program);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[2].first == 12U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls.size() == 11U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls[0] == 0x84C0U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls[9] == 0x84C9U);
|
||||||
|
PP_EXPECT(h, recorded_active_texture_calls[10] == 0x84C7U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[3].kind == RecordedOpenGlBindingCall::Kind::bind_texture);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[3].first == 0x0DE1U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[3].second == 300U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[23].kind == RecordedOpenGlBindingCall::Kind::bind_texture);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[23].first == 0x8513U);
|
||||||
|
PP_EXPECT(h, recorded_binding_calls[23].second == 77U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_incomplete_gl_state_restore_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto status = pp::renderer::gl::restore_opengl_state(
|
||||||
|
pp::renderer::gl::OpenGlSavedState {},
|
||||||
|
pp::renderer::gl::OpenGlStateRestoreDispatch {
|
||||||
|
.enable = record_enable,
|
||||||
|
.disable = record_disable,
|
||||||
|
.viewport = record_viewport,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !status.ok());
|
||||||
|
PP_EXPECT(h, status.code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
void queries_app_runtime_info(pp::tests::Harness& h)
|
void queries_app_runtime_info(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
recorded_string_queries.clear();
|
recorded_string_queries.clear();
|
||||||
@@ -1433,6 +1693,10 @@ int main()
|
|||||||
harness.run("maps_app_initialization_parameters", maps_app_initialization_parameters);
|
harness.run("maps_app_initialization_parameters", maps_app_initialization_parameters);
|
||||||
harness.run("applies_app_initialization_state", applies_app_initialization_state);
|
harness.run("applies_app_initialization_state", applies_app_initialization_state);
|
||||||
harness.run("rejects_incomplete_app_initialization_state_dispatch", rejects_incomplete_app_initialization_state_dispatch);
|
harness.run("rejects_incomplete_app_initialization_state_dispatch", rejects_incomplete_app_initialization_state_dispatch);
|
||||||
|
harness.run("snapshots_legacy_gl_state", snapshots_legacy_gl_state);
|
||||||
|
harness.run("rejects_incomplete_gl_state_snapshot_dispatch", rejects_incomplete_gl_state_snapshot_dispatch);
|
||||||
|
harness.run("restores_legacy_gl_state", restores_legacy_gl_state);
|
||||||
|
harness.run("rejects_incomplete_gl_state_restore_dispatch", rejects_incomplete_gl_state_restore_dispatch);
|
||||||
harness.run("queries_app_runtime_info", queries_app_runtime_info);
|
harness.run("queries_app_runtime_info", queries_app_runtime_info);
|
||||||
harness.run("rejects_incomplete_app_runtime_info_dispatch", rejects_incomplete_app_runtime_info_dispatch);
|
harness.run("rejects_incomplete_app_runtime_info_dispatch", rejects_incomplete_app_runtime_info_dispatch);
|
||||||
harness.run("clears_app_default_target", clears_app_default_target);
|
harness.run("clears_app_default_target", clears_app_default_target);
|
||||||
|
|||||||
Reference in New Issue
Block a user