diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 661423c..bb4fe09 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -460,9 +460,10 @@ Known local toolchain state: the debt-tracked adapter isolated in `src/platform_legacy/legacy_platform_services.*`. - `pp_renderer_gl` owns the tested `OpenGlInitialState` startup depth/blend - policy and dispatch application consumed by `App::init`, plus renderer API - to OpenGL token mapping and command-planning contracts used by the OpenGL - parity work. + policy and dispatch application consumed by `App::init`, tested runtime + version/vendor/renderer/GLSL string query dispatch, 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, new-document warning, publish prompt, and save-before-upload planning as JSON; the live cloud upload command consumes the same start contract before diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 15b1652..a9cc301 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -518,6 +518,9 @@ Initial PanoPainter OpenGL depth/blend startup state is now represented and applied by tested `pp_renderer_gl` startup-state contracts; `App::init` delegates to the backend dispatch path instead of hard-coding the policy or operation order. +OpenGL runtime version/vendor/renderer/GLSL string queries now also use a +tested `pp_renderer_gl` dispatch contract, leaving `App::init` to log the +result while the backend owns the query set and order. Windows RenderDoc frame capture hooks now also dispatch through `PlatformServices`, keeping capture integration in the platform service while leaving non-Windows adapters as no-ops. diff --git a/src/app.cpp b/src/app.cpp index b5e316c..7c9b184 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -25,31 +25,16 @@ std::condition_variable App::render_cv; namespace { -[[nodiscard]] GLenum version_string_name() noexcept -{ - return static_cast(pp::renderer::gl::version_string_name()); -} - -[[nodiscard]] GLenum vendor_string_name() noexcept -{ - return static_cast(pp::renderer::gl::vendor_string_name()); -} - -[[nodiscard]] GLenum renderer_string_name() noexcept -{ - return static_cast(pp::renderer::gl::renderer_string_name()); -} - -[[nodiscard]] GLenum shading_language_version_string_name() noexcept -{ - return static_cast(pp::renderer::gl::shading_language_version_string_name()); -} - [[nodiscard]] GLenum scissor_test_state() noexcept { return static_cast(pp::renderer::gl::scissor_test_state()); } +[[nodiscard]] const char* query_opengl_string(std::uint32_t name) noexcept +{ + return reinterpret_cast(glGetString(static_cast(name))); +} + void enable_opengl_state(std::uint32_t state) noexcept { glEnable(static_cast(state)); @@ -393,10 +378,22 @@ void App::init() render_task([] { App::I->install_render_debug_callback(); - LOG("GL version: %s", glGetString(version_string_name())); - LOG("GL vendor: %s", glGetString(vendor_string_name())); - LOG("GL renderer: %s", glGetString(renderer_string_name())); - LOG("GLSL version: %s", glGetString(shading_language_version_string_name())); + const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info( + pp::renderer::gl::OpenGlRuntimeInfoDispatch { + .get_string = query_opengl_string, + }); + if (runtime_info_result.ok()) + { + const auto& 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); + LOG("GLSL version: %s", runtime_info.shading_language_version); + } + else + { + LOG("OpenGL runtime info failed: %s", runtime_info_result.status().message); + } //GLint n_exts; //glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts); diff --git a/src/renderer_gl/opengl_capabilities.cpp b/src/renderer_gl/opengl_capabilities.cpp index 164b6d7..008caf6 100644 --- a/src/renderer_gl/opengl_capabilities.cpp +++ b/src/renderer_gl/opengl_capabilities.cpp @@ -245,6 +245,22 @@ pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispa return pp::foundation::Status::success(); } +pp::foundation::Result query_opengl_runtime_info( + OpenGlRuntimeInfoDispatch dispatch) noexcept +{ + if (dispatch.get_string == nullptr) { + return pp::foundation::Result::failure( + pp::foundation::Status::invalid_argument("OpenGL runtime info string callback must not be null")); + } + + return pp::foundation::Result::success(OpenGlRuntimeInfo { + .version = dispatch.get_string(version_string_name()), + .vendor = dispatch.get_string(vendor_string_name()), + .renderer = dispatch.get_string(renderer_string_name()), + .shading_language_version = dispatch.get_string(shading_language_version_string_name()), + }); +} + std::uint32_t extension_count_query() noexcept { return gl_num_extensions; diff --git a/src/renderer_gl/opengl_capabilities.h b/src/renderer_gl/opengl_capabilities.h index 9868b29..06b4759 100644 --- a/src/renderer_gl/opengl_capabilities.h +++ b/src/renderer_gl/opengl_capabilities.h @@ -135,6 +135,19 @@ struct OpenGlStateDispatch { OpenGlBlendEquationSeparateFn blend_equation_separate = nullptr; }; +struct OpenGlRuntimeInfo { + const char* version = ""; + const char* vendor = ""; + const char* renderer = ""; + const char* shading_language_version = ""; +}; + +using OpenGlStringQueryFn = const char* (*)(std::uint32_t name) noexcept; + +struct OpenGlRuntimeInfoDispatch { + OpenGlStringQueryFn get_string = nullptr; +}; + [[nodiscard]] OpenGlCapabilities detect_opengl_capabilities( std::span extensions, OpenGlRuntime runtime) noexcept; @@ -142,6 +155,8 @@ struct OpenGlStateDispatch { OpenGlCapabilities capabilities) noexcept; [[nodiscard]] OpenGlInitialState panopainter_initial_state() noexcept; [[nodiscard]] pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispatch) noexcept; +[[nodiscard]] pp::foundation::Result query_opengl_runtime_info( + OpenGlRuntimeInfoDispatch dispatch) noexcept; [[nodiscard]] std::uint32_t extension_count_query() noexcept; [[nodiscard]] std::uint32_t extension_string_name() noexcept; diff --git a/tests/renderer_gl/capabilities_tests.cpp b/tests/renderer_gl/capabilities_tests.cpp index 7737fed..cdfa33e 100644 --- a/tests/renderer_gl/capabilities_tests.cpp +++ b/tests/renderer_gl/capabilities_tests.cpp @@ -25,6 +25,7 @@ struct RecordedOpenGlStateCall { }; std::vector recorded_state_calls; +std::vector recorded_string_queries; void record_enable(std::uint32_t state) noexcept { @@ -60,6 +61,23 @@ void record_blend_equation_separate(std::uint32_t color_equation, std::uint32_t }); } +const char* record_string_query(std::uint32_t name) noexcept +{ + recorded_string_queries.push_back(name); + switch (name) { + case 0x1F02U: + return "test-version"; + case 0x1F00U: + return "test-vendor"; + case 0x1F01U: + return "test-renderer"; + case 0x8B8CU: + return "test-glsl"; + default: + return "unexpected"; + } +} + void detects_common_extension_capabilities(pp::tests::Harness& h) { constexpr std::array extensions { @@ -738,6 +756,35 @@ void rejects_incomplete_app_initialization_state_dispatch(pp::tests::Harness& h) PP_EXPECT(h, status.code == pp::foundation::StatusCode::invalid_argument); } +void queries_app_runtime_info(pp::tests::Harness& h) +{ + recorded_string_queries.clear(); + + const auto result = pp::renderer::gl::query_opengl_runtime_info( + pp::renderer::gl::OpenGlRuntimeInfoDispatch { + .get_string = record_string_query, + }); + + PP_EXPECT(h, result.ok()); + PP_EXPECT(h, recorded_string_queries.size() == 4U); + PP_EXPECT(h, recorded_string_queries[0] == 0x1F02U); + PP_EXPECT(h, recorded_string_queries[1] == 0x1F00U); + PP_EXPECT(h, recorded_string_queries[2] == 0x1F01U); + PP_EXPECT(h, recorded_string_queries[3] == 0x8B8CU); + PP_EXPECT(h, std::strcmp(result.value().version, "test-version") == 0); + PP_EXPECT(h, std::strcmp(result.value().vendor, "test-vendor") == 0); + PP_EXPECT(h, std::strcmp(result.value().renderer, "test-renderer") == 0); + PP_EXPECT(h, std::strcmp(result.value().shading_language_version, "test-glsl") == 0); +} + +void rejects_incomplete_app_runtime_info_dispatch(pp::tests::Harness& h) +{ + const auto result = pp::renderer::gl::query_opengl_runtime_info(pp::renderer::gl::OpenGlRuntimeInfoDispatch {}); + + PP_EXPECT(h, !result.ok()); + PP_EXPECT(h, result.status().code == pp::foundation::StatusCode::invalid_argument); +} + void maps_renderer_viewports_and_scissors(pp::tests::Harness& h) { const auto viewport = pp::renderer::gl::viewport_for_renderer_viewport( @@ -1114,6 +1161,8 @@ int main() harness.run("maps_app_initialization_parameters", maps_app_initialization_parameters); 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("queries_app_runtime_info", queries_app_runtime_info); + harness.run("rejects_incomplete_app_runtime_info_dispatch", rejects_incomplete_app_runtime_info_dispatch); 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_color_write_masks", maps_renderer_color_write_masks);