Centralize retained UI GL dispatch

This commit is contained in:
2026-06-05 13:34:59 +02:00
parent 8f062fb0c4
commit 92fa5b224a
6 changed files with 122 additions and 265 deletions

View File

@@ -540,8 +540,8 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
clear-color restore, active texture unit execution, fallback 2D texture
unbinds, 2D texture targets, copy targets, and sampler filters/wraps. Its
live stroke-mixer and brush-preview viewport, scissor, and depth/blend state
changes now execute through tested `pp_renderer_gl` dispatch with only local
OpenGL adapter endpoints retained.
changes now execute through tested `pp_renderer_gl` dispatch via the shared
`legacy_ui_gl_dispatch` bridge.
Retained `Canvas` stroke/thumbnail/object/export paths and `NodeCanvas`
panorama rendering use the same tested active-texture dispatch for
texture-unit switches, and their live viewport, scissor, and generic
@@ -552,7 +552,10 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
clear-color query plus clear-color restore paths also use tested
`pp_renderer_gl` dispatch helpers. `NodeCanvas` saved viewport/clear-color
query, density/offscreen color clear, and clear-color restore paths use the
same helpers. Retained desktop HMD eye rendering also routes viewport
same helpers. `NodeCanvas` and `NodeStrokePreview` now share
`legacy_ui_gl_dispatch` for active texture, texture unbind, viewport/scissor,
clear-color, color-buffer clear, and capability query/apply adapter endpoints.
Retained desktop HMD eye rendering also routes viewport
execution through tested backend dispatch.
Legacy `Texture2D`, `TextureManager`, `Sampler`, and `RTT` public headers no
longer expose raw OpenGL enum defaults; default texture formats, sampler
@@ -855,6 +858,9 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
`NodeImageTexture`, `NodeColorWheel`, `NodeAnimationTimeline`, `NodeScroll`,
`NodeText`, `NodeTextInput`, and `NodeViewport` blend-state, fallback
texture unbind, viewport, color clear, and clear-color restore paths,
plus retained `NodeCanvas` and `NodeStrokePreview` active-texture, fallback
texture unbind, viewport/scissor, clear-color, color-buffer clear, and
capability query/apply draw-state adapter endpoints,
tested convert-command state dispatch consumed by
`App::cmd_convert`, tested render platform hint dispatch consumed by
`WindowsPlatformServices` and the retained macOS legacy fallback, tested

File diff suppressed because one or more lines are too long

View File

@@ -1252,8 +1252,8 @@ texture unit execution, fallback 2D texture unbinds, 2D texture targets, copy
targets, sampler filters/wraps, and destination-feedback copy/fetch decisions
to `pp_renderer_gl` and `pp_paint_renderer`. Its live stroke-mixer and
brush-preview viewport, scissor, and depth/blend state changes now also
execute through tested `pp_renderer_gl` dispatch with only local OpenGL adapter
endpoints retained.
execute through tested `pp_renderer_gl` dispatch via the shared
`legacy_ui_gl_dispatch` bridge.
Retained `Canvas` stroke/thumbnail/object/export paths and `NodeCanvas`
panorama rendering use the same tested active-texture dispatch for their
texture-unit switches, and their live viewport, scissor, and generic
@@ -1263,7 +1263,10 @@ snapshots now route through the same backend dispatch contracts. Retained
generation, object drawing, and `LayerFrame::clear` saved viewport/clear-color
query plus clear-color restore paths also use tested `pp_renderer_gl` dispatch
helpers. `NodeCanvas` saved viewport/clear-color query, density target color
clear, and clear-color restore paths use the same helpers.
clear, and clear-color restore paths use the same helpers. `NodeCanvas` and
`NodeStrokePreview` now share that retained UI GL dispatch bridge for
active-texture, fallback texture unbind, viewport/scissor, clear-color,
color-buffer clear, and capability query/apply adapter endpoints.
Desktop HMD eye rendering now routes eye framebuffer viewport changes through
the tested `pp_renderer_gl` viewport dispatch while platform VR SDK bridges
remain isolated for later platform-shell extraction.
@@ -2504,7 +2507,11 @@ Results:
- Retained paint UI surface paths now use tested `pp_renderer_gl` viewport
query, clear-color query, clear-color restore, and color-buffer clear helpers
in `NodeCanvas` and `NodeStrokePreview`, removing direct query/clear calls
from those draw bodies while keeping their legacy compositing order.
from those draw bodies while keeping their legacy compositing order. Their
active-texture, fallback texture unbind, viewport/scissor, clear-color,
color-buffer clear, and capability query/apply adapter endpoints are now
centralized in `legacy_ui_gl_dispatch` instead of being duplicated in each
node implementation.
- Retained Canvas stroke draw/commit, thumbnail, object-render, and
`LayerFrame::clear` paths now use the same tested backend viewport query,
clear-color query, and clear-color restore helpers, removing direct

View File

@@ -13,11 +13,21 @@ inline void enable_opengl_state(std::uint32_t state) noexcept
glEnable(static_cast<GLenum>(state));
}
inline std::uint8_t is_opengl_state_enabled(std::uint32_t state) noexcept
{
return static_cast<std::uint8_t>(glIsEnabled(static_cast<GLenum>(state)));
}
inline void disable_opengl_state(std::uint32_t state) noexcept
{
glDisable(static_cast<GLenum>(state));
}
inline void activate_opengl_texture(std::uint32_t texture_unit) noexcept
{
glActiveTexture(static_cast<GLenum>(texture_unit));
}
inline void clear_opengl_buffer(std::uint32_t mask) noexcept
{
glClear(static_cast<GLbitfield>(mask));
@@ -33,6 +43,11 @@ inline void set_opengl_viewport(std::int32_t x, std::int32_t y, std::int32_t wid
glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
}
inline void set_opengl_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept
{
glScissor(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
}
inline void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
{
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
@@ -61,6 +76,17 @@ inline std::array<std::int32_t, 4> query_viewport(const char* context)
return viewport;
}
inline pp::renderer::gl::OpenGlViewportRect query_viewport_rect(const char* context)
{
const auto result = pp::renderer::gl::query_opengl_viewport(
pp::renderer::gl::OpenGlViewportQueryDispatch {
.get_integer = get_opengl_integer,
});
if (!result.ok())
LOG("%s viewport query dispatch failed because: %s", context, result.status().message);
return result.value();
}
inline std::array<float, 4> query_clear_color(const char* context)
{
std::array<float, 4> color {};
@@ -69,6 +95,20 @@ inline std::array<float, 4> query_clear_color(const char* context)
return color;
}
inline bool query_capability(std::uint32_t state, const char* context)
{
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("%s capability query failed because: %s", context, result.status().message);
return false;
}
return result.value();
}
inline void set_capability(std::uint32_t state, bool enabled, const char* context)
{
const auto status = pp::renderer::gl::apply_opengl_capability(
@@ -82,6 +122,17 @@ inline void set_capability(std::uint32_t state, bool enabled, const char* contex
LOG("%s capability dispatch failed because: %s", context, status.message);
}
inline void activate_texture_unit(std::uint32_t unit_index, const char* context)
{
const auto status = pp::renderer::gl::activate_opengl_texture_unit(
unit_index,
pp::renderer::gl::OpenGlActiveTextureDispatch {
.active_texture = activate_opengl_texture,
});
if (!status.ok())
LOG("%s active texture dispatch failed because: %s", context, status.message);
}
inline void set_blend_enabled(bool enabled, const char* context)
{
set_capability(pp::renderer::gl::blend_state(), enabled, context);
@@ -108,6 +159,30 @@ inline void apply_viewport(
LOG("%s viewport dispatch failed because: %s", context, status.message);
}
inline void apply_scissor_rect(
std::int32_t x,
std::int32_t y,
std::int32_t width,
std::int32_t height,
const char* context)
{
const auto status = pp::renderer::gl::apply_opengl_scissor_rect(
pp::renderer::gl::OpenGlScissorRect {
.enabled = 1U,
.x = x,
.y = y,
.width = width,
.height = height,
},
pp::renderer::gl::OpenGlScissorDispatch {
.enable = enable_opengl_state,
.disable = disable_opengl_state,
.scissor = set_opengl_scissor,
});
if (!status.ok())
LOG("%s scissor dispatch failed because: %s", context, status.message);
}
inline void clear_color_buffer(std::array<float, 4> color, const char* context)
{
const auto status = pp::renderer::gl::clear_opengl_render_target(

View File

@@ -12,6 +12,7 @@
#include "app_core/document_animation.h"
#include "app.h"
#include "node_panel_grid.h"
#include "legacy_ui_gl_dispatch.h"
#include "legacy_canvas_tool_services.h"
#include "legacy_history_services.h"
#include "log.h"
@@ -24,174 +25,49 @@
namespace {
void activate_opengl_texture(std::uint32_t texture_unit) noexcept
{
glActiveTexture(static_cast<GLenum>(texture_unit));
}
void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
{
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
}
void set_active_texture_unit(std::uint32_t unit_index)
{
const auto status = pp::renderer::gl::activate_opengl_texture_unit(
unit_index,
pp::renderer::gl::OpenGlActiveTextureDispatch {
.active_texture = activate_opengl_texture,
});
if (!status.ok())
LOG("NodeCanvas active texture dispatch failed because: %s", status.message);
pp::legacy::ui_gl::activate_texture_unit(unit_index, "NodeCanvas");
}
void unbind_texture_2d()
{
const auto status = pp::renderer::gl::bind_opengl_texture_2d(
0U,
pp::renderer::gl::OpenGlTexture2DBindDispatch {
.bind_texture = bind_opengl_texture,
});
if (!status.ok())
LOG("NodeCanvas texture unbind dispatch failed because: %s", status.message);
}
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));
}
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
{
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 clear_opengl_buffer(std::uint32_t mask) noexcept
{
glClear(static_cast<GLbitfield>(mask));
}
void get_opengl_integer(std::uint32_t name, std::int32_t* values) noexcept
{
GLint raw_values[4] {};
glGetIntegerv(static_cast<GLenum>(name), raw_values);
values[0] = static_cast<std::int32_t>(raw_values[0]);
values[1] = static_cast<std::int32_t>(raw_values[1]);
values[2] = static_cast<std::int32_t>(raw_values[2]);
values[3] = static_cast<std::int32_t>(raw_values[3]);
}
void get_opengl_float(std::uint32_t name, float* values) noexcept
{
glGetFloatv(static_cast<GLenum>(name), values);
pp::legacy::ui_gl::unbind_texture_2d("NodeCanvas");
}
void apply_node_canvas_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
const auto status = pp::renderer::gl::apply_opengl_viewport(
pp::renderer::gl::OpenGlViewportRect {
.x = x,
.y = y,
.width = width,
.height = height,
},
pp::renderer::gl::OpenGlViewportDispatch {
.viewport = set_opengl_viewport,
});
if (!status.ok())
LOG("NodeCanvas viewport dispatch failed because: %s", status.message);
pp::legacy::ui_gl::apply_viewport(x, y, width, height, "NodeCanvas");
}
pp::renderer::gl::OpenGlViewportRect query_node_canvas_viewport()
{
const auto result = pp::renderer::gl::query_opengl_viewport(
pp::renderer::gl::OpenGlViewportQueryDispatch {
.get_integer = get_opengl_integer,
});
if (!result.ok()) {
LOG("NodeCanvas viewport query dispatch failed because: %s", result.status().message);
}
return result.value();
return pp::legacy::ui_gl::query_viewport_rect("NodeCanvas");
}
std::array<float, 4> query_node_canvas_clear_color()
{
const auto result = pp::renderer::gl::query_opengl_clear_color(
pp::renderer::gl::OpenGlClearColorQueryDispatch {
.get_float = get_opengl_float,
});
if (!result.ok()) {
LOG("NodeCanvas clear-color query dispatch failed because: %s", result.status().message);
}
return result.value();
return pp::legacy::ui_gl::query_clear_color("NodeCanvas");
}
void apply_node_canvas_clear_color(std::array<float, 4> color)
{
const auto status = pp::renderer::gl::apply_opengl_clear_color(
color,
pp::renderer::gl::OpenGlClearColorDispatch {
.clear_color = set_opengl_clear_color,
});
if (!status.ok())
LOG("NodeCanvas clear-color dispatch failed because: %s", status.message);
pp::legacy::ui_gl::set_clear_color(color, "NodeCanvas");
}
void clear_node_canvas_color_buffer(std::array<float, 4> color)
{
const auto status = pp::renderer::gl::clear_opengl_render_target(
pp::renderer::gl::OpenGlDefaultClear {
.color = color,
.mask = pp::renderer::gl::framebuffer_color_buffer_mask(),
},
pp::renderer::gl::OpenGlClearDispatch {
.clear_color = set_opengl_clear_color,
.clear = clear_opengl_buffer,
});
if (!status.ok())
LOG("NodeCanvas color-buffer clear dispatch failed because: %s", status.message);
pp::legacy::ui_gl::clear_color_buffer(color, "NodeCanvas");
}
void apply_node_canvas_capability(std::uint32_t state, bool enabled)
{
const auto status = pp::renderer::gl::apply_opengl_capability(
state,
enabled,
pp::renderer::gl::OpenGlCapabilityDispatch {
.enable = enable_opengl_state,
.disable = disable_opengl_state,
});
if (!status.ok())
LOG("NodeCanvas capability dispatch failed because: %s", status.message);
pp::legacy::ui_gl::set_capability(state, enabled, "NodeCanvas");
}
bool query_node_canvas_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("NodeCanvas capability query failed because: %s", result.status().message);
return false;
}
return result.value();
return pp::legacy::ui_gl::query_capability(state, "NodeCanvas");
}
pp::renderer::RenderDeviceFeatures node_canvas_stroke_composite_features() noexcept

View File

@@ -6,6 +6,7 @@
#include "bezier.h"
#include "canvas.h"
#include "app.h"
#include "legacy_ui_gl_dispatch.h"
#include "paint_renderer/compositor.h"
#include "renderer_gl/opengl_capabilities.h"
#include "util.h"
@@ -41,159 +42,44 @@ pp::paint_renderer::CanvasStrokeFeedbackPlan stroke_preview_destination_feedback
return fallback;
}
void activate_opengl_texture(std::uint32_t texture_unit) noexcept
{
glActiveTexture(static_cast<GLenum>(texture_unit));
}
void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
{
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
}
void set_active_texture_unit(std::uint32_t unit_index)
{
const auto status = pp::renderer::gl::activate_opengl_texture_unit(
unit_index,
pp::renderer::gl::OpenGlActiveTextureDispatch {
.active_texture = activate_opengl_texture,
});
if (!status.ok())
LOG("NodeStrokePreview active texture dispatch failed because: %s", status.message);
pp::legacy::ui_gl::activate_texture_unit(unit_index, "NodeStrokePreview");
}
void unbind_texture_2d()
{
const auto status = pp::renderer::gl::bind_opengl_texture_2d(
0U,
pp::renderer::gl::OpenGlTexture2DBindDispatch {
.bind_texture = bind_opengl_texture,
});
if (!status.ok())
LOG("NodeStrokePreview texture unbind dispatch failed because: %s", status.message);
}
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_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept
{
glScissor(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 get_opengl_integer(std::uint32_t name, std::int32_t* values) noexcept
{
GLint raw_values[4] {};
glGetIntegerv(static_cast<GLenum>(name), raw_values);
values[0] = static_cast<std::int32_t>(raw_values[0]);
values[1] = static_cast<std::int32_t>(raw_values[1]);
values[2] = static_cast<std::int32_t>(raw_values[2]);
values[3] = static_cast<std::int32_t>(raw_values[3]);
}
void get_opengl_float(std::uint32_t name, float* values) noexcept
{
glGetFloatv(static_cast<GLenum>(name), values);
pp::legacy::ui_gl::unbind_texture_2d("NodeStrokePreview");
}
void apply_stroke_preview_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
const auto status = pp::renderer::gl::apply_opengl_viewport(
pp::renderer::gl::OpenGlViewportRect {
.x = x,
.y = y,
.width = width,
.height = height,
},
pp::renderer::gl::OpenGlViewportDispatch {
.viewport = set_opengl_viewport,
});
if (!status.ok())
LOG("NodeStrokePreview viewport dispatch failed because: %s", status.message);
pp::legacy::ui_gl::apply_viewport(x, y, width, height, "NodeStrokePreview");
}
pp::renderer::gl::OpenGlViewportRect query_stroke_preview_viewport()
{
const auto result = pp::renderer::gl::query_opengl_viewport(
pp::renderer::gl::OpenGlViewportQueryDispatch {
.get_integer = get_opengl_integer,
});
if (!result.ok()) {
LOG("NodeStrokePreview viewport query dispatch failed because: %s", result.status().message);
}
return result.value();
return pp::legacy::ui_gl::query_viewport_rect("NodeStrokePreview");
}
std::array<float, 4> query_stroke_preview_clear_color()
{
const auto result = pp::renderer::gl::query_opengl_clear_color(
pp::renderer::gl::OpenGlClearColorQueryDispatch {
.get_float = get_opengl_float,
});
if (!result.ok()) {
LOG("NodeStrokePreview clear-color query dispatch failed because: %s", result.status().message);
}
return result.value();
return pp::legacy::ui_gl::query_clear_color("NodeStrokePreview");
}
void apply_stroke_preview_clear_color(std::array<float, 4> color)
{
const auto status = pp::renderer::gl::apply_opengl_clear_color(
color,
pp::renderer::gl::OpenGlClearColorDispatch {
.clear_color = set_opengl_clear_color,
});
if (!status.ok())
LOG("NodeStrokePreview clear-color dispatch failed because: %s", status.message);
pp::legacy::ui_gl::set_clear_color(color, "NodeStrokePreview");
}
void apply_stroke_preview_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
const auto status = pp::renderer::gl::apply_opengl_scissor_rect(
pp::renderer::gl::OpenGlScissorRect {
.enabled = 1U,
.x = x,
.y = y,
.width = width,
.height = height,
},
pp::renderer::gl::OpenGlScissorDispatch {
.enable = enable_opengl_state,
.disable = disable_opengl_state,
.scissor = set_opengl_scissor,
});
if (!status.ok())
LOG("NodeStrokePreview scissor dispatch failed because: %s", status.message);
pp::legacy::ui_gl::apply_scissor_rect(x, y, width, height, "NodeStrokePreview");
}
void apply_stroke_preview_capability(std::uint32_t state, bool enabled)
{
const auto status = pp::renderer::gl::apply_opengl_capability(
state,
enabled,
pp::renderer::gl::OpenGlCapabilityDispatch {
.enable = enable_opengl_state,
.disable = disable_opengl_state,
});
if (!status.ok())
LOG("NodeStrokePreview capability dispatch failed because: %s", status.message);
pp::legacy::ui_gl::set_capability(state, enabled, "NodeStrokePreview");
}
}