Route VR and startup GL state through backend
This commit is contained in:
@@ -371,8 +371,8 @@ Known local toolchain state:
|
|||||||
filters/wraps, and render-target formats resolve through backend-owned
|
filters/wraps, and render-target formats resolve through backend-owned
|
||||||
overloads.
|
overloads.
|
||||||
The Windows entrypoint also consumes backend-owned generic OpenGL
|
The Windows entrypoint also consumes backend-owned generic OpenGL
|
||||||
error-code/info-string tokens and WGL core-context/pixel-format attribute
|
error-code/info-string tokens, runtime string query ordering, and WGL
|
||||||
catalogs.
|
core-context/pixel-format attribute catalogs.
|
||||||
The headless OpenGL command planner consumes `pp_renderer_api` recorded
|
The headless OpenGL command planner consumes `pp_renderer_api` recorded
|
||||||
commands and maps render-pass clear masks/values, viewport/scissor state,
|
commands and maps render-pass clear masks/values, viewport/scissor state,
|
||||||
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
||||||
@@ -391,9 +391,10 @@ Known local toolchain state:
|
|||||||
counts so automation can assert backend interpretation without an OpenGL
|
counts so automation can assert backend interpretation without an OpenGL
|
||||||
context.
|
context.
|
||||||
Desktop VR drawing also consumes backend-owned scissor/depth/blend state,
|
Desktop VR drawing also consumes backend-owned scissor/depth/blend state,
|
||||||
depth clear masks, active texture units, and fallback 2D texture unbind
|
blend/depth state query-restore, depth clear masks, active texture units,
|
||||||
targets; VR SDK start/stop now dispatches through `PlatformServices` while
|
and fallback 2D texture unbind targets; VR SDK start/stop now dispatches
|
||||||
retaining the existing Windows OpenVR bridge shape.
|
through `PlatformServices` while retaining the existing Windows OpenVR bridge
|
||||||
|
shape.
|
||||||
Canvas mode overlay, mask, and transform paths also consume backend-owned
|
Canvas mode overlay, mask, and transform paths also consume backend-owned
|
||||||
blend/depth state, active texture units, 2D texture copy targets, and RGBA8
|
blend/depth state, active texture units, 2D texture copy targets, and RGBA8
|
||||||
readback format tokens.
|
readback format tokens.
|
||||||
@@ -599,12 +600,13 @@ Known local toolchain state:
|
|||||||
shared layout parser.
|
shared layout parser.
|
||||||
- `pp_renderer_gl` owns the tested `OpenGlInitialState` startup depth/blend
|
- `pp_renderer_gl` owns the tested `OpenGlInitialState` startup depth/blend
|
||||||
policy and dispatch application consumed by `App::init`, tested runtime
|
policy and dispatch application consumed by `App::init`, tested runtime
|
||||||
version/vendor/renderer/GLSL string query dispatch, tested default clear
|
version/vendor/renderer/GLSL string query dispatch consumed by `App::init`
|
||||||
|
and Windows startup logging/title construction, tested default clear
|
||||||
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 query/apply and buffer-clear dispatch consumed by
|
||||||
setup, tested saved-state snapshot/restore dispatch consumed by the retained
|
VR draw state setup and restore, tested saved-state snapshot/restore dispatch
|
||||||
`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 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
|
||||||
|
|||||||
@@ -781,7 +781,9 @@ delegates to the backend dispatch path instead of hard-coding the policy or
|
|||||||
operation order.
|
operation order.
|
||||||
OpenGL runtime version/vendor/renderer/GLSL string queries now also use a
|
OpenGL runtime version/vendor/renderer/GLSL string queries now also use a
|
||||||
tested `pp_renderer_gl` dispatch contract, leaving `App::init` to log the
|
tested `pp_renderer_gl` dispatch contract, leaving `App::init` to log the
|
||||||
result while the backend owns the query set and order.
|
result while the backend owns the query set and order. The Windows entrypoint
|
||||||
|
also uses that contract for early context logging and renderer-name window
|
||||||
|
title construction before replacing the temporary WGL context.
|
||||||
The default app clear color and color-buffer clear operation now dispatch
|
The default app clear color and color-buffer clear operation now dispatch
|
||||||
through `pp_renderer_gl` as well, moving another direct OpenGL operation out
|
through `pp_renderer_gl` as well, moving another direct OpenGL operation out
|
||||||
of `App::clear` while preserving the current gray clear behavior.
|
of `App::clear` while preserving the current gray clear behavior.
|
||||||
@@ -792,10 +794,10 @@ the live OpenGL call sequence.
|
|||||||
VR UI framebuffer viewport and scissor-test setup now also consumes those
|
VR UI framebuffer viewport and scissor-test setup now also consumes those
|
||||||
`pp_renderer_gl` contracts, keeping desktop and VR UI rendering aligned while
|
`pp_renderer_gl` contracts, keeping desktop and VR UI rendering aligned while
|
||||||
the retained OpenVR app path is split incrementally.
|
the retained OpenVR app path is split incrementally.
|
||||||
VR draw blend/depth state transitions and depth-buffer clears now use generic
|
VR draw blend/depth state snapshots, transitions, restore, and depth-buffer
|
||||||
tested `pp_renderer_gl` capability and clear dispatch contracts, reducing
|
clears now use generic tested `pp_renderer_gl` capability query/apply and clear
|
||||||
direct OpenGL execution in the retained VR app path without changing state
|
dispatch contracts, reducing direct OpenGL execution in the retained VR app
|
||||||
restore behavior.
|
path without changing state restore behavior.
|
||||||
The retained `gl_state` save/restore utility now snapshots and restores through
|
The retained `gl_state` save/restore utility now snapshots and restores through
|
||||||
tested `pp_renderer_gl` saved-state dispatch contracts, covering capability
|
tested `pp_renderer_gl` saved-state dispatch contracts, covering capability
|
||||||
state, viewport, clear color, framebuffer/program bindings, active texture,
|
state, viewport, clear color, framebuffer/program bindings, active texture,
|
||||||
@@ -1081,7 +1083,8 @@ longer expose raw OpenGL enum defaults; default texture formats, sampler
|
|||||||
filters/wraps, and render-target formats are resolved through backend-owned
|
filters/wraps, and render-target formats are resolved through backend-owned
|
||||||
overloads.
|
overloads.
|
||||||
The Windows entrypoint now delegates generic OpenGL error-code/info-string
|
The Windows entrypoint now delegates generic OpenGL error-code/info-string
|
||||||
tokens and WGL core-context/pixel-format attribute catalogs to `pp_renderer_gl`.
|
tokens, runtime string query ordering, and WGL core-context/pixel-format
|
||||||
|
attribute catalogs to `pp_renderer_gl`.
|
||||||
The headless OpenGL command planner now consumes `pp_renderer_api` recorded
|
The headless OpenGL command planner now consumes `pp_renderer_api` recorded
|
||||||
commands and maps render-pass clear masks/values, viewport/scissor state,
|
commands and maps render-pass clear masks/values, viewport/scissor state,
|
||||||
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
||||||
@@ -1966,9 +1969,9 @@ Results:
|
|||||||
- Android arm64 configured with NDK 29.0.14206865 through the platform-build
|
- Android arm64 configured with NDK 29.0.14206865 through the platform-build
|
||||||
wrapper and compiled headless foundation/tool/test targets.
|
wrapper and compiled headless foundation/tool/test targets.
|
||||||
- Desktop VR drawing now routes generic OpenGL scissor/depth/blend state,
|
- Desktop VR drawing now routes generic OpenGL scissor/depth/blend state,
|
||||||
depth clears, active texture units, and fallback 2D texture unbinds through
|
blend/depth state snapshots and restores, depth clears, active texture units,
|
||||||
the renderer GL backend mapping; platform VR SDK bridges remain isolated for
|
and fallback 2D texture unbinds through the renderer GL backend mapping;
|
||||||
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, and RGBA8
|
||||||
readback formats through the renderer GL backend mapping.
|
readback formats through the renderer GL backend mapping.
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ void disable_opengl_state(std::uint32_t state) noexcept
|
|||||||
glDisable(static_cast<GLenum>(state));
|
glDisable(static_cast<GLenum>(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint8_t is_opengl_state_enabled(std::uint32_t state) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint8_t>(glIsEnabled(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
|
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));
|
glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
|
||||||
@@ -75,6 +80,20 @@ void apply_vr_render_capability(std::uint32_t state, bool enabled)
|
|||||||
LOG("OpenGL VR render state failed: %s", status.message);
|
LOG("OpenGL VR render state failed: %s", status.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool query_vr_render_capability(std::uint32_t state)
|
||||||
|
{
|
||||||
|
const auto result = pp::renderer::gl::query_opengl_capability_state(
|
||||||
|
state,
|
||||||
|
pp::renderer::gl::OpenGlCapabilityStateQueryDispatch {
|
||||||
|
.is_enabled = is_opengl_state_enabled,
|
||||||
|
});
|
||||||
|
if (!result.ok()) {
|
||||||
|
LOG("OpenGL VR render state query failed: %s", result.status().message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return result.value();
|
||||||
|
}
|
||||||
|
|
||||||
void clear_vr_depth_buffer()
|
void clear_vr_depth_buffer()
|
||||||
{
|
{
|
||||||
const auto status = pp::renderer::gl::clear_opengl_buffers(
|
const auto status = pp::renderer::gl::clear_opengl_buffers(
|
||||||
@@ -262,8 +281,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
|
|||||||
glm::vec3 origin = glm::vec3(0, 0, -1) * glm::transpose(glm::mat3(pose));
|
glm::vec3 origin = glm::vec3(0, 0, -1) * glm::transpose(glm::mat3(pose));
|
||||||
vr_rot = glm::lookAt({ 0, 0, 0 }, origin, { 0, 1, 0 });
|
vr_rot = glm::lookAt({ 0, 0, 0 }, origin, { 0, 1, 0 });
|
||||||
|
|
||||||
auto blend = glIsEnabled(pp::renderer::gl::blend_state());
|
const bool blend = query_vr_render_capability(pp::renderer::gl::blend_state());
|
||||||
auto depth = glIsEnabled(pp::renderer::gl::depth_test_state());
|
const bool depth = query_vr_render_capability(pp::renderer::gl::depth_test_state());
|
||||||
|
|
||||||
apply_vr_render_capability(pp::renderer::gl::blend_state(), false);
|
apply_vr_render_capability(pp::renderer::gl::blend_state(), false);
|
||||||
apply_vr_render_capability(pp::renderer::gl::depth_test_state(), false);
|
apply_vr_render_capability(pp::renderer::gl::depth_test_state(), false);
|
||||||
@@ -556,8 +575,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
|
|||||||
mode->on_Draw(ortho_proj, proj, camera);
|
mode->on_Draw(ortho_proj, proj, camera);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
apply_vr_render_capability(pp::renderer::gl::blend_state(), blend != 0U);
|
apply_vr_render_capability(pp::renderer::gl::blend_state(), blend);
|
||||||
apply_vr_render_capability(pp::renderer::gl::depth_test_state(), depth != 0U);
|
apply_vr_render_capability(pp::renderer::gl::depth_test_state(), depth);
|
||||||
sampler.unbind();
|
sampler.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
src/main.cpp
24
src/main.cpp
@@ -89,6 +89,11 @@ void win32_renderdoc_frame_start() { }
|
|||||||
void win32_renderdoc_frame_end() { }
|
void win32_renderdoc_frame_end() { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char* query_opengl_string(std::uint32_t name) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const char*>(glGetString(static_cast<GLenum>(name)));
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
|
HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
|
||||||
HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value);
|
HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value);
|
||||||
void init_shcore_API()
|
void init_shcore_API()
|
||||||
@@ -853,17 +858,28 @@ int main(int argc, char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("GL version: %s", glGetString(static_cast<GLenum>(pp::renderer::gl::version_string_name())));
|
auto runtime_info = pp::renderer::gl::OpenGlRuntimeInfo {};
|
||||||
LOG("GL vendor: %s", glGetString(static_cast<GLenum>(pp::renderer::gl::vendor_string_name())));
|
const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info(
|
||||||
LOG("GL renderer: %s", glGetString(static_cast<GLenum>(pp::renderer::gl::renderer_string_name())));
|
pp::renderer::gl::OpenGlRuntimeInfoDispatch {
|
||||||
|
.get_string = query_opengl_string,
|
||||||
|
});
|
||||||
|
if (runtime_info_result.ok()) {
|
||||||
|
runtime_info = runtime_info_result.value();
|
||||||
|
LOG("GL version: %s", runtime_info.version);
|
||||||
|
LOG("GL vendor: %s", runtime_info.vendor);
|
||||||
|
LOG("GL renderer: %s", runtime_info.renderer);
|
||||||
|
} else {
|
||||||
|
LOG("OpenGL runtime info query failed: %s", runtime_info_result.status().message);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_RENDERDOC
|
#ifdef USE_RENDERDOC
|
||||||
if (!win32_renderdoc_init())
|
if (!win32_renderdoc_init())
|
||||||
LOG("Renderdoc not started");
|
LOG("Renderdoc not started");
|
||||||
#endif // USE_RENDERDOC
|
#endif // USE_RENDERDOC
|
||||||
|
|
||||||
|
const auto renderer_name = std::string(runtime_info.renderer != nullptr ? runtime_info.renderer : "");
|
||||||
swprintf_s(window_title, L"PanoPainter %s (%s)", g_version_number_w,
|
swprintf_s(window_title, L"PanoPainter %s (%s)", g_version_number_w,
|
||||||
str2wstr((char*)glGetString(static_cast<GLenum>(pp::renderer::gl::renderer_string_name()))).c_str());
|
str2wstr(renderer_name).c_str());
|
||||||
|
|
||||||
// If supported create a 3.3 context
|
// If supported create a 3.3 context
|
||||||
if (GLAD_WGL_ARB_create_context)
|
if (GLAD_WGL_ARB_create_context)
|
||||||
|
|||||||
@@ -526,6 +526,18 @@ pp::foundation::Status apply_opengl_capability(
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<bool> query_opengl_capability_state(
|
||||||
|
std::uint32_t state,
|
||||||
|
OpenGlCapabilityStateQueryDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.is_enabled == nullptr) {
|
||||||
|
return pp::foundation::Result<bool>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL capability state query callback must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Result<bool>::success(dispatch.is_enabled(state) != 0U);
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Status apply_opengl_render_platform_hints(
|
pp::foundation::Status apply_opengl_render_platform_hints(
|
||||||
OpenGlRenderPlatformHintDispatch dispatch) noexcept
|
OpenGlRenderPlatformHintDispatch dispatch) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -530,6 +530,10 @@ struct OpenGlCapabilityDispatch {
|
|||||||
OpenGlCapabilityFn disable = nullptr;
|
OpenGlCapabilityFn disable = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlCapabilityStateQueryDispatch {
|
||||||
|
OpenGlIsEnabledFn is_enabled = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct OpenGlRenderPlatformHintDispatch {
|
struct OpenGlRenderPlatformHintDispatch {
|
||||||
OpenGlCapabilityFn enable = nullptr;
|
OpenGlCapabilityFn enable = nullptr;
|
||||||
};
|
};
|
||||||
@@ -760,6 +764,9 @@ struct OpenGlMeshDeleteDispatch {
|
|||||||
std::uint32_t state,
|
std::uint32_t state,
|
||||||
bool enabled,
|
bool enabled,
|
||||||
OpenGlCapabilityDispatch dispatch) noexcept;
|
OpenGlCapabilityDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<bool> query_opengl_capability_state(
|
||||||
|
std::uint32_t state,
|
||||||
|
OpenGlCapabilityStateQueryDispatch dispatch) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status apply_opengl_render_platform_hints(
|
[[nodiscard]] pp::foundation::Status apply_opengl_render_platform_hints(
|
||||||
OpenGlRenderPlatformHintDispatch dispatch) noexcept;
|
OpenGlRenderPlatformHintDispatch dispatch) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status apply_opengl_debug_output_states(
|
[[nodiscard]] pp::foundation::Status apply_opengl_debug_output_states(
|
||||||
|
|||||||
@@ -2246,6 +2246,35 @@ void rejects_incomplete_generic_capability_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 queries_generic_capability_state(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto blend = pp::renderer::gl::query_opengl_capability_state(
|
||||||
|
0x0BE2U,
|
||||||
|
pp::renderer::gl::OpenGlCapabilityStateQueryDispatch {
|
||||||
|
.is_enabled = record_is_enabled,
|
||||||
|
});
|
||||||
|
const auto depth = pp::renderer::gl::query_opengl_capability_state(
|
||||||
|
0x0B71U,
|
||||||
|
pp::renderer::gl::OpenGlCapabilityStateQueryDispatch {
|
||||||
|
.is_enabled = record_is_enabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, blend.ok());
|
||||||
|
PP_EXPECT(h, blend.value());
|
||||||
|
PP_EXPECT(h, depth.ok());
|
||||||
|
PP_EXPECT(h, !depth.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_incomplete_generic_capability_state_query(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const auto result = pp::renderer::gl::query_opengl_capability_state(
|
||||||
|
0x0BE2U,
|
||||||
|
pp::renderer::gl::OpenGlCapabilityStateQueryDispatch {});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !result.ok());
|
||||||
|
PP_EXPECT(h, result.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
void applies_render_platform_hints(pp::tests::Harness& h)
|
void applies_render_platform_hints(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
recorded_state_calls.clear();
|
recorded_state_calls.clear();
|
||||||
@@ -4435,6 +4464,8 @@ int main()
|
|||||||
harness.run("rejects_incomplete_scissor_test_dispatch", rejects_incomplete_scissor_test_dispatch);
|
harness.run("rejects_incomplete_scissor_test_dispatch", rejects_incomplete_scissor_test_dispatch);
|
||||||
harness.run("applies_generic_capability_dispatch", applies_generic_capability_dispatch);
|
harness.run("applies_generic_capability_dispatch", applies_generic_capability_dispatch);
|
||||||
harness.run("rejects_incomplete_generic_capability_dispatch", rejects_incomplete_generic_capability_dispatch);
|
harness.run("rejects_incomplete_generic_capability_dispatch", rejects_incomplete_generic_capability_dispatch);
|
||||||
|
harness.run("queries_generic_capability_state", queries_generic_capability_state);
|
||||||
|
harness.run("rejects_incomplete_generic_capability_state_query", rejects_incomplete_generic_capability_state_query);
|
||||||
harness.run("applies_render_platform_hints", applies_render_platform_hints);
|
harness.run("applies_render_platform_hints", applies_render_platform_hints);
|
||||||
harness.run("rejects_incomplete_render_platform_hint_dispatch", rejects_incomplete_render_platform_hint_dispatch);
|
harness.run("rejects_incomplete_render_platform_hint_dispatch", rejects_incomplete_render_platform_hint_dispatch);
|
||||||
harness.run("applies_debug_output_states", applies_debug_output_states);
|
harness.run("applies_debug_output_states", applies_debug_output_states);
|
||||||
|
|||||||
Reference in New Issue
Block a user