Publish renderer feature snapshot for canvas gates

This commit is contained in:
2026-06-03 18:32:17 +02:00
parent 1369a9048e
commit bc5b39057d
7 changed files with 40 additions and 9 deletions

View File

@@ -53,7 +53,7 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, and the `ToolsMenuServices` boundary, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and call the iOS SonarPen bridge directly | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter |
| DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_about`, `pano_cli plan-about-menu`, and the `AboutMenuServices` boundary, but the live adapter still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly | Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | `pp_app_core_about_menu_tests`; `pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7`; `pano_cli plan-about-menu --command performance --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with `App::init_menu_about` acting only as a UI adapter and no legacy About adapter |
| DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-main-toolbar`, and the `MainToolbarServices` boundary, and history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, but the live adapter still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters | Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | `pp_app_core_main_toolbar_tests`; `pano_cli plan-main-toolbar --command undo --undo-count 2`; `pano_cli plan-main-toolbar --command clear-canvas --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with `App::init_toolbar_main` acting only as a UI adapter and no legacy toolbar adapter |
| DEBT-0036 | Open | Modernization | `pp_renderer_api`, `pp_paint_renderer`, `pano_cli plan-paint-feedback`, and `pano_cli plan-stroke-composite` can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. `pp_paint_renderer::plan_canvas_blend_gate` now owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live `Canvas::draw_merge` plus `NodeCanvas` panorama rendering both call it for their existing shader-blend gates. Actual live stroke compositing, dual-brush feedback, and pattern feedback still use the legacy OpenGL canvas path | Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | `pp_renderer_api_tests`; `pp_paint_renderer_compositor_tests`; `pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-paint-feedback --texture-copy`; `pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Live stroke/layer compositing chooses its feedback path through `pp_paint_renderer` and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior |
| DEBT-0036 | Open | Modernization | `pp_renderer_api`, `pp_paint_renderer`, `pano_cli plan-paint-feedback`, and `pano_cli plan-stroke-composite` can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. OpenGL extension detection now stores `pp::renderer::RenderDeviceFeatures` through `ShaderManager`, using `pp_renderer_gl::render_device_features` as the backend conversion point. `pp_paint_renderer::plan_canvas_blend_gate` owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live `Canvas::draw_merge` plus `NodeCanvas` panorama rendering both call it with the stored renderer-neutral feature set for their existing shader-blend gates. Actual live stroke compositing, dual-brush feedback, and pattern feedback still use the legacy OpenGL canvas path | Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | `pp_renderer_api_tests`; `pp_renderer_gl_capabilities_tests`; `pp_paint_renderer_compositor_tests`; `pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-paint-feedback --texture-copy`; `pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Live stroke/layer compositing chooses its feedback path through `pp_paint_renderer` and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior |
## Closed Debt

View File

@@ -883,6 +883,10 @@ mapping from persisted layer and brush blend indices to that planner, including
fallback behavior for unknown nonzero indices. Both `Canvas::draw_merge` and
`NodeCanvas` panorama rendering consume that shared gate, so the live app no
longer has duplicate local blend-trigger logic.
The OpenGL shader initialization path now stores a renderer-neutral
`RenderDeviceFeatures` snapshot converted by `pp_renderer_gl`, and those live
canvas gates consume that snapshot instead of rebuilding feature flags from
individual `ShaderManager` extension booleans.
The existing renderer classes are not yet fully
behind the renderer interfaces.
@@ -1610,6 +1614,10 @@ Results:
- `NodeCanvas` panorama rendering now consumes the same tested
`pp_paint_renderer` canvas blend-gate planner as `Canvas::draw_merge`, so
layer and primary-brush blend-trigger compatibility is centralized.
- Shader initialization now publishes the OpenGL backend's renderer-neutral
feature snapshot through the legacy shader manager, and live canvas blend
gates consume that `RenderDeviceFeatures` value instead of hand-built
framebuffer-fetch/texture-copy flags.
- Canvas equirectangular import drawing and depth export rendering now route
depth/blend state and active texture units through the renderer GL backend
mapping.

View File

@@ -16,6 +16,17 @@ namespace {
return static_cast<GLenum>(pp::renderer::gl::extension_string_name());
}
[[nodiscard]] pp::renderer::gl::OpenGlCapabilities shader_manager_capabilities() noexcept
{
pp::renderer::gl::OpenGlCapabilities capabilities;
capabilities.framebuffer_fetch = ShaderManager::ext_framebuffer_fetch;
capabilities.map_buffer_alignment = ShaderManager::ext_map_aligned;
capabilities.float32_textures = ShaderManager::ext_float32;
capabilities.float32_linear = ShaderManager::ext_float32_linear;
capabilities.float16_textures = ShaderManager::ext_float16;
return capabilities;
}
}
void App::initShaders()
@@ -55,6 +66,7 @@ void App::initShaders()
ShaderManager::ext_float32 = capabilities.float32_textures;
ShaderManager::ext_float32_linear = capabilities.float32_linear;
ShaderManager::ext_float16 = capabilities.float16_textures;
ShaderManager::set_render_device_features(pp::renderer::gl::render_device_features(capabilities));
});
#if __GL__
@@ -63,6 +75,8 @@ void App::initShaders()
ShaderManager::ext_float32 = true;
ShaderManager::ext_float16 = true;
#endif
ShaderManager::set_render_device_features(
pp::renderer::gl::render_device_features(shader_manager_capabilities()));
LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled");

View File

@@ -46,10 +46,7 @@ GLenum rgba_pixel_format()
pp::renderer::RenderDeviceFeatures canvas_stroke_composite_features() noexcept
{
return pp::renderer::RenderDeviceFeatures {
.framebuffer_fetch = ShaderManager::ext_framebuffer_fetch,
.texture_copy = !ShaderManager::ext_framebuffer_fetch,
};
return ShaderManager::render_device_features();
}
bool draw_merge_needs_shader_blend(

View File

@@ -29,10 +29,7 @@ void unbind_texture_2d()
pp::renderer::RenderDeviceFeatures node_canvas_stroke_composite_features() noexcept
{
return pp::renderer::RenderDeviceFeatures {
.framebuffer_fetch = ShaderManager::ext_framebuffer_fetch,
.texture_copy = !ShaderManager::ext_framebuffer_fetch,
};
return ShaderManager::render_device_features();
}
bool node_canvas_needs_shader_blend(

View File

@@ -211,6 +211,7 @@ std::int32_t get_opengl_uniform_location(std::uint32_t program, const char* name
std::map<kShader, Shader> ShaderManager::m_shaders;
Shader* ShaderManager::m_current;
pp::renderer::RenderDeviceFeatures ShaderManager::m_render_device_features {};
bool ShaderManager::ext_framebuffer_fetch = false;
bool ShaderManager::ext_float32 = false;
bool ShaderManager::ext_float32_linear = false;
@@ -816,6 +817,16 @@ void ShaderManager::u_float(kShaderUniform id, float f)
m_current->u_float(id, f);
}
void ShaderManager::set_render_device_features(pp::renderer::RenderDeviceFeatures features) noexcept
{
m_render_device_features = features;
}
pp::renderer::RenderDeviceFeatures ShaderManager::render_device_features() noexcept
{
return m_render_device_features;
}
void ShaderManager::invalidate()
{
m_shaders.clear();

View File

@@ -1,4 +1,5 @@
#pragma once
#include "renderer_api/renderer_api.h"
#include "util.h"
bool check_uniform_uniqueness();
@@ -108,6 +109,7 @@ class ShaderManager
{
static std::map<kShader, Shader> m_shaders;
static Shader* m_current;
static pp::renderer::RenderDeviceFeatures m_render_device_features;
public:
static bool ext_framebuffer_fetch;
static bool ext_float32;
@@ -127,5 +129,7 @@ public:
static void u_int(kShaderUniform id, int i);
static void u_int(const char* name, int i);
static void u_float(kShaderUniform id, float f);
static void set_render_device_features(pp::renderer::RenderDeviceFeatures features) noexcept;
static pp::renderer::RenderDeviceFeatures render_device_features() noexcept;
static void invalidate();
};