Route RTT lifecycle through GL backend
This commit is contained in:
@@ -287,13 +287,14 @@ Known local toolchain state:
|
||||
used by `TextureCube`. It also owns and
|
||||
validates framebuffer blit color mask and linear/nearest filters used by
|
||||
`RTT::resize` and `RTT::copy`, renderer API blit-filter to OpenGL token
|
||||
mapping, plus the default linear clamp-to-edge
|
||||
render-target texture parameters, texture/renderbuffer targets, depth format,
|
||||
framebuffer targets, binding queries, attachment points, and completion
|
||||
status used by `RTT::create` and framebuffer bind/restore paths, plus RTT
|
||||
clear color/depth masks. Canvas object-drawing depth renderbuffer
|
||||
allocation/storage/delete and framebuffer depth attach/detach also execute
|
||||
through tested dispatch contracts here. Renderer API render-pass color/depth/stencil
|
||||
mapping, plus the default linear clamp-to-edge render-target texture
|
||||
parameters and parameter dispatch, texture/renderbuffer targets, depth format,
|
||||
framebuffer targets, binding queries, attachment points, render-target
|
||||
framebuffer allocation/delete, binding restore, and completion status used by
|
||||
`RTT::create`/`RTT::destroy` and framebuffer bind/restore paths, plus RTT
|
||||
clear color/depth masks. Optional RTT depth renderbuffer allocation/storage/delete
|
||||
and framebuffer depth attach/detach, plus canvas object-drawing depth
|
||||
renderbuffer setup, also execute through tested dispatch contracts here. Renderer API render-pass color/depth/stencil
|
||||
clear-mask and clear-value mapping, and color-write-mask query tokens. `RTT` no longer
|
||||
spells GL enum names directly. `RTT` also exposes a retained RGBA8
|
||||
region-readback helper that uses the tested framebuffer readback dispatch for
|
||||
@@ -626,12 +627,14 @@ Known local toolchain state:
|
||||
consumed by the retained `gl_state` utility, tested texture lifecycle/readback dispatch consumed by
|
||||
the retained `Texture2D` utility, tested framebuffer blit/readback dispatch
|
||||
consumed by retained `RTT` resize/copy/readback and RGBA8 region-readback
|
||||
paths, tested pixel-buffer allocation/readback/map/unmap/delete dispatch
|
||||
paths, tested render-target texture parameter, framebuffer allocation/delete,
|
||||
color/depth attachment, status-check, and binding-restore dispatch consumed
|
||||
by retained `RTT::create`/`RTT::destroy`, tested pixel-buffer allocation/readback/map/unmap/delete dispatch
|
||||
consumed by retained `PBO` recording readbacks, tested framebuffer-to-texture
|
||||
2D copy dispatch consumed by retained canvas/UI paint paths, tested framebuffer
|
||||
bind/restore dispatch consumed by retained `RTT` render-target pass entry
|
||||
and exit paths, tested depth renderbuffer allocation/delete and framebuffer
|
||||
depth attach/detach dispatch consumed by canvas object-drawing helpers,
|
||||
depth attach/detach dispatch consumed by retained RTT and canvas object-drawing helpers,
|
||||
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
|
||||
|
||||
@@ -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, and direct command execution is centralized in `src/legacy_app_shell_services.*`; SonarPen availability/startup now routes through `PlatformServices`, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and rely on the legacy platform adapter for the retained iOS SonarPen bridge | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pp_platform_api_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, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge 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, history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge 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. OpenGL extension detection now stores `pp::renderer::RenderDeviceFeatures` through `ShaderManager`, using `pp_renderer_gl::query_opengl_capability_detection`, `detect_opengl_feature_state`, and `render_device_features` as the backend conversion point; that feature snapshot now includes float32-linear filtering, so canvas stroke texture format selection, renderer diagnostics, grid lightmap render planning, and grid bake target selection no longer read `ShaderManager::ext_*` flags directly. `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 and destination-copy versus framebuffer-fetch decisions. `pp_paint_renderer::plan_canvas_stroke_feedback` also owns the current destination-feedback decision, and live `Canvas::stroke_draw`, thumbnail layer blending, and `NodeStrokePreview` brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. The retained `copy_framebuffer_to_texture_2d` utility bridge now routes 2D framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch, but actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, brush-preview compositing, the retained cube-map framebuffer copy, and the retained `ShaderManager::ext_*` compatibility fields still use legacy OpenGL canvas/UI execution | 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 |
|
||||
| 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::query_opengl_capability_detection`, `detect_opengl_feature_state`, and `render_device_features` as the backend conversion point; that feature snapshot now includes float32-linear filtering, so canvas stroke texture format selection, renderer diagnostics, grid lightmap render planning, and grid bake target selection no longer read `ShaderManager::ext_*` flags directly. `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 and destination-copy versus framebuffer-fetch decisions. `pp_paint_renderer::plan_canvas_stroke_feedback` also owns the current destination-feedback decision, and live `Canvas::stroke_draw`, thumbnail layer blending, and `NodeStrokePreview` brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. The retained `copy_framebuffer_to_texture_2d` utility bridge now routes 2D framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch, and retained `RTT::create`/`RTT::destroy` render-target texture parameter setup, optional depth renderbuffer allocation, framebuffer allocation/attachment/status checks, binding restore, and resource deletion now route through tested `pp_renderer_gl` dispatch, but actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, brush-preview compositing, the retained cube-map framebuffer copy, and the retained `ShaderManager::ext_*` compatibility fields still use legacy OpenGL canvas/UI execution | 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 |
|
||||
| DEBT-0037 | Open | Modernization | Recording lifecycle/export planning and execution dispatch now consume pure `pp_app_core` through `App::rec_start`, `App::rec_stop`, `App::rec_clear`, `App::rec_export`, `pano_cli plan-recording-session`, and the `RecordingServices` boundary; live execution is centralized in `src/legacy_recording_services.*`, and retained `PBO` allocation/readback/map/unmap/delete operations now route through tested `pp_renderer_gl` dispatch, but the bridge still owns legacy recording thread startup/shutdown, platform recorded-file cleanup, progress UI, retained `App::rec_loop` readback call sites, and `MP4Encoder::write_mp4` execution | Preserve current timelapse/MP4 behavior while recording moves toward app/document/renderer/video services | `pp_app_core_document_recording_tests`; `pp_renderer_gl_capabilities_tests`; `pano_cli plan-recording-session --running --frame-count 12`; `pano_cli plan-recording-session --platform-clears-files`; `ctest --preset desktop-fast --build-config Debug` | Recording thread lifecycle, frame readback scheduling, platform cleanup, progress reporting, and MP4 writing are owned by injected app/renderer/video services with `App` methods acting only as adapters |
|
||||
| DEBT-0038 | Open | Modernization | Cloud upload/browse/bulk planning and execution dispatch now consume pure `pp_app_core` through `App::cloud_upload`, `App::cloud_upload_all`, `App::cloud_browse`, `pano_cli plan-cloud-upload`, `pano_cli plan-cloud-upload-all`, `pano_cli plan-cloud-browse`, and the `CloudServices` boundary; live execution is centralized in `src/legacy_cloud_services.*`, the app-owned `upload`/`download`/license curl helpers now ask `PlatformServices` for the Android TLS-verification bypass policy, and retained `Asset::open_url`, `LogRemote::net_init`, and `NodeDialogCloud::load_thumbs_thread` curl sites consume the `pp_platform_api` default TLS policy helper instead of spelling Android branches locally, but the bridge still uses legacy save-before-upload, app-owned curl helpers instead of an injected network service, progress/message UI, OpenGL context guarding, `NodeDialogCloud`, `Canvas` project open, layer refresh, and `ActionManager` reset | Preserve current cloud behavior while cloud/network/document import flows move toward app/document/platform services | `pp_app_core_document_cloud_tests`; `pp_platform_api_tests`; `pano_cli plan-cloud-upload --new-document --unsaved`; `pano_cli plan-cloud-browse --selected-file demo.ppi`; `pano_cli plan-cloud-upload-all --file-count 3`; `ctest --preset desktop-fast --build-config Debug` | Cloud upload/download, TLS policy, save-before-upload, progress reporting, cloud browse dialog, downloaded project opening, layer refresh, OpenGL context ownership, and action-history reset are owned by injected app/document/network/platform/renderer services with `App` methods acting only as adapters |
|
||||
| DEBT-0039 | Open | Modernization | Document-open planning and execution dispatch now consume pure `pp_app_core` through `App::open_document`, `pano_cli plan-open-route`, `DocumentOpenServices`, and `src/legacy_document_open_services.*`, but the bridge still opens ABR/PPBR import prompts before delegating import execution to `src/legacy_brush_package_import_services.*`, applies unsaved-project discard prompts, calls legacy project-open execution, refreshes layer UI, updates the app title, and clears legacy history directly | Preserve current file-open/import behavior while document loading and brush import move toward app/document/asset/UI services | `pp_app_core_document_route_tests`; `pp_app_core_document_session_tests`; `pano_cli plan-open-route --path D:/Paint/Scenes/demo.ppi --unsaved`; `pano_cli plan-open-route --path D:/Paint/Brushes/clouds.ABR --unsaved`; `ctest --preset desktop-fast --build-config Debug` | Brush import prompting, project-open execution, unsaved-project discard prompting, layer refresh, title updates, and history clearing are owned by injected app/document/asset/UI services with `App::open_document` acting only as an adapter |
|
||||
|
||||
@@ -810,6 +810,10 @@ resource lifecycle path behind the renderer backend boundary.
|
||||
Legacy `RTT` resize/copy blits and byte/float framebuffer readbacks now execute
|
||||
through tested `pp_renderer_gl` framebuffer dispatch contracts with draw/read
|
||||
framebuffer binding restore handled by the backend helper.
|
||||
Legacy `RTT::create`/`RTT::destroy` now route render-target texture allocation,
|
||||
default texture parameter setup, optional depth renderbuffer allocation,
|
||||
framebuffer color/depth attachment, framebuffer status checks, binding restore,
|
||||
and resource deletion through tested `pp_renderer_gl` dispatch helpers.
|
||||
Legacy `RTT` also exposes an RGBA8 region-readback helper that uses the same
|
||||
backend framebuffer readback dispatch; canvas pick/history/snapshot and
|
||||
transform history paths now call that helper instead of binding an RTT and
|
||||
@@ -1005,12 +1009,14 @@ dispatch sequences used by retained recording readbacks now live in
|
||||
`pp_renderer_gl`. The framebuffer blit color mask and linear/nearest
|
||||
filter tokens used by `RTT::resize` and `RTT::copy`, renderer API blit-filter
|
||||
to OpenGL token mapping, plus the default
|
||||
render-target texture parameters, texture/renderbuffer targets, depth format,
|
||||
framebuffer targets, binding queries, attachment points, and completion status
|
||||
used by `RTT::create` and framebuffer bind/restore paths, also live in
|
||||
`pp_renderer_gl`. Depth renderbuffer allocation/storage/delete and framebuffer
|
||||
depth attach/detach sequences used by canvas object-drawing helpers now execute
|
||||
through tested `pp_renderer_gl` dispatch contracts. 2D framebuffer-to-texture
|
||||
render-target texture parameters and parameter dispatch, texture/renderbuffer
|
||||
targets, depth format, framebuffer targets, binding queries, attachment points,
|
||||
render-target framebuffer allocation/delete, binding restore, and completion
|
||||
status used by `RTT::create`/`RTT::destroy` and framebuffer bind/restore paths,
|
||||
also live in `pp_renderer_gl`. Depth renderbuffer allocation/storage/delete and
|
||||
framebuffer depth attach/detach sequences used by retained `RTT` and canvas
|
||||
object-drawing helpers now execute through tested `pp_renderer_gl` dispatch
|
||||
contracts. 2D framebuffer-to-texture
|
||||
copies used by canvas, transform, layer-conversion, panorama UI, and brush
|
||||
preview paths now route through a tested `pp_renderer_gl` copy dispatch via the
|
||||
retained `copy_framebuffer_to_texture_2d` utility bridge; the remaining cube-map
|
||||
|
||||
@@ -748,6 +748,33 @@ pp::foundation::Status update_opengl_texture_2d(
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Status set_opengl_texture_2d_parameters(
|
||||
std::uint32_t texture_id,
|
||||
std::span<const OpenGlTextureParameter> parameters,
|
||||
OpenGlTexture2DParameterDispatch dispatch) noexcept
|
||||
{
|
||||
if (dispatch.bind_texture == nullptr || dispatch.tex_parameter_f == nullptr) {
|
||||
return pp::foundation::Status::invalid_argument("OpenGL texture parameter dispatch callbacks must not be null");
|
||||
}
|
||||
|
||||
if (texture_id == 0U || parameters.empty()) {
|
||||
return pp::foundation::Status::invalid_argument("OpenGL texture parameter request is invalid");
|
||||
}
|
||||
|
||||
for (const auto parameter : parameters) {
|
||||
if (parameter.name == 0U) {
|
||||
return pp::foundation::Status::invalid_argument("OpenGL texture parameter name is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
dispatch.bind_texture(texture_2d_target(), texture_id);
|
||||
for (const auto parameter : parameters) {
|
||||
dispatch.tex_parameter_f(texture_2d_target(), parameter.name, static_cast<float>(parameter.value));
|
||||
}
|
||||
dispatch.bind_texture(texture_2d_target(), default_framebuffer_id());
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Status copy_opengl_framebuffer_to_texture_2d(
|
||||
OpenGlTexture2DFramebufferCopy copy,
|
||||
OpenGlTexture2DFramebufferCopyDispatch dispatch) noexcept
|
||||
@@ -969,6 +996,78 @@ pp::foundation::Status restore_opengl_framebuffer_binding(
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult> allocate_opengl_render_target_framebuffer(
|
||||
std::uint32_t texture_id,
|
||||
std::uint32_t depth_renderbuffer_id,
|
||||
OpenGlRenderTargetFramebufferAllocationDispatch dispatch) noexcept
|
||||
{
|
||||
if (dispatch.gen_framebuffers == nullptr
|
||||
|| dispatch.get_integer == nullptr
|
||||
|| dispatch.bind_framebuffer == nullptr
|
||||
|| dispatch.framebuffer_texture_2d == nullptr
|
||||
|| dispatch.framebuffer_renderbuffer == nullptr
|
||||
|| dispatch.check_framebuffer_status == nullptr) {
|
||||
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
|
||||
pp::foundation::Status::invalid_argument(
|
||||
"OpenGL render-target framebuffer allocation dispatch callbacks must not be null"));
|
||||
}
|
||||
|
||||
if (texture_id == 0U) {
|
||||
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
|
||||
pp::foundation::Status::invalid_argument("OpenGL render-target framebuffer texture id is invalid"));
|
||||
}
|
||||
|
||||
std::int32_t old_framebuffer = 0;
|
||||
dispatch.get_integer(draw_framebuffer_binding_query(), &old_framebuffer);
|
||||
|
||||
std::uint32_t framebuffer_id = 0U;
|
||||
dispatch.gen_framebuffers(1U, &framebuffer_id);
|
||||
if (framebuffer_id == 0U) {
|
||||
dispatch.bind_framebuffer(framebuffer_target(), static_cast<std::uint32_t>(old_framebuffer));
|
||||
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::failure(
|
||||
pp::foundation::Status::out_of_range("OpenGL render-target framebuffer allocation returned id 0"));
|
||||
}
|
||||
|
||||
dispatch.bind_framebuffer(framebuffer_target(), framebuffer_id);
|
||||
dispatch.framebuffer_texture_2d(
|
||||
framebuffer_target(),
|
||||
framebuffer_color_attachment(),
|
||||
texture_2d_target(),
|
||||
texture_id,
|
||||
0);
|
||||
if (depth_renderbuffer_id != 0U) {
|
||||
dispatch.framebuffer_renderbuffer(
|
||||
framebuffer_target(),
|
||||
framebuffer_depth_attachment(),
|
||||
renderbuffer_target(),
|
||||
depth_renderbuffer_id);
|
||||
}
|
||||
|
||||
const auto framebuffer_status = dispatch.check_framebuffer_status(framebuffer_target());
|
||||
dispatch.bind_framebuffer(framebuffer_target(), static_cast<std::uint32_t>(old_framebuffer));
|
||||
return pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult>::success(
|
||||
OpenGlRenderTargetFramebufferAllocationResult {
|
||||
.framebuffer_id = framebuffer_id,
|
||||
.framebuffer_status = framebuffer_status,
|
||||
});
|
||||
}
|
||||
|
||||
pp::foundation::Status delete_opengl_framebuffer(
|
||||
std::uint32_t framebuffer_id,
|
||||
OpenGlFramebufferDeleteDispatch dispatch) noexcept
|
||||
{
|
||||
if (dispatch.delete_framebuffers == nullptr) {
|
||||
return pp::foundation::Status::invalid_argument("OpenGL framebuffer delete dispatch callback must not be null");
|
||||
}
|
||||
|
||||
if (framebuffer_id == 0U) {
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
dispatch.delete_framebuffers(1U, &framebuffer_id);
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::uint32_t> allocate_opengl_pixel_buffer(
|
||||
OpenGlPixelBufferAllocationDispatch dispatch) noexcept
|
||||
{
|
||||
|
||||
@@ -172,6 +172,11 @@ struct OpenGlTexture2DReadbackResult {
|
||||
bool pixels_read = false;
|
||||
};
|
||||
|
||||
struct OpenGlRenderTargetFramebufferAllocationResult {
|
||||
std::uint32_t framebuffer_id = 0;
|
||||
std::uint32_t framebuffer_status = 0;
|
||||
};
|
||||
|
||||
struct OpenGlShaderCompileInfo {
|
||||
std::uint32_t shader_id = 0;
|
||||
std::int32_t compile_status = 0;
|
||||
@@ -442,6 +447,7 @@ using OpenGlTexSubImage2DFn = void (*)(
|
||||
std::uint32_t pixel_format,
|
||||
std::uint32_t component_type,
|
||||
const void* data) noexcept;
|
||||
using OpenGlTexParameterfFn = void (*)(std::uint32_t target, std::uint32_t parameter, float value) noexcept;
|
||||
using OpenGlCopyTexSubImage2DFn = void (*)(
|
||||
std::uint32_t target,
|
||||
std::int32_t level,
|
||||
@@ -607,6 +613,11 @@ struct OpenGlTexture2DUpdateDispatch {
|
||||
OpenGlTexSubImage2DFn tex_sub_image_2d = nullptr;
|
||||
};
|
||||
|
||||
struct OpenGlTexture2DParameterDispatch {
|
||||
OpenGlBindTextureFn bind_texture = nullptr;
|
||||
OpenGlTexParameterfFn tex_parameter_f = nullptr;
|
||||
};
|
||||
|
||||
struct OpenGlTexture2DFramebufferCopyDispatch {
|
||||
OpenGlCopyTexSubImage2DFn copy_tex_sub_image_2d = nullptr;
|
||||
};
|
||||
@@ -648,6 +659,19 @@ struct OpenGlFramebufferRestoreDispatch {
|
||||
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
|
||||
};
|
||||
|
||||
struct OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
OpenGlGenObjectsFn gen_framebuffers = nullptr;
|
||||
OpenGlGetIntegerFn get_integer = nullptr;
|
||||
OpenGlBindFramebufferFn bind_framebuffer = nullptr;
|
||||
OpenGlFramebufferTexture2DFn framebuffer_texture_2d = nullptr;
|
||||
OpenGlFramebufferRenderbufferFn framebuffer_renderbuffer = nullptr;
|
||||
OpenGlCheckFramebufferStatusFn check_framebuffer_status = nullptr;
|
||||
};
|
||||
|
||||
struct OpenGlFramebufferDeleteDispatch {
|
||||
OpenGlDeleteObjectsFn delete_framebuffers = nullptr;
|
||||
};
|
||||
|
||||
struct OpenGlPixelBufferAllocationDispatch {
|
||||
OpenGlGenObjectsFn gen_buffers = nullptr;
|
||||
};
|
||||
@@ -874,6 +898,10 @@ struct OpenGlMeshDeleteDispatch {
|
||||
[[nodiscard]] pp::foundation::Status update_opengl_texture_2d(
|
||||
OpenGlTexture2DUpdate update,
|
||||
OpenGlTexture2DUpdateDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status set_opengl_texture_2d_parameters(
|
||||
std::uint32_t texture_id,
|
||||
std::span<const OpenGlTextureParameter> parameters,
|
||||
OpenGlTexture2DParameterDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status copy_opengl_framebuffer_to_texture_2d(
|
||||
OpenGlTexture2DFramebufferCopy copy,
|
||||
OpenGlTexture2DFramebufferCopyDispatch dispatch) noexcept;
|
||||
@@ -895,6 +923,13 @@ struct OpenGlMeshDeleteDispatch {
|
||||
[[nodiscard]] pp::foundation::Status restore_opengl_framebuffer_binding(
|
||||
OpenGlFramebufferBindingState binding,
|
||||
OpenGlFramebufferRestoreDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult> allocate_opengl_render_target_framebuffer(
|
||||
std::uint32_t texture_id,
|
||||
std::uint32_t depth_renderbuffer_id,
|
||||
OpenGlRenderTargetFramebufferAllocationDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status delete_opengl_framebuffer(
|
||||
std::uint32_t framebuffer_id,
|
||||
OpenGlFramebufferDeleteDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_pixel_buffer(
|
||||
OpenGlPixelBufferAllocationDispatch dispatch) noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<std::uint32_t> readback_opengl_framebuffer_to_pixel_buffer(
|
||||
|
||||
266
src/rtt.cpp
266
src/rtt.cpp
@@ -34,6 +34,120 @@ void bind_opengl_framebuffer(std::uint32_t target, std::uint32_t framebuffer) no
|
||||
glBindFramebuffer(static_cast<GLenum>(target), static_cast<GLuint>(framebuffer));
|
||||
}
|
||||
|
||||
void gen_opengl_textures(std::uint32_t count, std::uint32_t* ids) noexcept
|
||||
{
|
||||
glGenTextures(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
|
||||
}
|
||||
|
||||
void delete_opengl_textures(std::uint32_t count, const std::uint32_t* ids) noexcept
|
||||
{
|
||||
glDeleteTextures(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
|
||||
}
|
||||
|
||||
void bind_opengl_texture(std::uint32_t target, std::uint32_t texture) noexcept
|
||||
{
|
||||
glBindTexture(static_cast<GLenum>(target), static_cast<GLuint>(texture));
|
||||
}
|
||||
|
||||
void set_opengl_texture_2d_image(
|
||||
std::uint32_t target,
|
||||
std::int32_t level,
|
||||
std::int32_t internal_format,
|
||||
std::int32_t width,
|
||||
std::int32_t height,
|
||||
std::int32_t border,
|
||||
std::uint32_t pixel_format,
|
||||
std::uint32_t component_type,
|
||||
const void* data) noexcept
|
||||
{
|
||||
glTexImage2D(
|
||||
static_cast<GLenum>(target),
|
||||
static_cast<GLint>(level),
|
||||
static_cast<GLint>(internal_format),
|
||||
static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height),
|
||||
static_cast<GLint>(border),
|
||||
static_cast<GLenum>(pixel_format),
|
||||
static_cast<GLenum>(component_type),
|
||||
data);
|
||||
}
|
||||
|
||||
void set_opengl_texture_parameter_f(std::uint32_t target, std::uint32_t parameter, float value) noexcept
|
||||
{
|
||||
glTexParameterf(static_cast<GLenum>(target), static_cast<GLenum>(parameter), static_cast<GLfloat>(value));
|
||||
}
|
||||
|
||||
void gen_opengl_renderbuffers(std::uint32_t count, std::uint32_t* ids) noexcept
|
||||
{
|
||||
glGenRenderbuffers(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
|
||||
}
|
||||
|
||||
void delete_opengl_renderbuffers(std::uint32_t count, const std::uint32_t* ids) noexcept
|
||||
{
|
||||
glDeleteRenderbuffers(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
|
||||
}
|
||||
|
||||
void bind_opengl_renderbuffer(std::uint32_t target, std::uint32_t renderbuffer) noexcept
|
||||
{
|
||||
glBindRenderbuffer(static_cast<GLenum>(target), static_cast<GLuint>(renderbuffer));
|
||||
}
|
||||
|
||||
void set_opengl_renderbuffer_storage(
|
||||
std::uint32_t target,
|
||||
std::uint32_t internal_format,
|
||||
std::int32_t width,
|
||||
std::int32_t height) noexcept
|
||||
{
|
||||
glRenderbufferStorage(
|
||||
static_cast<GLenum>(target),
|
||||
static_cast<GLenum>(internal_format),
|
||||
static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height));
|
||||
}
|
||||
|
||||
void gen_opengl_framebuffers(std::uint32_t count, std::uint32_t* ids) noexcept
|
||||
{
|
||||
glGenFramebuffers(static_cast<GLsizei>(count), reinterpret_cast<GLuint*>(ids));
|
||||
}
|
||||
|
||||
void delete_opengl_framebuffers(std::uint32_t count, const std::uint32_t* ids) noexcept
|
||||
{
|
||||
glDeleteFramebuffers(static_cast<GLsizei>(count), reinterpret_cast<const GLuint*>(ids));
|
||||
}
|
||||
|
||||
void attach_opengl_framebuffer_texture_2d(
|
||||
std::uint32_t target,
|
||||
std::uint32_t attachment,
|
||||
std::uint32_t texture_target,
|
||||
std::uint32_t texture,
|
||||
std::int32_t level) noexcept
|
||||
{
|
||||
glFramebufferTexture2D(
|
||||
static_cast<GLenum>(target),
|
||||
static_cast<GLenum>(attachment),
|
||||
static_cast<GLenum>(texture_target),
|
||||
static_cast<GLuint>(texture),
|
||||
static_cast<GLint>(level));
|
||||
}
|
||||
|
||||
void attach_opengl_framebuffer_renderbuffer(
|
||||
std::uint32_t target,
|
||||
std::uint32_t attachment,
|
||||
std::uint32_t renderbuffer_target,
|
||||
std::uint32_t renderbuffer) noexcept
|
||||
{
|
||||
glFramebufferRenderbuffer(
|
||||
static_cast<GLenum>(target),
|
||||
static_cast<GLenum>(attachment),
|
||||
static_cast<GLenum>(renderbuffer_target),
|
||||
static_cast<GLuint>(renderbuffer));
|
||||
}
|
||||
|
||||
std::uint32_t check_opengl_framebuffer_status(std::uint32_t target) noexcept
|
||||
{
|
||||
return static_cast<std::uint32_t>(glCheckFramebufferStatus(static_cast<GLenum>(target)));
|
||||
}
|
||||
|
||||
void blit_opengl_framebuffer(
|
||||
std::int32_t source_x0,
|
||||
std::int32_t source_y0,
|
||||
@@ -243,18 +357,36 @@ void RTT::destroy()
|
||||
{
|
||||
if (rboID)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
const auto status = pp::renderer::gl::delete_opengl_renderbuffer(
|
||||
static_cast<std::uint32_t>(rboID),
|
||||
pp::renderer::gl::OpenGlRenderbufferDeleteDispatch {
|
||||
.delete_renderbuffers = delete_opengl_renderbuffers,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("RTT::destroy renderbuffer delete failed because: %s", status.message);
|
||||
}
|
||||
if (texID)
|
||||
{
|
||||
//unbindTexture();
|
||||
glDeleteTextures(1, &texID);
|
||||
const auto status = pp::renderer::gl::delete_opengl_texture_2d(
|
||||
static_cast<std::uint32_t>(texID),
|
||||
pp::renderer::gl::OpenGlTexture2DDeleteDispatch {
|
||||
.delete_textures = delete_opengl_textures,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("RTT::destroy texture delete failed because: %s", status.message);
|
||||
//LOG("TEX rtt destroy %d", texID)
|
||||
}
|
||||
if (fboID)
|
||||
{
|
||||
//unbindFramebuffer();
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
const auto status = pp::renderer::gl::delete_opengl_framebuffer(
|
||||
static_cast<std::uint32_t>(fboID),
|
||||
pp::renderer::gl::OpenGlFramebufferDeleteDispatch {
|
||||
.delete_framebuffers = delete_opengl_framebuffers,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("RTT::destroy framebuffer delete failed because: %s", status.message);
|
||||
//LOG("RTT DESTROY %d", fboID);
|
||||
}
|
||||
});
|
||||
@@ -354,7 +486,7 @@ bool RTT::create(int width, int height, int tex)
|
||||
|
||||
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
|
||||
{
|
||||
GLenum status = 0;
|
||||
std::uint32_t status = 0;
|
||||
App::I->render_task([&]
|
||||
{
|
||||
// Destroy any previously created object
|
||||
@@ -366,7 +498,28 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
|
||||
|
||||
if (tex == -1)
|
||||
{
|
||||
glGenTextures(1, &texID);
|
||||
const auto texture = pp::renderer::gl::allocate_opengl_texture_2d(
|
||||
pp::renderer::gl::OpenGlTexture2DAllocation {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.internal_format = internal_format,
|
||||
.pixel_format = pp::renderer::gl::rgba_pixel_format(),
|
||||
.component_type = pp::renderer::gl::texture_upload_type_for_internal_format(
|
||||
static_cast<std::uint32_t>(internal_format)),
|
||||
.data = nullptr,
|
||||
},
|
||||
pp::renderer::gl::OpenGlTexture2DAllocationDispatch {
|
||||
.gen_textures = gen_opengl_textures,
|
||||
.bind_texture = bind_opengl_texture,
|
||||
.tex_image_2d = set_opengl_texture_2d_image,
|
||||
});
|
||||
if (!texture.ok())
|
||||
{
|
||||
LOG("RTT::create texture allocation failed because: %s", texture.status().message);
|
||||
status = 0;
|
||||
return;
|
||||
}
|
||||
texID = static_cast<GLuint>(texture.value());
|
||||
//LOG("TEX rtt create %d", texID);
|
||||
}
|
||||
else
|
||||
@@ -374,81 +527,72 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
|
||||
texID = tex;
|
||||
}
|
||||
|
||||
const auto ifmt = static_cast<GLenum>(
|
||||
pp::renderer::gl::texture_upload_type_for_internal_format(static_cast<std::uint32_t>(internal_format)));
|
||||
|
||||
glBindTexture(texture_2d_target(), texID);
|
||||
if (tex == -1)
|
||||
glTexImage2D(
|
||||
texture_2d_target(),
|
||||
0,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
static_cast<GLenum>(pp::renderer::gl::rgba_pixel_format()),
|
||||
ifmt,
|
||||
0);
|
||||
for (const auto parameter : pp::renderer::gl::default_render_target_texture_parameters())
|
||||
const auto parameter_status = pp::renderer::gl::set_opengl_texture_2d_parameters(
|
||||
static_cast<std::uint32_t>(texID),
|
||||
pp::renderer::gl::default_render_target_texture_parameters(),
|
||||
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
|
||||
.bind_texture = bind_opengl_texture,
|
||||
.tex_parameter_f = set_opengl_texture_parameter_f,
|
||||
});
|
||||
if (!parameter_status.ok())
|
||||
{
|
||||
glTexParameterf(
|
||||
texture_2d_target(),
|
||||
static_cast<GLenum>(parameter.name),
|
||||
static_cast<GLfloat>(parameter.value));
|
||||
LOG("RTT::create texture parameter setup failed because: %s", parameter_status.message);
|
||||
status = 0;
|
||||
return;
|
||||
}
|
||||
glBindTexture(texture_2d_target(), 0);
|
||||
|
||||
// Create a renderbuffer object to store depth info
|
||||
if (depth_buffer)
|
||||
{
|
||||
glGenRenderbuffers(1, &rboID);
|
||||
glBindRenderbuffer(renderbuffer_target(), rboID);
|
||||
glRenderbufferStorage(
|
||||
renderbuffer_target(),
|
||||
static_cast<GLenum>(pp::renderer::gl::depth_component24_format()),
|
||||
const auto renderbuffer = pp::renderer::gl::allocate_opengl_depth_renderbuffer(
|
||||
width,
|
||||
height);
|
||||
glBindRenderbuffer(renderbuffer_target(), 0);
|
||||
height,
|
||||
pp::renderer::gl::OpenGlDepthRenderbufferAllocationDispatch {
|
||||
.gen_renderbuffers = gen_opengl_renderbuffers,
|
||||
.bind_renderbuffer = bind_opengl_renderbuffer,
|
||||
.renderbuffer_storage = set_opengl_renderbuffer_storage,
|
||||
});
|
||||
if (!renderbuffer.ok())
|
||||
{
|
||||
LOG("RTT::create depth renderbuffer allocation failed because: %s", renderbuffer.status().message);
|
||||
status = 0;
|
||||
return;
|
||||
}
|
||||
rboID = static_cast<GLuint>(renderbuffer.value());
|
||||
}
|
||||
|
||||
GLint oldFboID;
|
||||
glGetIntegerv(static_cast<GLenum>(pp::renderer::gl::draw_framebuffer_binding_query()), &oldFboID);
|
||||
|
||||
// Create a framebuffer object
|
||||
glGenFramebuffers(1, &fboID);
|
||||
glBindFramebuffer(framebuffer_target(), fboID);
|
||||
const auto framebuffer = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
|
||||
static_cast<std::uint32_t>(texID),
|
||||
static_cast<std::uint32_t>(rboID),
|
||||
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
.gen_framebuffers = gen_opengl_framebuffers,
|
||||
.get_integer = query_opengl_integer,
|
||||
.bind_framebuffer = bind_opengl_framebuffer,
|
||||
.framebuffer_texture_2d = attach_opengl_framebuffer_texture_2d,
|
||||
.framebuffer_renderbuffer = attach_opengl_framebuffer_renderbuffer,
|
||||
.check_framebuffer_status = check_opengl_framebuffer_status,
|
||||
});
|
||||
if (!framebuffer.ok())
|
||||
{
|
||||
LOG("RTT::create framebuffer allocation failed because: %s", framebuffer.status().message);
|
||||
status = 0;
|
||||
return;
|
||||
}
|
||||
fboID = static_cast<GLuint>(framebuffer.value().framebuffer_id);
|
||||
status = framebuffer.value().framebuffer_status;
|
||||
//LOG("RTT CREATE %d - tex %d", fboID, texID);
|
||||
|
||||
// Attach the texture to FBO color attachment point
|
||||
glFramebufferTexture2D(
|
||||
framebuffer_target(),
|
||||
static_cast<GLenum>(pp::renderer::gl::framebuffer_color_attachment()),
|
||||
texture_2d_target(),
|
||||
texID,
|
||||
0);
|
||||
if (depth_buffer)
|
||||
{
|
||||
// Attach the renderbuffer to depth attachment point
|
||||
glFramebufferRenderbuffer(
|
||||
framebuffer_target(),
|
||||
static_cast<GLenum>(pp::renderer::gl::framebuffer_depth_attachment()),
|
||||
renderbuffer_target(),
|
||||
rboID);
|
||||
}
|
||||
|
||||
// Check FBO status
|
||||
status = glCheckFramebufferStatus(framebuffer_target());
|
||||
if (status != static_cast<GLenum>(pp::renderer::gl::framebuffer_complete_status()))
|
||||
if (status != pp::renderer::gl::framebuffer_complete_status())
|
||||
LOG("RTT::create failed because: %s",
|
||||
pp::renderer::gl::framebuffer_status_name(static_cast<std::uint32_t>(status)));
|
||||
pp::renderer::gl::framebuffer_status_name(status));
|
||||
|
||||
// Switch back to window-system-provided framebuffer
|
||||
glBindFramebuffer(framebuffer_target(), oldFboID);
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
});
|
||||
|
||||
return status == static_cast<GLenum>(pp::renderer::gl::framebuffer_complete_status());
|
||||
return status == pp::renderer::gl::framebuffer_complete_status();
|
||||
}
|
||||
|
||||
void RTT::bindFramebuffer()
|
||||
|
||||
@@ -55,6 +55,12 @@ struct RecordedOpenGlTextureImageCall {
|
||||
bool sub_image = false;
|
||||
};
|
||||
|
||||
struct RecordedOpenGlTextureParameterCall {
|
||||
std::uint32_t target = 0;
|
||||
std::uint32_t parameter = 0;
|
||||
float value = 0.0F;
|
||||
};
|
||||
|
||||
struct RecordedOpenGlFramebufferTextureCopyCall {
|
||||
std::uint32_t target = 0;
|
||||
std::int32_t level = 0;
|
||||
@@ -204,6 +210,7 @@ std::vector<RecordedOpenGlBindingCall> recorded_binding_calls;
|
||||
std::vector<std::uint32_t> recorded_generated_texture_counts;
|
||||
std::vector<std::uint32_t> recorded_deleted_textures;
|
||||
std::vector<RecordedOpenGlTextureImageCall> recorded_texture_image_calls;
|
||||
std::vector<RecordedOpenGlTextureParameterCall> recorded_texture_parameter_calls;
|
||||
std::vector<RecordedOpenGlFramebufferTextureCopyCall> recorded_framebuffer_texture_copy_calls;
|
||||
std::vector<std::uint32_t> recorded_mipmap_targets;
|
||||
std::vector<std::uint32_t> recorded_generated_framebuffer_counts;
|
||||
@@ -545,6 +552,15 @@ void record_tex_sub_image_2d(
|
||||
});
|
||||
}
|
||||
|
||||
void record_tex_parameter_f(std::uint32_t target, std::uint32_t parameter, float value) noexcept
|
||||
{
|
||||
recorded_texture_parameter_calls.push_back(RecordedOpenGlTextureParameterCall {
|
||||
.target = target,
|
||||
.parameter = parameter,
|
||||
.value = value,
|
||||
});
|
||||
}
|
||||
|
||||
void record_copy_tex_sub_image_2d(
|
||||
std::uint32_t target,
|
||||
std::int32_t level,
|
||||
@@ -2607,6 +2623,75 @@ void deletes_texture_objects_through_dispatch(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, recorded_deleted_textures[2] == 11U);
|
||||
}
|
||||
|
||||
void sets_texture_2d_parameters_through_dispatch(pp::tests::Harness& h)
|
||||
{
|
||||
recorded_binding_calls.clear();
|
||||
recorded_texture_parameter_calls.clear();
|
||||
|
||||
constexpr std::array parameters {
|
||||
pp::renderer::gl::OpenGlTextureParameter { .name = 0x2800U, .value = 0x2601U },
|
||||
pp::renderer::gl::OpenGlTextureParameter { .name = 0x2801U, .value = 0x2600U },
|
||||
};
|
||||
const auto status = pp::renderer::gl::set_opengl_texture_2d_parameters(
|
||||
37U,
|
||||
parameters,
|
||||
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
|
||||
.bind_texture = record_bind_texture,
|
||||
.tex_parameter_f = record_tex_parameter_f,
|
||||
});
|
||||
|
||||
PP_EXPECT(h, status.ok());
|
||||
PP_EXPECT(h, recorded_binding_calls.size() == 2U);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].kind == RecordedOpenGlBindingCall::Kind::bind_texture);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].first == 0x0DE1U);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].second == 37U);
|
||||
PP_EXPECT(h, recorded_binding_calls[1].second == 0U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls.size() == 2U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls[0].target == 0x0DE1U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls[0].parameter == 0x2800U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls[0].value == 0x2601U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls[1].parameter == 0x2801U);
|
||||
PP_EXPECT(h, recorded_texture_parameter_calls[1].value == 0x2600U);
|
||||
}
|
||||
|
||||
void rejects_invalid_texture_2d_parameter_dispatch(pp::tests::Harness& h)
|
||||
{
|
||||
constexpr std::array parameters {
|
||||
pp::renderer::gl::OpenGlTextureParameter { .name = 0x2800U, .value = 0x2601U },
|
||||
};
|
||||
constexpr std::array invalid_parameters {
|
||||
pp::renderer::gl::OpenGlTextureParameter { .name = 0U, .value = 0x2601U },
|
||||
};
|
||||
|
||||
const auto missing_dispatch = pp::renderer::gl::set_opengl_texture_2d_parameters(
|
||||
37U,
|
||||
parameters,
|
||||
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
|
||||
.bind_texture = record_bind_texture,
|
||||
});
|
||||
const auto invalid_texture = pp::renderer::gl::set_opengl_texture_2d_parameters(
|
||||
0U,
|
||||
parameters,
|
||||
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
|
||||
.bind_texture = record_bind_texture,
|
||||
.tex_parameter_f = record_tex_parameter_f,
|
||||
});
|
||||
const auto invalid_parameter = pp::renderer::gl::set_opengl_texture_2d_parameters(
|
||||
37U,
|
||||
invalid_parameters,
|
||||
pp::renderer::gl::OpenGlTexture2DParameterDispatch {
|
||||
.bind_texture = record_bind_texture,
|
||||
.tex_parameter_f = record_tex_parameter_f,
|
||||
});
|
||||
|
||||
PP_EXPECT(h, !missing_dispatch.ok());
|
||||
PP_EXPECT(h, missing_dispatch.code == pp::foundation::StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !invalid_texture.ok());
|
||||
PP_EXPECT(h, invalid_texture.code == pp::foundation::StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !invalid_parameter.ok());
|
||||
PP_EXPECT(h, invalid_parameter.code == pp::foundation::StatusCode::invalid_argument);
|
||||
}
|
||||
|
||||
void allocates_texture_cube_through_dispatch(pp::tests::Harness& h)
|
||||
{
|
||||
recorded_generated_texture_counts.clear();
|
||||
@@ -4433,6 +4518,121 @@ void rejects_incomplete_framebuffer_binding_dispatch(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, restore.code == pp::foundation::StatusCode::invalid_argument);
|
||||
}
|
||||
|
||||
void allocates_and_deletes_render_target_framebuffer(pp::tests::Harness& h)
|
||||
{
|
||||
recorded_integer_queries.clear();
|
||||
recorded_generated_framebuffer_counts.clear();
|
||||
recorded_binding_calls.clear();
|
||||
recorded_framebuffer_attachment_calls.clear();
|
||||
recorded_framebuffer_status_queries.clear();
|
||||
recorded_deleted_framebuffers.clear();
|
||||
configured_framebuffer_status = 0x8CD5U;
|
||||
next_framebuffer_id = 44U;
|
||||
|
||||
const auto framebuffer = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
|
||||
27U,
|
||||
81U,
|
||||
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
.gen_framebuffers = record_gen_framebuffers,
|
||||
.get_integer = record_get_integer,
|
||||
.bind_framebuffer = record_bind_framebuffer,
|
||||
.framebuffer_texture_2d = record_framebuffer_texture_2d,
|
||||
.framebuffer_renderbuffer = record_framebuffer_renderbuffer,
|
||||
.check_framebuffer_status = record_check_framebuffer_status,
|
||||
});
|
||||
const auto deleted = pp::renderer::gl::delete_opengl_framebuffer(
|
||||
framebuffer.ok() ? framebuffer.value().framebuffer_id : 0U,
|
||||
pp::renderer::gl::OpenGlFramebufferDeleteDispatch {
|
||||
.delete_framebuffers = record_delete_framebuffers,
|
||||
});
|
||||
|
||||
PP_EXPECT(h, framebuffer.ok());
|
||||
PP_EXPECT(h, framebuffer.value().framebuffer_id == 44U);
|
||||
PP_EXPECT(h, framebuffer.value().framebuffer_status == 0x8CD5U);
|
||||
PP_EXPECT(h, deleted.ok());
|
||||
PP_EXPECT(h, recorded_integer_queries.size() == 1U);
|
||||
PP_EXPECT(h, recorded_integer_queries[0] == 0x8CA6U);
|
||||
PP_EXPECT(h, recorded_generated_framebuffer_counts.size() == 1U);
|
||||
PP_EXPECT(h, recorded_generated_framebuffer_counts[0] == 1U);
|
||||
PP_EXPECT(h, recorded_binding_calls.size() == 2U);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].kind == RecordedOpenGlBindingCall::Kind::bind_framebuffer);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8D40U);
|
||||
PP_EXPECT(h, recorded_binding_calls[0].second == 44U);
|
||||
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8D40U);
|
||||
PP_EXPECT(h, recorded_binding_calls[1].second == 7U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls.size() == 2U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[0].target == 0x8D40U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[0].attachment == 0x8CE0U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[0].texture_target == 0x0DE1U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[0].texture == 27U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[1].attachment == 0x8D00U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[1].texture_target == 0x8D41U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[1].texture == 81U);
|
||||
PP_EXPECT(h, recorded_framebuffer_status_queries.size() == 1U);
|
||||
PP_EXPECT(h, recorded_framebuffer_status_queries[0] == 0x8D40U);
|
||||
PP_EXPECT(h, recorded_deleted_framebuffers.size() == 1U);
|
||||
PP_EXPECT(h, recorded_deleted_framebuffers[0] == 44U);
|
||||
}
|
||||
|
||||
void reports_incomplete_render_target_framebuffer(pp::tests::Harness& h)
|
||||
{
|
||||
recorded_framebuffer_attachment_calls.clear();
|
||||
configured_framebuffer_status = 0x8CD6U;
|
||||
next_framebuffer_id = 45U;
|
||||
|
||||
const auto framebuffer = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
|
||||
27U,
|
||||
0U,
|
||||
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
.gen_framebuffers = record_gen_framebuffers,
|
||||
.get_integer = record_get_integer,
|
||||
.bind_framebuffer = record_bind_framebuffer,
|
||||
.framebuffer_texture_2d = record_framebuffer_texture_2d,
|
||||
.framebuffer_renderbuffer = record_framebuffer_renderbuffer,
|
||||
.check_framebuffer_status = record_check_framebuffer_status,
|
||||
});
|
||||
|
||||
PP_EXPECT(h, framebuffer.ok());
|
||||
PP_EXPECT(h, framebuffer.value().framebuffer_id == 45U);
|
||||
PP_EXPECT(h, framebuffer.value().framebuffer_status == 0x8CD6U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls.size() == 1U);
|
||||
PP_EXPECT(h, recorded_framebuffer_attachment_calls[0].texture == 27U);
|
||||
configured_framebuffer_status = 0x8CD5U;
|
||||
}
|
||||
|
||||
void rejects_invalid_render_target_framebuffer_dispatch(pp::tests::Harness& h)
|
||||
{
|
||||
const auto missing_dispatch = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
|
||||
27U,
|
||||
0U,
|
||||
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
.gen_framebuffers = record_gen_framebuffers,
|
||||
.get_integer = record_get_integer,
|
||||
.bind_framebuffer = record_bind_framebuffer,
|
||||
});
|
||||
const auto invalid_texture = pp::renderer::gl::allocate_opengl_render_target_framebuffer(
|
||||
0U,
|
||||
0U,
|
||||
pp::renderer::gl::OpenGlRenderTargetFramebufferAllocationDispatch {
|
||||
.gen_framebuffers = record_gen_framebuffers,
|
||||
.get_integer = record_get_integer,
|
||||
.bind_framebuffer = record_bind_framebuffer,
|
||||
.framebuffer_texture_2d = record_framebuffer_texture_2d,
|
||||
.framebuffer_renderbuffer = record_framebuffer_renderbuffer,
|
||||
.check_framebuffer_status = record_check_framebuffer_status,
|
||||
});
|
||||
const auto missing_delete_dispatch = pp::renderer::gl::delete_opengl_framebuffer(
|
||||
44U,
|
||||
pp::renderer::gl::OpenGlFramebufferDeleteDispatch {});
|
||||
|
||||
PP_EXPECT(h, !missing_dispatch.ok());
|
||||
PP_EXPECT(h, missing_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !invalid_texture.ok());
|
||||
PP_EXPECT(h, invalid_texture.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !missing_delete_dispatch.ok());
|
||||
PP_EXPECT(h, missing_delete_dispatch.code == pp::foundation::StatusCode::invalid_argument);
|
||||
}
|
||||
|
||||
void allocates_attaches_and_deletes_depth_renderbuffer(pp::tests::Harness& h)
|
||||
{
|
||||
recorded_generated_renderbuffer_counts.clear();
|
||||
@@ -4942,6 +5142,8 @@ int main()
|
||||
harness.run("rejects_invalid_texture_2d_allocation", rejects_invalid_texture_2d_allocation);
|
||||
harness.run("deletes_and_binds_texture_2d_through_dispatch", deletes_and_binds_texture_2d_through_dispatch);
|
||||
harness.run("deletes_texture_objects_through_dispatch", deletes_texture_objects_through_dispatch);
|
||||
harness.run("sets_texture_2d_parameters_through_dispatch", sets_texture_2d_parameters_through_dispatch);
|
||||
harness.run("rejects_invalid_texture_2d_parameter_dispatch", rejects_invalid_texture_2d_parameter_dispatch);
|
||||
harness.run("allocates_texture_cube_through_dispatch", allocates_texture_cube_through_dispatch);
|
||||
harness.run("rejects_invalid_texture_cube_allocation", rejects_invalid_texture_cube_allocation);
|
||||
harness.run("binds_texture_cube_through_dispatch", binds_texture_cube_through_dispatch);
|
||||
@@ -4984,6 +5186,9 @@ int main()
|
||||
harness.run("binds_framebuffer_draw_read_through_dispatch", binds_framebuffer_draw_read_through_dispatch);
|
||||
harness.run("restores_framebuffer_draw_read_through_dispatch", restores_framebuffer_draw_read_through_dispatch);
|
||||
harness.run("rejects_incomplete_framebuffer_binding_dispatch", rejects_incomplete_framebuffer_binding_dispatch);
|
||||
harness.run("allocates_and_deletes_render_target_framebuffer", allocates_and_deletes_render_target_framebuffer);
|
||||
harness.run("reports_incomplete_render_target_framebuffer", reports_incomplete_render_target_framebuffer);
|
||||
harness.run("rejects_invalid_render_target_framebuffer_dispatch", rejects_invalid_render_target_framebuffer_dispatch);
|
||||
harness.run("allocates_attaches_and_deletes_depth_renderbuffer", allocates_attaches_and_deletes_depth_renderbuffer);
|
||||
harness.run("rejects_invalid_depth_renderbuffer_dispatch", rejects_invalid_depth_renderbuffer_dispatch);
|
||||
harness.run("maps_renderer_viewports_and_scissors", maps_renderer_viewports_and_scissors);
|
||||
|
||||
Reference in New Issue
Block a user