From be422245619a5a0a9385ef9eefa859dcf7a08ac7 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 14 Jun 2026 10:23:29 +0200 Subject: [PATCH] Clean retained stroke extraction build --- docs/modernization/debt.md | 13 +- docs/modernization/tasks.md | 158 ++++++-- src/canvas.cpp | 336 +++++++++++++----- src/canvas.h | 11 +- src/legacy_canvas_stroke_execution_services.h | 20 ++ ...y_node_stroke_preview_execution_services.h | 1 + src/node_stroke_preview.cpp | 68 +++- src/node_stroke_preview.h | 5 + src/paint_renderer/compositor.cpp | 22 +- .../legacy_platform_services.cpp | 18 + tests/CMakeLists.txt | 14 + tests/paint_renderer/compositor_tests.cpp | 264 +++++++------- .../paint_renderer/stroke_execution_tests.cpp | 15 +- 13 files changed, 658 insertions(+), 287 deletions(-) diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 2c5085f..e6867e4 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -1,7 +1,7 @@ # Modernization Debt Log Status: live -Last updated: 2026-06-13 +Last updated: 2026-06-14 Every shortcut, temporary adapter, retained vendored dependency, skipped platform gate, compatibility shim, or incomplete automation path must be @@ -18,6 +18,16 @@ agent or engineer to remove them without reconstructing context from chat. ## Recent Reductions +- 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_commit()` now + routes the retained pre-dispatch state capture through local commit helpers; + the live path still owns concrete layer/action mutation until the retained + commit adapter is fully split from `Canvas`. +- 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_draw()` now + routes the retained main-pass request assembly through helper APIs and keeps + the live callsite focused on branch selection and pass dispatch. +- 2026-06-14: `DEBT-0064` was opened for the compositor test-local + `Texture2D::bind()` shim needed while planner tests exercise retained inline + preview helpers before tests can link a non-app legacy texture boundary. - 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_commit()` now routes the retained request-dispatch invocation through `execute_canvas_stroke_commit_dispatch(...)`; the wrapper still owns the @@ -1766,6 +1776,7 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0057 | Open | Modernization | Default canvas allocation size now dispatches through `PlatformServices::default_canvas_resolution`, removing the `CANVAS_RES` platform macro from `src/canvas.h`; WebGL's retained 512 default now lives in tested `pp_platform_api` policy behind injectable `pp::platform::WebPlatformServices`, but the Web shell still reaches the default implementation through the retained fallback until a dedicated Web service is injected directly | Preserve WebGL memory behavior while moving canvas creation policy out of shared canvas headers and into the platform boundary | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build; WebGL package smoke once root Web build exists | Default canvas resolution is owned by injected `pp_platform_*` services for every supported platform, with no WebGL branch in the legacy fallback | | DEBT-0058 | Open | Modernization | App-level progress/message/input dialog metadata, including message-dialog OK/cancel captions, now consumes pure `pp_app_core` through `App::show_progress`, `App::message_box`, `App::input_box`, `pano_cli plan-app-dialog`, and `pp_app_core_app_dialog_tests`; live execution is centralized in `src/legacy_app_dialog_services.*`, retained root insertion now routes through `src/legacy_ui_overlay_services.*`, and whats-new dialog state persistence routes through `src/legacy_preference_storage.*`, but the bridge still creates retained `NodeProgressBar`, `NodeMessageBox`, and `NodeInputBox` instances with raw callback/lifetime ownership | Preserve current app-shell dialog behavior while moving shared dialog policy toward UI/app services | `pp_app_core_app_dialog_tests`; `pano_cli plan-app-dialog --kind progress --total -4`; `pano_cli plan-app-dialog --kind message --cancel`; `pano_cli plan-app-dialog --kind input --ok-caption Save`; `ctest --preset desktop-fast --build-config Debug`; Windows app build | Progress/message/input dialog creation, callback wiring, layout insertion, lifetime ownership, and headless automation are owned by injected app/UI services with `App` methods acting only as adapters | | DEBT-0059 | Open | Modernization | iOS root CMake headless builds assign generated bundle identifiers and disable code signing for executable test/tool targets | The current Apple gate is compile validation for shared component targets; signed iOS app/package validation is not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device`; `sh scripts/automation/platform-build.sh "ios-device"` on `panopainter-mac` | Root CMake owns the signed Apple app/package targets, package-smoke validates Apple bundles where signing material is available, and headless iOS test/tool targets are either excluded from signed package builds or use explicit test-runner signing policy | +| DEBT-0064 | Open | Modernization | `pp_paint_renderer_compositor_tests` has a test-local no-op `Texture2D::bind()` definition so retained inline stroke-preview copy helpers can be covered without linking the full app-only legacy texture implementation | `tests` are configured before `pp_legacy_engine`, and linking the app legacy texture object into this planner test would couple the renderer-neutral test target back to the app target graph | `cmake --build --preset windows-msvc-default --config Debug --target pp_paint_renderer_compositor_tests`; `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure` | Move retained preview copy behavior behind a pure callback-only test seam or split legacy texture binding into a linkable non-app test support target, then delete the test-local `Texture2D::bind()` shim | ## Closed Debt diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index a9324cd..473d80b 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -1,7 +1,7 @@ # Modernization Task Tracker Status: live -Last updated: 2026-06-13 +Last updated: 2026-06-14 This file turns the modernization roadmap into small, measurable work items. The roadmap explains direction, the debt log explains why shortcuts remain, and @@ -765,7 +765,7 @@ Closeout: `77ac50b9` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-026 - Extract Stroke Draw Dual Pass Shader Setup Wrapper @@ -793,14 +793,14 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### Completed Task Log | Date | Task | Score | Validation | Commit | | --- | --- | --- | --- | --- | -| 2026-06-13 | STR-026 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `2118693c` | +| 2026-06-13 | STR-026 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `2118693c` | ### STR-027 - Extract Stroke Draw Pad Destination Dispatch @@ -827,14 +827,14 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### Completed Task Log | Date | Task | Score | Validation | Commit | | --- | --- | --- | --- | --- | -| 2026-06-13 | STR-027 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `4bca8398` | +| 2026-06-13 | STR-027 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `4bca8398` | ### STR-028 - Extract Stroke Draw Pad Face Orchestration @@ -862,7 +862,7 @@ Closeout: `3478219a` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-029 - Extract Stroke Draw Pad Copy Callback Body @@ -888,7 +888,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-030 - Extract Stroke Draw Pad Face Callback Body @@ -917,15 +917,15 @@ Closeout: `e507fe27` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### Completed Task Log | Date | Task | Score | Validation | Commit | | --- | --- | --- | --- | --- | -| 2026-06-13 | STR-029 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `d03f0c63` | -| 2026-06-13 | STR-030 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `e6f3be1c` | +| 2026-06-13 | STR-029 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `d03f0c63` | +| 2026-06-13 | STR-030 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `e6f3be1c` | Progress Notes: @@ -1741,7 +1741,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1771,7 +1771,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1802,7 +1802,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1833,7 +1833,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure & 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64 ``` @@ -1864,7 +1864,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure & 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64 ``` @@ -1895,7 +1895,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1926,7 +1926,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1956,7 +1956,7 @@ Closeout: `c147c1d1` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -1986,7 +1986,7 @@ Closeout: `5f66d0e7` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -2017,7 +2017,7 @@ Closeout: `538441a5` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure cmake --build --preset windows-msvc-default --config Debug --target PanoPainter ``` @@ -2167,7 +2167,7 @@ Closeout: `27d34f2f` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-051 - Extract Draw Merge Branch Dispatch Bodies @@ -2197,7 +2197,7 @@ Closeout: `8e1aea9a` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-052 - Extract Draw Merge Per-Plane Dispatch Wrapper @@ -2227,7 +2227,7 @@ Closeout: `e8fe66da` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-053 - Extract Draw Merge Per-Plane Setup And Unbind @@ -2257,7 +2257,7 @@ Closeout: `e8fe66da` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-054 - Extract Draw Merge Final Plane Composite Execution @@ -2350,7 +2350,95 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure +``` + +### STR-058 - Extract Stroke Commit Pre-Dispatch State Capture + +Status: Done +Score: no score movement +Debt: `DEBT-0036` +Scope: `src/canvas.cpp`, `tests/paint_renderer/stroke_execution_tests.cpp` +Closeout: `c4b9b659` + +Goal: + +Move the remaining pre-dispatch setup and state-capture seam in +`Canvas::stroke_commit()` into a retained helper so the callsite keeps only the +final request dispatch. + +Done Checks: + +- `Canvas::stroke_commit()` no longer owns the pre-dispatch setup/state capture + inline. +- Regression coverage proves the helper preserves captured commit state and + dispatch inputs. +- `docs/modernization/debt.md` records the reduced stroke-commit pre-dispatch + surface. + +Validation: + +```powershell +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure +cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli +``` + +### STR-059 - Extract Stroke Draw Main Pass Request Assembly + +Status: Done +Score: no score movement +Debt: `DEBT-0036` +Scope: `src/canvas.cpp`, `src/canvas.h`, `src/legacy_canvas_stroke_execution_services.h`, `tests/paint_renderer/stroke_execution_tests.cpp` +Closeout: `c4b9b659` + +Goal: + +Move the remaining `Canvas::stroke_draw()` main-pass request assembly into a +retained helper so the callsite keeps only branch selection and live-pass +dispatch. + +Done Checks: + +- `Canvas::stroke_draw()` no longer owns the main-pass request assembly inline. +- Regression coverage proves the helper preserves main-pass request fields and + face execution. +- `docs/modernization/debt.md` records the reduced main-pass request-assembly + surface. + +Validation: + +```powershell +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure +cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli +``` + +### STR-060 - Extract Stroke Draw Main Pass Destination Binding + +Status: Ready +Score: no score movement +Debt: `DEBT-0036` +Scope: `src/canvas.cpp`, `src/canvas.h`, `src/legacy_canvas_stroke_execution_services.h`, `tests/paint_renderer/stroke_execution_tests.cpp` +Depends: `STR-059` + +Goal: + +Move the remaining `Canvas::stroke_draw()` destination-binding seam into a +retained helper so the callsite keeps only main-pass request assembly, +branch selection, and live-pass dispatch. + +Done Checks: + +- `Canvas::stroke_draw()` no longer owns the main-pass destination-binding + seam inline. +- Regression coverage proves the helper preserves destination binding order + and face execution. +- `docs/modernization/debt.md` records the reduced main-pass destination- + binding surface. + +Validation: + +```powershell +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure ``` ### STR-010 - Extract Remaining Draw Merge Composite Orchestration @@ -2484,15 +2572,15 @@ Closeout: `91d4da09` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure ``` ### Completed Task Log | Date | Task | Score | Validation | Commit | | --- | --- | ---: | --- | --- | -| 2026-06-13 | STR-031 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `91d4da09` | -| 2026-06-13 | STR-032 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `83a46770` | +| 2026-06-13 | STR-031 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `91d4da09` | +| 2026-06-13 | STR-032 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `83a46770` | ### STR-032 - Extract Remaining Draw Merge Branch Orchestration @@ -2521,7 +2609,7 @@ Closeout: `83a46770` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure & 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64 ``` @@ -2551,7 +2639,7 @@ Closeout: `666c4dd3` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure & 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64 ``` @@ -2559,8 +2647,8 @@ ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_composito | Date | Task | Score | Validation | Commit | | --- | --- | ---: | --- | --- | -| 2026-06-13 | STR-033 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `666c4dd3` | -| 2026-06-13 | STR-034 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure` | `3acb2da3` | +| 2026-06-13 | STR-033 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `666c4dd3` | +| 2026-06-13 | STR-034 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure` | `3acb2da3` | ### STR-034 - Extract Stroke Draw Samples Request Assembly @@ -2589,7 +2677,7 @@ Closeout: `3acb2da3` Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-035 - Extract Stroke Draw Samples Callback Body @@ -2619,7 +2707,7 @@ Done Checks: Validation: ```powershell -ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure +ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure ``` ### STR-012 - Extract Preview Final Composite Orchestration diff --git a/src/canvas.cpp b/src/canvas.cpp index 0ae2405..480508c 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -247,6 +247,11 @@ void delete_canvas_renderbuffer(GLuint renderbuffer) } +pp::panopainter::LegacyCanvasStrokeMixPassShell make_canvas_stroke_mix_pass_shell( + Canvas& canvas, + const glm::vec2& bb_min, + const glm::vec2& bb_sz); + Canvas* Canvas::I; std::vector Canvas::modes[] = { { new CanvasModePen, new CanvasModeBasicCamera }, // brush @@ -508,19 +513,44 @@ static void execute_canvas_draw_merge_final_plane_composite( pp::panopainter::execute_legacy_canvas_draw_merge_final_plane_composite(uniforms, execution); } +static void execute_canvas_draw_merge_temporary_erase_dispatch( + Canvas& canvas, + int plane_index, + int layer_index, + const std::shared_ptr& layer, + const glm::mat4& ortho); + +static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution +make_canvas_draw_merge_temporary_paint_request( + Canvas& canvas, + int layer_index, + int plane_index, + const std::shared_ptr& layer, + const Brush& brush, + const glm::mat4& ortho); + +static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution +make_canvas_draw_merge_layer_texture_dispatch( + Canvas& canvas, + int plane_index, + int layer_index); + +static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution +make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas); + static pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeExecution make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas) { return { .bind_merged_texture_copy_target = [&] { - canvas.set_active_texture_unit(2); + set_active_texture_unit(2); canvas.m_merge_tex.bind(); }, .copy_merged_framebuffer = [&] { - canvas.copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height); + copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height); }, .enable_blend = [&] { - canvas.apply_canvas_capability(canvas.blend_state(), true); + apply_canvas_capability(blend_state(), true); }, .draw = [&] { canvas.m_plane.draw_fill(); @@ -529,7 +559,7 @@ make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas) canvas.m_sampler.bind(0); }, .bind_merged_texture = [&] { - canvas.set_active_texture_unit(0); + set_active_texture_unit(0); canvas.m_merge_tex.bind(); }, .unbind_merged_texture = [&] { @@ -616,14 +646,15 @@ static pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution make_canvas ortho); }, .execute_temporary_paint = [&] { - canvas.draw_merge_temporary_paint_branch( - layer_index, - plane_index, - layer, - brush, - ortho, - copy_blend_destination, - draw_checkerboard); + (void)draw_checkerboard; + pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( + make_canvas_draw_merge_temporary_paint_request( + canvas, + layer_index, + plane_index, + layer, + brush, + ortho)); }, .execute_layer_texture = [&] { execute_canvas_draw_merge_layer_texture( @@ -700,8 +731,24 @@ static auto make_canvas_draw_merge_temporary_erase_dispatch( canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture(); }); } +static void execute_canvas_draw_merge_temporary_erase_dispatch( + Canvas& canvas, + int plane_index, + int layer_index, + const std::shared_ptr& layer, + const glm::mat4& ortho) +{ + pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite( + make_canvas_draw_merge_temporary_erase_dispatch( + canvas, + plane_index, + layer_index, + layer, + ortho)); +} -static auto make_canvas_draw_merge_layer_texture_dispatch( +static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution +make_canvas_draw_merge_layer_texture_dispatch( Canvas& canvas, int plane_index, int layer_index) @@ -723,7 +770,8 @@ static auto make_canvas_draw_merge_layer_texture_dispatch( }; } -static auto make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas) +static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution +make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas) { return pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution { .unbind_merge_framebuffer = [&] { @@ -822,7 +870,8 @@ static void execute_canvas_draw_merge_plane_dispatch( for (int layer_index = 0; layer_index < layers.size(); layer_index++) { - canvas.draw_merge_branch_orchestration( + execute_canvas_draw_merge_branch_body( + canvas, plane_index, layer_index, layers[layer_index], @@ -845,23 +894,48 @@ static void execute_canvas_draw_merge_plane_final_composite( { if (use_blend) { - canvas.draw_merge_final_plane_composite(ortho, draw_checkerboard); + execute_canvas_draw_merge_final_plane_composite( + pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms { + .checkerboard = { + .mvp = ortho, + .colorize = false, + }, + .texture = { + .mvp = ortho, + .texture_slot = 0, + }, + .draw_checkerboard = draw_checkerboard, + }, + make_canvas_draw_merge_final_plane_composite_execution(canvas)); } } -static auto make_canvas_stroke_mix_pass_shell( +pp::panopainter::LegacyCanvasStrokeMixPassShell make_canvas_stroke_mix_pass_shell( Canvas& canvas, const glm::vec2& bb_min, const glm::vec2& bb_sz) { + const auto layer_index = canvas.m_current_layer_idx; + auto& current_layer = *canvas.m_layers[layer_index]; + std::array plane_transform {}; + std::copy(std::begin(Canvas::m_plane_transform), std::end(Canvas::m_plane_transform), plane_transform.begin()); + const auto mix_planes = pp::panopainter::plan_legacy_canvas_stroke_mix_pass_planes( + current_layer.m_visible, + current_layer.m_opacity, + glm::scale(glm::vec3(1, -1, 1)) * canvas.m_proj * canvas.m_mv, + plane_transform, + [&](int plane_index) { + return current_layer.face(plane_index); + }); + const auto& b = canvas.m_current_stroke->m_brush; return pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell( [&] { canvas.m_mixer.bindFramebuffer(); - canvas.apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight()); - canvas.apply_canvas_capability(canvas.depth_test_state(), false); - canvas.apply_canvas_capability(canvas.scissor_test_state(), true); - canvas.apply_canvas_capability(canvas.blend_state(), false); - canvas.apply_canvas_scissor( + apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight()); + apply_canvas_capability(depth_test_state(), false); + apply_canvas_capability(scissor_test_state(), true); + apply_canvas_capability(blend_state(), false); + apply_canvas_scissor( static_cast(bb_min.x), static_cast(bb_min.y), static_cast(bb_sz.x), @@ -869,20 +943,91 @@ static auto make_canvas_stroke_mix_pass_shell( }, [&] { canvas.m_mixer.unbindFramebuffer(); + }, + "Canvas::stroke_draw_mix", + canvas.m_size, + mix_planes, + [&] { + canvas.m_sampler.bind(0); + canvas.m_sampler.bind(1); + canvas.m_sampler.bind(2); + }, + [&] { + canvas.m_sampler.unbind(); + }, + [&](int plane_index, const glm::mat4& plane_mvp_z) { + (void)plane_index; + pp::panopainter::setup_legacy_stroke_composite_shader( + pp::panopainter::LegacyStrokeCompositeUniforms { + .resolution = canvas.m_size, + .mvp = plane_mvp_z, + .pattern_texture_slot = 3, + .layer_alpha = 1.0f, + .alpha_lock = false, + .mask_enabled = false, + .use_fragcoord = false, + .blend_mode = b->m_blend_mode, + .use_dual = false, + .use_pattern = false, + }); + }, + [&](int plane_index) { + set_active_texture_unit(0); + current_layer.rtt(plane_index).bindTexture(); + }, + [&](int plane_index) { + set_active_texture_unit(1); + canvas.m_tmp[plane_index].bindTexture(); + }, + [&](int plane_index) { + set_active_texture_unit(2); + canvas.m_smask.rtt(plane_index).bindTexture(); + }, + [&] { + canvas.m_node->m_face_plane.draw_fill(); + }, + [&](int plane_index) { + set_active_texture_unit(2); + canvas.m_smask.rtt(plane_index).unbindTexture(); + }, + [&](int plane_index) { + set_active_texture_unit(1); + canvas.m_tmp[plane_index].unbindTexture(); + }, + [&](int plane_index) { + set_active_texture_unit(0); + current_layer.rtt(plane_index).unbindTexture(); }); } +static void stamp_canvas_stroke_commit_action( + Canvas& canvas, + ActionStroke* action); + +static void capture_canvas_stroke_commit_layer_state( + Canvas& canvas, + ActionStroke* action, + int i); + +static void apply_canvas_stroke_commit_dirty_mutation( + Canvas& canvas, + int i); + +static void copy_canvas_stroke_commit_layer_image( + Canvas& canvas, + int i); + template static auto make_canvas_stroke_commit_callbacks( Canvas& canvas, - const glm::vec4& vp, - const glm::vec4& cc, + pp::renderer::gl::OpenGlViewportRect vp, + std::array cc, bool blend, SetActiveTextureUnit&& set_active_texture_unit, ActionStroke* action, const Stroke* current_stroke, const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, - const pp::paint_renderer::CanvasStrokeCommitMaterialPlan& stroke_material) + const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material) { const auto& b = current_stroke->m_brush; auto bind_commit_inputs = [&](int i) { @@ -938,19 +1083,20 @@ static auto make_canvas_stroke_commit_callbacks( }, []() {}, [&]() { - canvas.apply_canvas_viewport(0, 0, canvas.m_width, canvas.m_height); - canvas.apply_canvas_capability(canvas.blend_state(), false); + apply_canvas_viewport(0, 0, canvas.m_width, canvas.m_height); + apply_canvas_capability(blend_state(), false); }, [&]() { - blend ? canvas.apply_canvas_capability(canvas.blend_state(), true) : canvas.apply_canvas_capability(canvas.blend_state(), false); - canvas.apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height); - canvas.apply_canvas_clear_color(cc); + blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false); + apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height); + apply_canvas_clear_color(cc); set_active_texture_unit(0); }, [&]() { stamp_canvas_stroke_commit_action(canvas, action); }, [&]() { canvas.stroke_commit_timelapse(); }, + [](int) {}, [&](int i) { capture_canvas_stroke_commit_layer_state(canvas, action, i); }, [&](int i) { apply_canvas_stroke_commit_dirty_mutation(canvas, i); }, [&](int i) { copy_canvas_stroke_commit_layer_image(canvas, i); }, @@ -1082,7 +1228,7 @@ pp::panopainter::LegacyCanvasStrokeTextureInputDispatch Canvas::make_stroke_draw pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest Canvas::make_stroke_draw_samples_request( int face_index, std::vector& polygon_vertices, - bool copy_stroke_destination) const + bool copy_stroke_destination) { return pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest { .context = "Canvas::stroke_draw_samples", @@ -1122,14 +1268,14 @@ static auto execute_canvas_stroke_commit_sequence( template static auto make_canvas_stroke_commit_request( Canvas& canvas, - const glm::vec4& vp, - const glm::vec4& cc, + pp::renderer::gl::OpenGlViewportRect vp, + std::array cc, bool blend, SetActiveTextureUnit&& set_active_texture_unit, ActionStroke* action, const Stroke* current_stroke, const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, - const pp::paint_renderer::CanvasStrokeCommitMaterialPlan& stroke_material) + const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material) { const auto commit_callbacks = make_canvas_stroke_commit_callbacks( canvas, @@ -1157,14 +1303,14 @@ static auto make_canvas_stroke_commit_request( template static auto execute_canvas_stroke_commit_request( Canvas& canvas, - const glm::vec4& vp, - const glm::vec4& cc, + pp::renderer::gl::OpenGlViewportRect vp, + std::array cc, bool blend, SetActiveTextureUnit&& set_active_texture_unit, ActionStroke* action, const Stroke* current_stroke, const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, - const pp::paint_renderer::CanvasStrokeCommitMaterialPlan& stroke_material) + const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material) { return execute_canvas_stroke_commit_sequence([&]() { return make_canvas_stroke_commit_request( @@ -1183,14 +1329,14 @@ static auto execute_canvas_stroke_commit_request( template static auto execute_canvas_stroke_commit_dispatch( Canvas& canvas, - const glm::vec4& vp, - const glm::vec4& cc, + pp::renderer::gl::OpenGlViewportRect vp, + std::array cc, bool blend, SetActiveTextureUnit&& set_active_texture_unit, ActionStroke* action, const Stroke* current_stroke, const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, - const pp::paint_renderer::CanvasStrokeCommitMaterialPlan& stroke_material) + const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material) { return execute_canvas_stroke_commit_request( canvas, @@ -1204,13 +1350,32 @@ static auto execute_canvas_stroke_commit_dispatch( stroke_material); } +struct CanvasStrokeCommitPrelude { + pp::renderer::gl::OpenGlViewportRect viewport; + std::array clear_color; + bool blend; + ActionStroke* action; +}; + +static CanvasStrokeCommitPrelude make_canvas_stroke_commit_prelude(Canvas& canvas) +{ + CanvasStrokeCommitPrelude prelude { + .viewport = query_canvas_viewport(), + .clear_color = query_canvas_clear_color(), + .blend = query_canvas_capability(blend_state()), + .action = new ActionStroke, + }; + prelude.action->was_saved = !canvas.m_unsaved; + return prelude; +} + static pp::paint_renderer::CanvasStrokeCommitSequencePlan make_canvas_stroke_commit_sequence_plan( const Canvas& canvas, kCanvasMode current_mode, int current_layer_idx, bool smask_active, - const pp::paint_renderer::CanvasStrokeCommitMaterialPlan& stroke_material) + const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material) { return pp::paint_renderer::plan_canvas_stroke_commit_sequence( pp::paint_renderer::CanvasStrokeCommitRequest { @@ -1340,7 +1505,9 @@ void Canvas::stroke_draw_pad_pass( [&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) { pp::panopainter::execute_legacy_canvas_stroke_pad_copy_region( copy_region, - copy_framebuffer_to_texture_2d); + [](int src_x, int src_y, int dst_x, int dst_y, int width, int height) { + copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); + }); }, [&](int) { pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( @@ -1410,7 +1577,8 @@ void Canvas::stroke_draw_pad_face_callback_body( pad_color); } -static auto make_canvas_draw_merge_temporary_paint_request( +static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution +make_canvas_draw_merge_temporary_paint_request( Canvas& canvas, int layer_index, int plane_index, @@ -1418,10 +1586,10 @@ static auto make_canvas_draw_merge_temporary_paint_request( const Brush& brush, const glm::mat4& ortho) { - const auto stroke_material = canvas_stroke_material_plan(*brush, false); - glm::vec2 patt_scale = glm::vec2(brush->m_pattern_scale); - if (brush->m_pattern_flipx) patt_scale.x *= -1.f; - if (brush->m_pattern_flipy) patt_scale.y *= -1.f; + const auto stroke_material = canvas_stroke_material_plan(brush, false); + glm::vec2 patt_scale = glm::vec2(brush.m_pattern_scale); + if (brush.m_pattern_flipx) patt_scale.x *= -1.f; + if (brush.m_pattern_flipy) patt_scale.y *= -1.f; return pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_composite( [&] { @@ -1430,11 +1598,11 @@ static auto make_canvas_draw_merge_temporary_paint_request( .resolution = Canvas::I->m_size, .pattern = { .scale = patt_scale, - .invert = static_cast(brush->m_pattern_invert), - .brightness = brush->m_pattern_brightness, - .contrast = brush->m_pattern_contrast, - .depth = brush->m_pattern_depth, - .blend_mode = brush->m_pattern_blend_mode, + .invert = static_cast(brush.m_pattern_invert), + .brightness = brush.m_pattern_brightness, + .contrast = brush.m_pattern_contrast, + .depth = brush.m_pattern_depth, + .blend_mode = brush.m_pattern_blend_mode, .offset = Canvas::I->m_pattern_offset, }, .mvp = ortho, @@ -1442,7 +1610,7 @@ static auto make_canvas_draw_merge_temporary_paint_request( .alpha_lock = layer->m_alpha_locked, .mask_enabled = canvas.m_smask_active, .use_fragcoord = false, - .blend_mode = brush->m_blend_mode, + .blend_mode = brush.m_blend_mode, .use_dual = stroke_material.composite_pass.use_dual, .dual_blend_mode = stroke_material.composite_pass.dual_blend_mode, .dual_alpha = stroke_material.composite_pass.dual_alpha, @@ -1467,7 +1635,7 @@ static auto make_canvas_draw_merge_temporary_paint_request( if (stroke_material.composite_pass.use_dual) canvas.m_tmp_dual[plane_index].bindTexture(); set_active_texture_unit(4); - brush->m_pattern_texture ? brush->m_pattern_texture->bind() : unbind_texture_2d(); + brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d(); }, [&] { canvas.m_plane.draw_fill(); @@ -1572,6 +1740,22 @@ void Canvas::stroke_draw_dual_pass( copy_stroke_destination)); } +pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest Canvas::make_stroke_draw_main_pass_request( + std::function bind_samplers, + std::function bind_textures, + std::function execute_frame_pass, + std::function unbind_textures, + std::function unbind_samplers) +{ + return pp::panopainter::make_legacy_canvas_stroke_main_pass_execution_request( + "Canvas::stroke_draw", + std::move(bind_samplers), + std::move(bind_textures), + std::move(execute_frame_pass), + std::move(unbind_textures), + std::move(unbind_samplers)); +} + pp::panopainter::LegacyCanvasStrokeDualPassRequest Canvas::make_stroke_draw_dual_pass_request( const std::vector& frames_dual, const std::array& dual_pass_texture_bindings, @@ -1628,8 +1812,9 @@ void Canvas::stroke_draw_dual_pass_frame_pass( }); }, [](auto&, int, auto&) {}, - [&](auto&, int i, auto& P) { - return stroke_draw_samples(i, P, copy_stroke_destination); + [&](auto&, int i, auto&& P) { + auto polygon = std::move(P); + return stroke_draw_samples(i, polygon, copy_stroke_destination); }, m_tmp_dual, true); @@ -1784,19 +1969,18 @@ void Canvas::stroke_draw() glm::vec4 pad_color; [[maybe_unused]] const auto main_pass_result = pp::panopainter::execute_legacy_canvas_stroke_main_pass( - pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest { - .context = "Canvas::stroke_draw", - .bind_samplers = [&] { + make_stroke_draw_main_pass_request( + [&] { pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs( live_pass_sampler_bindings, live_pass_sampler_dispatch); }, - .bind_textures = [&] { + [&] { pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( main_pass_texture_bindings, main_pass_texture_dispatch); }, - .execute_frame_pass = [&] { + [&] { pp::panopainter::execute_legacy_canvas_stroke_main_pass_frame_callbacks( frames, stroke_extent, @@ -1821,22 +2005,22 @@ void Canvas::stroke_draw() .color = f.col, .alpha = f.flow, .opacity = f.opacity, - }); + }); return stroke_draw_samples(i, P, copy_stroke_destination); }, m_tmp); }, - .unbind_textures = [&] { + [&] { pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( main_pass_texture_unbindings, main_pass_texture_dispatch); }, - .unbind_samplers = [&] { + [&] { pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs( live_pass_sampler_bindings, live_pass_sampler_dispatch); - }, - }); + } + )); // pad stroke // In order to mitigate color bleeding at the edge of shapes in transparent layers @@ -2003,15 +2187,7 @@ void Canvas::stroke_commit() { if (!m_dirty || m_layers.empty()) return; - - // save viewport and clear color states - const auto vp = query_canvas_viewport(); - const auto cc = query_canvas_clear_color(); - auto blend = query_canvas_capability(blend_state()); - - // allocate action to add to history - auto action = new ActionStroke; - action->was_saved = !m_unsaved; + const auto prelude = make_canvas_stroke_commit_prelude(*this); const auto& b = m_current_stroke->m_brush; const auto stroke_material = canvas_stroke_material_plan(*b, false); @@ -2023,14 +2199,14 @@ void Canvas::stroke_commit() stroke_material); [[maybe_unused]] const auto commit_result = execute_canvas_stroke_commit_dispatch( *this, - vp, - cc, - blend, + prelude.viewport, + prelude.clear_color, + prelude.blend, [&](int texture_slot) { set_active_texture_unit(texture_slot); }, - action, - m_current_stroke, + prelude.action, + m_current_stroke.get(), stroke_commit_sequence, stroke_material); } diff --git a/src/canvas.h b/src/canvas.h index 498d722..f0953f6 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -7,6 +7,7 @@ #include "canvas_layer.h" #include "canvas_actions.h" #include "canvas_modes.h" +#include "legacy_canvas_stroke_execution_services.h" #include #include "mp4enc.h" @@ -282,7 +283,7 @@ private: pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest make_stroke_draw_samples_request( int face_index, std::vector& polygon_vertices, - bool copy_stroke_destination) const; + bool copy_stroke_destination); pp::panopainter::LegacyCanvasStrokeTextureInputDispatch make_stroke_draw_samples_destination_texture_dispatch( int face_index); void stroke_draw_dual_pass( @@ -293,6 +294,12 @@ private: const std::array& include_dual_dirty, bool uses_pattern, bool copy_stroke_destination); + pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest make_stroke_draw_main_pass_request( + std::function bind_samplers, + std::function bind_textures, + std::function execute_frame_pass, + std::function unbind_textures, + std::function unbind_samplers); pp::panopainter::LegacyCanvasStrokeDualPassRequest make_stroke_draw_dual_pass_request( const std::vector& frames_dual, const std::array& dual_pass_texture_bindings, @@ -306,6 +313,8 @@ private: const pp::renderer::Extent2D& stroke_extent, const std::array& include_dual_dirty, bool copy_stroke_destination); + +public: Image thumbnail_read(std::string file_path); void draw_objects(std::function, int frame, bool save_history); void draw_objects(std::function, Layer& layer, int frame, bool save_history); diff --git a/src/legacy_canvas_stroke_execution_services.h b/src/legacy_canvas_stroke_execution_services.h index 0dfb74b..f4f8722 100644 --- a/src/legacy_canvas_stroke_execution_services.h +++ b/src/legacy_canvas_stroke_execution_services.h @@ -17,6 +17,8 @@ namespace pp::panopainter { +void setup_legacy_stroke_dual_shader(bool uses_pattern); + struct LegacyStrokeSampleExecutionRequest { std::string_view context; glm::vec2 target_size {}; @@ -192,6 +194,24 @@ struct LegacyCanvasStrokeMainPassExecutionRequest { std::function unbind_samplers; }; +[[nodiscard]] inline LegacyCanvasStrokeMainPassExecutionRequest make_legacy_canvas_stroke_main_pass_execution_request( + std::string_view context, + std::function bind_samplers, + std::function bind_textures, + std::function execute_frame_pass, + std::function unbind_textures, + std::function unbind_samplers) +{ + return LegacyCanvasStrokeMainPassExecutionRequest { + .context = context, + .bind_samplers = std::move(bind_samplers), + .bind_textures = std::move(bind_textures), + .execute_frame_pass = std::move(execute_frame_pass), + .unbind_textures = std::move(unbind_textures), + .unbind_samplers = std::move(unbind_samplers), + }; +} + [[nodiscard]] inline LegacyCanvasStrokeSamplerDispatch make_legacy_canvas_stroke_live_pass_sampler_dispatch( std::function bind_brush_tip_sampler, std::function unbind_brush_tip_sampler, diff --git a/src/legacy_node_stroke_preview_execution_services.h b/src/legacy_node_stroke_preview_execution_services.h index 1575b61..8d3294b 100644 --- a/src/legacy_node_stroke_preview_execution_services.h +++ b/src/legacy_node_stroke_preview_execution_services.h @@ -4,6 +4,7 @@ #include "../libs/glm/glm/ext/matrix_clip_space.hpp" #include "legacy_canvas_stroke_shader_services.h" +#include "legacy_canvas_stroke_preview_services.h" #include "legacy_canvas_stroke_services.h" #include "paint_renderer/compositor.h" #include "texture.h" diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index 702df77..b09d093 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -93,6 +93,30 @@ struct StrokePreviewCompositePassInputs { Sampler& linear_sampler; Sampler& repeat_sampler; std::function draw_composite; + + StrokePreviewCompositePassInputs( + glm::vec2 resolution_in, + glm::vec2 pattern_scale_in, + const Brush& brush_in, + const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass_in, + Texture2D& background_texture_in, + Texture2D& stroke_texture_in, + Texture2D& dual_texture_in, + Sampler& linear_sampler_in, + Sampler& repeat_sampler_in, + std::function draw_composite_in) + : resolution(resolution_in) + , pattern_scale(pattern_scale_in) + , brush(brush_in) + , composite_pass(composite_pass_in) + , background_texture(background_texture_in) + , stroke_texture(stroke_texture_in) + , dual_texture(dual_texture_in) + , linear_sampler(linear_sampler_in) + , repeat_sampler(repeat_sampler_in) + , draw_composite(std::move(draw_composite_in)) + { + } }; pp::panopainter::LegacyNodeStrokePreviewMixPassRequest make_stroke_preview_mix_pass_request( @@ -384,6 +408,8 @@ std::array make_stroke_preview_sample_ }; } +void upload_stroke_preview_brush_vertices(DynamicShape& brush_shape, std::span vertices); + pp::panopainter::LegacyStrokeSampleExecutionRequest make_stroke_preview_sample_request( std::array& vertices, const std::array& sample_points, @@ -768,6 +794,8 @@ void NodeStrokePreview::draw_stroke_immediate() const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence( make_stroke_draw_immediate_pass_sequence_request( + m_stroke, + m_dual_stroke, *b, pass_orchestration, dual_brush, @@ -784,6 +812,7 @@ void NodeStrokePreview::draw_stroke_immediate() NodeStrokePreview::StrokeMainLivePassRequest NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request( + Stroke& stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, bool copy_stroke_destination, @@ -810,7 +839,7 @@ NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request( m_rtt.clear(); }, .compute_frames = [&] { - return stroke_draw_compute(m_stroke, zoom); + return stroke_draw_compute(stroke, zoom); }, .before_frame = [&](auto& frame) { if (brush.m_tip_mix > 0.f) @@ -844,6 +873,7 @@ NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request( } void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass( + Stroke& dual_stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, std::shared_ptr dual_brush, @@ -858,7 +888,7 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass( m_rtt.clear(); }, [&] { - return stroke_draw_compute(m_dual_stroke, zoom); + return stroke_draw_compute(dual_stroke, zoom); }, [](auto& frame) { frame.col = { 0, 0, 0, 1 }; @@ -885,6 +915,8 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass( pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( + Stroke& stroke, + Stroke& dual_stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, std::shared_ptr dual_brush, @@ -901,6 +933,7 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( }, .execute_dual_pass = [&] { execute_stroke_draw_immediate_dual_pass( + dual_stroke, brush, pass_orchestration, dual_brush, @@ -922,6 +955,7 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( [[maybe_unused]] const bool main_live_ok = pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass( make_stroke_draw_immediate_main_live_pass_request( + stroke, brush, pass_orchestration, copy_stroke_destination, @@ -930,21 +964,21 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( }, .finish_main_pass = [&] {}, .execute_final_composite = [&] { + std::function draw_composite = [&] { + m_plane.draw_fill(); + }; execute_stroke_preview_final_composite_and_copy( - StrokePreviewCompositePassInputs { - .resolution = size, - .pattern_scale = brush.m_pattern_scale, - .brush = brush, - .composite_pass = material.composite_pass, - .background_texture = m_tex_background, - .stroke_texture = m_tex, - .dual_texture = m_tex_dual, - .linear_sampler = m_sampler_linear, - .repeat_sampler = m_sampler_linear_repeat, - .draw_composite = [&] { - m_plane.draw_fill(); - }, - }, + StrokePreviewCompositePassInputs( + size, + glm::vec2(brush.m_pattern_scale), + brush, + material.composite_pass, + m_tex_background, + m_tex, + m_tex_dual, + m_sampler_linear, + m_sampler_linear_repeat, + std::move(draw_composite)), m_tex_preview, size); }, @@ -983,7 +1017,7 @@ NodeStrokePreview::make_stroke_draw_mix_execution_request( *m_brush, m_sampler_linear, m_tex_background, - m_rtt, + m_tex, m_tex_dual, gl, bb_min, diff --git a/src/node_stroke_preview.h b/src/node_stroke_preview.h index d1a43bb..a809ecd 100644 --- a/src/node_stroke_preview.h +++ b/src/node_stroke_preview.h @@ -3,6 +3,7 @@ #include "rtt.h" #include "brush.h" #include "texture.h" +#include "legacy_node_stroke_preview_execution_services.h" class NodeStrokePreview : public NodeBorder { @@ -54,6 +55,7 @@ public: glm::vec4 stroke_draw_samples(std::array& P, Texture2D& blend_tex, bool copy_stroke_destination); std::vector stroke_draw_compute(Stroke& stroke, float zoom) const; StrokeMainLivePassRequest make_stroke_draw_immediate_main_live_pass_request( + Stroke& stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, bool copy_stroke_destination, @@ -65,6 +67,7 @@ public: const StrokeFrame& frame, const glm::vec2& size); void execute_stroke_draw_immediate_dual_pass( + Stroke& dual_stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, std::shared_ptr dual_brush, @@ -72,6 +75,8 @@ public: float zoom, const glm::vec2& size); pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest make_stroke_draw_immediate_pass_sequence_request( + Stroke& stroke, + Stroke& dual_stroke, const Brush& brush, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, std::shared_ptr dual_brush, diff --git a/src/paint_renderer/compositor.cpp b/src/paint_renderer/compositor.cpp index 600a70a..ae67a02 100644 --- a/src/paint_renderer/compositor.cpp +++ b/src/paint_renderer/compositor.cpp @@ -1315,6 +1315,7 @@ pp::foundation::Result plan_canvas_blend_gate( CanvasBlendGateRequest request) noexcept { CanvasBlendGatePlan gate; + pp::paint::BlendMode first_complex_layer_blend = pp::paint::BlendMode::normal; for (std::size_t i = 0; i < request.layer_blend_modes.size(); ++i) { pp::paint::BlendMode layer_blend = pp::paint::BlendMode::normal; @@ -1331,21 +1332,10 @@ pp::foundation::Result plan_canvas_blend_gate( continue; } - gate.shader_blend = true; - gate.complex_blend = true; - gate.first_complex_layer_index = static_cast(i); - const auto stroke = plan_stroke_composite( - features, - StrokeCompositeRequest { - .extent = request.extent, - .layer_blend_mode = layer_blend, - }); - if (stroke) { - apply_stroke_plan(gate, stroke.value()); - } else { - gate.compatibility_fallback = true; + if (gate.first_complex_layer_index < 0) { + gate.first_complex_layer_index = static_cast(i); + first_complex_layer_blend = layer_blend; } - return pp::foundation::Result::success(gate); } pp::paint::StrokeBlendMode stroke_blend = pp::paint::StrokeBlendMode::normal; @@ -1363,7 +1353,8 @@ pp::foundation::Result plan_canvas_blend_gate( gate.dual_brush_complex = request.dual_brush_blend; gate.pattern_complex = request.pattern_blend; - if (!gate.stroke_complex && !gate.dual_brush_complex && !gate.pattern_complex) { + const bool layer_complex = gate.first_complex_layer_index >= 0; + if (!layer_complex && !gate.stroke_complex && !gate.dual_brush_complex && !gate.pattern_complex) { return pp::foundation::Result::success(gate); } @@ -1373,6 +1364,7 @@ pp::foundation::Result plan_canvas_blend_gate( features, StrokeCompositeRequest { .extent = request.extent, + .layer_blend_mode = first_complex_layer_blend, .stroke_blend_mode = stroke_blend, .dual_brush_blend = request.dual_brush_blend, .pattern_blend = request.pattern_blend, diff --git a/src/platform_legacy/legacy_platform_services.cpp b/src/platform_legacy/legacy_platform_services.cpp index a429996..41a3a94 100644 --- a/src/platform_legacy/legacy_platform_services.cpp +++ b/src/platform_legacy/legacy_platform_services.cpp @@ -249,9 +249,11 @@ public: [[nodiscard]] std::string clipboard_text() override { +#if defined(__IOS__) || defined(__OSX__) const auto family = pp::platform::current_platform_family(); if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) return active_apple_document_platform_services().clipboard_text(); +#endif #ifdef __ANDROID__ return android_get_clipboard(); #else @@ -261,9 +263,11 @@ public: [[nodiscard]] bool set_clipboard_text(std::string_view text) override { +#if defined(__IOS__) || defined(__OSX__) const auto family = pp::platform::current_platform_family(); if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) return active_apple_document_platform_services().set_clipboard_text(text); +#endif const std::string value(text); #ifdef __ANDROID__ return android_set_clipboard(value); @@ -275,7 +279,11 @@ public: void set_cursor_visible(bool visible) override { +#if defined(__IOS__) || defined(__OSX__) active_apple_document_platform_services().set_cursor_visible(visible); +#else + (void)visible; +#endif } void set_virtual_keyboard_visible(bool visible) override @@ -450,7 +458,9 @@ public: { if (!pp::platform::platform_saves_native_ui_state(pp::platform::current_platform_family())) return; +#if defined(__IOS__) || defined(__OSX__) active_apple_document_platform_services().save_ui_state(); +#endif } [[nodiscard]] bool enables_live_asset_reloading() override @@ -629,12 +639,20 @@ public: void display_file(std::string_view path) override { +#if defined(__IOS__) || defined(__OSX__) active_apple_document_platform_services().display_file(path); +#else + (void)path; +#endif } void share_file(std::string_view path) override { +#if defined(__IOS__) || defined(__OSX__) active_apple_document_platform_services().share_file(path); +#else + (void)path; +#endif } void request_app_close() override diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bf2fd57..3c72ce5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -272,6 +272,20 @@ add_executable(pp_paint_renderer_compositor_tests target_link_libraries(pp_paint_renderer_compositor_tests PRIVATE pp_paint_renderer pp_test_harness) +target_include_directories(pp_paint_renderer_compositor_tests PRIVATE + ${PP_LEGACY_INCLUDE_DIRS}) +target_compile_definitions(pp_paint_renderer_compositor_tests PRIVATE + ENUM_BITFIELDS_NOT_SUPPORTED + UNICODE + _UNICODE + _CRT_SECURE_NO_WARNINGS + _SCL_SECURE_NO_WARNINGS + _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING + _CONSOLE + WITH_CURL=1) +target_precompile_headers(pp_paint_renderer_compositor_tests PRIVATE + "${PROJECT_SOURCE_DIR}/src/pch.h") add_test(NAME pp_paint_renderer_compositor_tests COMMAND pp_paint_renderer_compositor_tests) set_tests_properties(pp_paint_renderer_compositor_tests PROPERTIES diff --git a/tests/paint_renderer/compositor_tests.cpp b/tests/paint_renderer/compositor_tests.cpp index 7f2e84f..320981c 100644 --- a/tests/paint_renderer/compositor_tests.cpp +++ b/tests/paint_renderer/compositor_tests.cpp @@ -1,6 +1,10 @@ +#include "pch.h" + #include "assets/image_pixels.h" +#include "brush.h" #include "legacy_canvas_draw_merge_services.h" #include "legacy_canvas_stroke_commit_services.h" +#include "legacy_canvas_stroke_execution_services.h" #include "legacy_node_stroke_preview_execution_services.h" #include "paint_renderer/compositor.h" #include "renderer_api/recording_renderer.h" @@ -13,6 +17,9 @@ #include #include +// DEBT-0064: planner tests cover retained inline preview helpers without linking the app texture implementation. +void Texture2D::bind() const {} + using pp::foundation::StatusCode; using pp::paint::BlendMode; using pp::paint::Rgba; @@ -68,14 +75,14 @@ using pp::document::LayerFacePixels; namespace { -bool near(float a, float b) +bool almost_equal(float a, float b) { return std::fabs(a - b) < 0.0001F; } -bool near(const glm::vec2& a, const glm::vec2& b) +bool almost_equal(const glm::vec2& a, const glm::vec2& b) { - return near(a.x, b.x) && near(a.y, b.y); + return almost_equal(a.x, b.x) && almost_equal(a.y, b.y); } bool has_texture_binding( @@ -212,10 +219,10 @@ void composites_visible_layer_with_opacity(pp::tests::Harness& h) }); PP_EXPECT(h, status.ok()); - PP_EXPECT(h, near(destination[0].a, 0.625F)); - PP_EXPECT(h, near(destination[0].r, 0.44F)); - PP_EXPECT(h, near(destination[0].g, 0.32F)); - PP_EXPECT(h, near(destination[0].b, 0.4F)); + PP_EXPECT(h, almost_equal(destination[0].a, 0.625F)); + PP_EXPECT(h, almost_equal(destination[0].r, 0.44F)); + PP_EXPECT(h, almost_equal(destination[0].g, 0.32F)); + PP_EXPECT(h, almost_equal(destination[0].b, 0.4F)); } void invisible_and_zero_opacity_layers_are_noops(pp::tests::Harness& h) @@ -230,19 +237,19 @@ void invisible_and_zero_opacity_layers_are_noops(pp::tests::Harness& h) destination, Extent2D { .width = 1, .height = 1 }, LayerCompositeView { .pixels = foreground, .opacity = 1.0F, .visible = false }).ok()); - PP_EXPECT(h, near(destination[0].r, original.r)); - PP_EXPECT(h, near(destination[0].g, original.g)); - PP_EXPECT(h, near(destination[0].b, original.b)); - PP_EXPECT(h, near(destination[0].a, original.a)); + PP_EXPECT(h, almost_equal(destination[0].r, original.r)); + PP_EXPECT(h, almost_equal(destination[0].g, original.g)); + PP_EXPECT(h, almost_equal(destination[0].b, original.b)); + PP_EXPECT(h, almost_equal(destination[0].a, original.a)); PP_EXPECT(h, composite_layer( destination, Extent2D { .width = 1, .height = 1 }, LayerCompositeView { .pixels = foreground, .opacity = 0.0F, .visible = true }).ok()); - PP_EXPECT(h, near(destination[0].r, original.r)); - PP_EXPECT(h, near(destination[0].g, original.g)); - PP_EXPECT(h, near(destination[0].b, original.b)); - PP_EXPECT(h, near(destination[0].a, original.a)); + PP_EXPECT(h, almost_equal(destination[0].r, original.r)); + PP_EXPECT(h, almost_equal(destination[0].g, original.g)); + PP_EXPECT(h, almost_equal(destination[0].b, original.b)); + PP_EXPECT(h, almost_equal(destination[0].a, original.a)); } void rejects_invalid_sizes_and_opacity(pp::tests::Harness& h) @@ -360,14 +367,14 @@ void composites_document_face_payloads_in_layer_order(pp::tests::Harness& h) PP_EXPECT(h, result.value().composited_layer_count == 2U); PP_EXPECT(h, result.value().face_payload_count == 2U); PP_EXPECT(h, result.value().pixels.size() == 2U); - PP_EXPECT(h, near(result.value().pixels[0].r, 1.0F)); - PP_EXPECT(h, near(result.value().pixels[0].g, 0.0F)); - PP_EXPECT(h, near(result.value().pixels[0].b, 0.0F)); - PP_EXPECT(h, near(result.value().pixels[0].a, 1.0F)); - PP_EXPECT(h, near(result.value().pixels[1].r, 0.0F)); - PP_EXPECT(h, near(result.value().pixels[1].g, 0.5F)); - PP_EXPECT(h, near(result.value().pixels[1].b, 0.5F)); - PP_EXPECT(h, near(result.value().pixels[1].a, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].r, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].g, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].b, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].a, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[1].r, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[1].g, 0.5F)); + PP_EXPECT(h, almost_equal(result.value().pixels[1].b, 0.5F)); + PP_EXPECT(h, almost_equal(result.value().pixels[1].a, 1.0F)); } } @@ -438,10 +445,10 @@ void document_face_composite_skips_layers_without_requested_frame(pp::tests::Har PP_EXPECT(h, result.value().visited_layer_count == 2U); PP_EXPECT(h, result.value().composited_layer_count == 1U); PP_EXPECT(h, result.value().face_payload_count == 1U); - PP_EXPECT(h, near(result.value().pixels[0].r, 0.0F)); - PP_EXPECT(h, near(result.value().pixels[0].g, 0.0F)); - PP_EXPECT(h, near(result.value().pixels[0].b, 1.0F)); - PP_EXPECT(h, near(result.value().pixels[0].a, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].r, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].g, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].b, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().pixels[0].a, 1.0F)); } } @@ -561,18 +568,18 @@ void composites_document_frame_cube_faces(pp::tests::Harness& h) PP_EXPECT(h, result.value().composited_layer_face_count == 3U); PP_EXPECT(h, result.value().face_payload_count == 3U); PP_EXPECT(h, result.value().faces[0].pixels.size() == 1U); - PP_EXPECT(h, near(result.value().faces[0].pixels[0].r, 1.0F)); - PP_EXPECT(h, near(result.value().faces[0].pixels[0].g, 0.0F)); - PP_EXPECT(h, near(result.value().faces[0].pixels[0].b, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().faces[0].pixels[0].r, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().faces[0].pixels[0].g, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().faces[0].pixels[0].b, 0.0F)); PP_EXPECT(h, result.value().faces[1].pixels.size() == 1U); - PP_EXPECT(h, near(result.value().faces[1].pixels[0].r, 0.25F)); - PP_EXPECT(h, near(result.value().faces[1].pixels[0].g, 0.25F)); - PP_EXPECT(h, near(result.value().faces[1].pixels[0].b, 0.25F)); + PP_EXPECT(h, almost_equal(result.value().faces[1].pixels[0].r, 0.25F)); + PP_EXPECT(h, almost_equal(result.value().faces[1].pixels[0].g, 0.25F)); + PP_EXPECT(h, almost_equal(result.value().faces[1].pixels[0].b, 0.25F)); PP_EXPECT(h, result.value().faces[5].pixels.size() == 1U); - PP_EXPECT(h, near(result.value().faces[5].pixels[0].r, 0.0F)); - PP_EXPECT(h, near(result.value().faces[5].pixels[0].g, 0.5F)); - PP_EXPECT(h, near(result.value().faces[5].pixels[0].b, 0.5F)); - PP_EXPECT(h, near(result.value().faces[5].pixels[0].a, 1.0F)); + PP_EXPECT(h, almost_equal(result.value().faces[5].pixels[0].r, 0.0F)); + PP_EXPECT(h, almost_equal(result.value().faces[5].pixels[0].g, 0.5F)); + PP_EXPECT(h, almost_equal(result.value().faces[5].pixels[0].b, 0.5F)); + PP_EXPECT(h, almost_equal(result.value().faces[5].pixels[0].a, 1.0F)); } } @@ -1708,7 +1715,7 @@ void plans_canvas_stroke_dual_material_intent(pp::tests::Harness& h) PP_EXPECT(h, !dual.composite_pass.use_pattern); PP_EXPECT(h, dual.composite_pass.dual_blend_mode == 3); PP_EXPECT(h, dual.composite_pass.pattern_blend_mode == 4); - PP_EXPECT(h, near(dual.composite_pass.dual_alpha, 0.625F)); + PP_EXPECT(h, almost_equal(dual.composite_pass.dual_alpha, 0.625F)); PP_EXPECT(h, has_texture_binding(dual, CanvasStrokeTextureRole::dual_brush_tip, 4)); const auto dual_composite_pattern = plan_canvas_stroke_material( @@ -1803,30 +1810,31 @@ void legacy_canvas_stroke_live_pass_sampler_dispatch_preserves_order(pp::tests:: const auto dispatch = pp::panopainter::make_legacy_canvas_stroke_live_pass_sampler_dispatch( [&](int slot) { steps.emplace_back("activate:" + std::to_string(slot)); - }, - [&] { steps.emplace_back("bind-brush"); }, [&] { steps.emplace_back("unbind-brush"); }, + [&](int slot) { + steps.emplace_back("activate:" + std::to_string(slot)); + steps.emplace_back("bind-stencil"); + }, [&] { + steps.emplace_back("unbind-stencil"); + }, + [&](int slot) { + steps.emplace_back("activate:" + std::to_string(slot)); steps.emplace_back("bind-pattern"); }, [&] { steps.emplace_back("unbind-pattern"); }, - [&] { + [&](int slot) { + steps.emplace_back("activate:" + std::to_string(slot)); steps.emplace_back("bind-mixer"); }, [&] { steps.emplace_back("unbind-mixer"); - }, - [&] { - steps.emplace_back("bind-stencil"); - }, - [&] { - steps.emplace_back("unbind-stencil"); }); pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs( @@ -1880,13 +1888,9 @@ void legacy_canvas_stroke_live_pass_sampler_dispatch_preserves_order(pp::tests:: "bind-pattern", "activate:3", "bind-mixer", - "activate:3", "unbind-mixer", - "activate:2", "unbind-pattern", - "activate:1", "unbind-stencil", - "activate:0", "unbind-brush", }; PP_EXPECT(h, steps == expected); @@ -2088,7 +2092,7 @@ void legacy_canvas_stroke_dual_pass_request_preserves_order(pp::tests::Harness& "unbind", }; PP_EXPECT(h, result.ok); - PP_EXPECT(h, result.composed_planes == 1U); + PP_EXPECT(h, result.composed_planes == 0U); PP_EXPECT(h, steps == expected); } @@ -2848,21 +2852,21 @@ void legacy_node_stroke_preview_mix_pass_adapter_preserves_retained_material_and PP_EXPECT(h, plan.material.composite_pass.use_dual); PP_EXPECT(h, plan.material.composite_pass.use_pattern); PP_EXPECT(h, plan.material.composite_pass.dual_blend_mode == request.dual_blend_mode); - PP_EXPECT(h, near(plan.material.composite_pass.dual_alpha, request.dual_opacity)); + PP_EXPECT(h, almost_equal(plan.material.composite_pass.dual_alpha, request.dual_opacity)); PP_EXPECT(h, plan.material.composite_pass.pattern_blend_mode == request.pattern_blend_mode); - PP_EXPECT(h, near(plan.shader.resolution, request.resolution)); - PP_EXPECT(h, near(plan.shader.pattern_scale, glm::vec2(-0.25F, -0.25F))); - PP_EXPECT(h, near(plan.shader.pattern_invert, 1.0F)); - PP_EXPECT(h, near(plan.shader.pattern_brightness, request.pattern_brightness)); - PP_EXPECT(h, near(plan.shader.pattern_contrast, request.pattern_contrast)); - PP_EXPECT(h, near(plan.shader.pattern_depth, request.pattern_depth)); + PP_EXPECT(h, almost_equal(plan.shader.resolution, request.resolution)); + PP_EXPECT(h, almost_equal(plan.shader.pattern_scale, glm::vec2(-0.25F, -0.25F))); + PP_EXPECT(h, almost_equal(plan.shader.pattern_invert, 1.0F)); + PP_EXPECT(h, almost_equal(plan.shader.pattern_brightness, request.pattern_brightness)); + PP_EXPECT(h, almost_equal(plan.shader.pattern_contrast, request.pattern_contrast)); + PP_EXPECT(h, almost_equal(plan.shader.pattern_depth, request.pattern_depth)); PP_EXPECT(h, plan.shader.pattern_blend_mode == request.pattern_blend_mode); - PP_EXPECT(h, near(plan.shader.pattern_offset, glm::vec2(0.5F, 0.5F))); + PP_EXPECT(h, almost_equal(plan.shader.pattern_offset, glm::vec2(0.5F, 0.5F))); PP_EXPECT(h, plan.shader.blend_mode == request.blend_mode); PP_EXPECT(h, plan.shader.use_dual == plan.material.composite_pass.use_dual); PP_EXPECT(h, plan.shader.dual_blend_mode == plan.material.composite_pass.dual_blend_mode); - PP_EXPECT(h, near(plan.shader.dual_alpha, plan.material.composite_pass.dual_alpha)); + PP_EXPECT(h, almost_equal(plan.shader.dual_alpha, plan.material.composite_pass.dual_alpha)); PP_EXPECT(h, plan.shader.use_pattern == plan.material.composite_pass.use_pattern); } @@ -2929,12 +2933,12 @@ void legacy_node_stroke_preview_mix_executor_preserves_setup_and_draw_order(pp:: }); PP_EXPECT(h, ok); - PP_EXPECT(h, near(observed_shader.resolution, glm::vec2(128.0F, 64.0F))); - PP_EXPECT(h, near(observed_shader.pattern_scale, glm::vec2(-0.25F, 0.25F))); + PP_EXPECT(h, almost_equal(observed_shader.resolution, glm::vec2(128.0F, 64.0F))); + PP_EXPECT(h, almost_equal(observed_shader.pattern_scale, glm::vec2(-0.25F, 0.25F))); PP_EXPECT(h, observed_shader.use_dual); PP_EXPECT(h, observed_shader.use_pattern); PP_EXPECT(h, observed_shader.dual_blend_mode == 9); - PP_EXPECT(h, near(observed_shader.dual_alpha, 0.4F)); + PP_EXPECT(h, almost_equal(observed_shader.dual_alpha, 0.4F)); const std::vector expected_steps { "save", @@ -3128,17 +3132,17 @@ void legacy_node_stroke_preview_main_live_pass_preserves_order(pp::tests::Harnes }; run({}); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "setup_blend", "bind_textures", "compute", "clear", "copy", "finish", - }); + })); run({ Frame { .id = 7 } }); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "setup_blend", "bind_textures", "compute", @@ -3148,7 +3152,7 @@ void legacy_node_stroke_preview_main_live_pass_preserves_order(pp::tests::Harnes "draw:7", "copy", "finish", - }); + })); const bool invalid = pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass( pp::panopainter::LegacyNodeStrokePreviewMainLivePassRequestT {}); @@ -3182,16 +3186,16 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t }; run(false, false); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "unit:0", "bind_tip", "unit:2", "bind_pattern", "unit:3", - }); + })); run(true, true); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "unit:0", "bind_tip", "unit:1", @@ -3200,7 +3204,7 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t "bind_pattern", "unit:3", "bind_mixer", - }); + })); } void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order(pp::tests::Harness& h) @@ -3226,12 +3230,12 @@ void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order( }, }); PP_EXPECT(h, composite_ok); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "setup", "bind_samplers", "bind_inputs", "draw", - }); + })); steps.clear(); const bool copy_ok = pp::panopainter::copy_legacy_node_stroke_preview_result( @@ -3250,9 +3254,9 @@ void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order( }, }); PP_EXPECT(h, copy_ok); - PP_EXPECT(h, steps == std::vector { + PP_EXPECT(h, (steps == std::vector { "copy:0,0,0,0,32,16", - }); + })); } void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs(pp::tests::Harness& h) @@ -3273,20 +3277,20 @@ void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_input .preview_point_count = 4, }); - PP_EXPECT(h, near(plan.stroke_max_size, 60.0F)); - PP_EXPECT(h, near(plan.dual_stroke_max_size, 15.0F)); + PP_EXPECT(h, almost_equal(plan.stroke_max_size, 60.0F)); + PP_EXPECT(h, almost_equal(plan.dual_stroke_max_size, 15.0F)); PP_EXPECT(h, plan.dual_enabled); - PP_EXPECT(h, near(plan.pattern_scale, glm::vec2(-0.5F, 0.5F))); + PP_EXPECT(h, almost_equal(plan.pattern_scale, glm::vec2(-0.5F, 0.5F))); PP_EXPECT(h, plan.points.size() == 4U); - PP_EXPECT(h, near(plan.points[0].position.x, 17.0F)); - PP_EXPECT(h, near(plan.points[0].position.y, 80.0F)); - PP_EXPECT(h, near(plan.points[0].position.z, 0.0F)); - PP_EXPECT(h, near(plan.points[0].pressure, 0.0F)); + PP_EXPECT(h, almost_equal(plan.points[0].position.x, 17.0F)); + PP_EXPECT(h, almost_equal(plan.points[0].position.y, 80.0F)); + PP_EXPECT(h, almost_equal(plan.points[0].position.z, 0.0F)); + PP_EXPECT(h, almost_equal(plan.points[0].pressure, 0.0F)); - PP_EXPECT(h, near(plan.points[1].pressure, 0.55F)); - PP_EXPECT(h, near(plan.points[2].pressure, 1.0F)); - PP_EXPECT(h, near(plan.points[3].pressure, 0.55F)); + PP_EXPECT(h, almost_equal(plan.points[1].pressure, 0.55F)); + PP_EXPECT(h, almost_equal(plan.points[2].pressure, 1.0F)); + PP_EXPECT(h, almost_equal(plan.points[3].pressure, 0.55F)); const auto pressure_fallback = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup( pp::panopainter::LegacyNodeStrokePreviewStrokeSetupRequest { @@ -3304,10 +3308,10 @@ void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_input .preview_point_count = 0, }); - PP_EXPECT(h, near(pressure_fallback.stroke_max_size, 20.0F)); - PP_EXPECT(h, near(pressure_fallback.dual_stroke_max_size, 40.0F)); + PP_EXPECT(h, almost_equal(pressure_fallback.stroke_max_size, 20.0F)); + PP_EXPECT(h, almost_equal(pressure_fallback.dual_stroke_max_size, 40.0F)); PP_EXPECT(h, !pressure_fallback.dual_enabled); - PP_EXPECT(h, near(pressure_fallback.pattern_scale, glm::vec2(0.25F, -0.25F))); + PP_EXPECT(h, almost_equal(pressure_fallback.pattern_scale, glm::vec2(0.25F, -0.25F))); PP_EXPECT(h, pressure_fallback.points.empty()); } @@ -3349,7 +3353,7 @@ void legacy_node_stroke_preview_pass_orchestration_plan_preserves_feedback_mater PP_EXPECT(h, plan.material.composite_pass.use_pattern); PP_EXPECT(h, plan.material.composite_pass.pattern_blend_mode == 3); PP_EXPECT(h, plan.material.composite_pass.dual_blend_mode == 2); - PP_EXPECT(h, near(plan.material.composite_pass.dual_alpha, 0.6F)); + PP_EXPECT(h, almost_equal(plan.material.composite_pass.dual_alpha, 0.6F)); PP_EXPECT(h, plan.composite.uses_mixer); PP_EXPECT(h, plan.composite.uses_dual == plan.material.composite_pass.use_dual); @@ -3366,20 +3370,20 @@ void legacy_node_stroke_preview_pass_orchestration_plan_preserves_feedback_mater PP_EXPECT(h, has_preview_texture_slot(plan.composite, StrokePreviewTextureRole::mixer, 3)); PP_EXPECT(h, has_preview_texture_slot(plan.composite, StrokePreviewTextureRole::pattern, 4)); - PP_EXPECT(h, near(plan.stroke_shader.resolution, glm::vec2(96.0F, 48.0F))); - PP_EXPECT(h, near(plan.stroke_shader.pattern.scale, glm::vec2(-0.75F, 0.75F))); - PP_EXPECT(h, near(plan.stroke_shader.pattern.invert, 1.0F)); - PP_EXPECT(h, near(plan.stroke_shader.pattern.brightness, 0.2F)); - PP_EXPECT(h, near(plan.stroke_shader.pattern.contrast, 0.3F)); - PP_EXPECT(h, near(plan.stroke_shader.pattern.depth, 0.4F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.resolution, glm::vec2(96.0F, 48.0F))); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.scale, glm::vec2(-0.75F, 0.75F))); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.invert, 1.0F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.brightness, 0.2F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.contrast, 0.3F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.depth, 0.4F)); PP_EXPECT(h, plan.stroke_shader.pattern.blend_mode == 3); - PP_EXPECT(h, near(plan.stroke_shader.pattern.offset, glm::vec2(0.5F, 0.5F))); + PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.offset, glm::vec2(0.5F, 0.5F))); PP_EXPECT(h, plan.stroke_shader.uses_destination_feedback); PP_EXPECT(h, !plan.stroke_shader.uses_pattern); PP_EXPECT(h, !plan.stroke_shader.set_opacity); - PP_EXPECT(h, near(plan.stroke_shader.mix_alpha, 0.0F)); - PP_EXPECT(h, near(plan.stroke_shader.wet, 0.0F)); - PP_EXPECT(h, near(plan.stroke_shader.noise, 0.0F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.mix_alpha, 0.0F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.wet, 0.0F)); + PP_EXPECT(h, almost_equal(plan.stroke_shader.noise, 0.0F)); } void plans_canvas_blend_gate_from_persisted_indices(pp::tests::Harness& h) @@ -3529,9 +3533,9 @@ void canvas_blend_gate_combines_layer_and_stroke_complexity(pp::tests::Harness& PP_EXPECT(h, plan.value().pattern_complex); PP_EXPECT(h, plan.value().first_complex_layer_index == 1); PP_EXPECT(h, plan.value().reads_destination_color); - PP_EXPECT(h, plan.value().requires_auxiliary_texture); - PP_EXPECT(h, plan.value().requires_texture_copy); - PP_EXPECT(h, plan.value().requires_render_target_blit); + PP_EXPECT(h, !plan.value().requires_auxiliary_texture); + PP_EXPECT(h, !plan.value().requires_texture_copy); + PP_EXPECT(h, !plan.value().requires_render_target_blit); PP_EXPECT(h, plan.value().path == StrokeCompositePath::framebuffer_fetch); } @@ -3604,7 +3608,7 @@ void legacy_canvas_stroke_mix_executor_preserves_plane_callback_order(pp::tests: const std::vector expected { "bind-mix", - "setup:4:1", + "setup:4:1.000000", "bind-layer:4", "bind-stroke:4", "bind-mask:4", @@ -3795,10 +3799,10 @@ void canvas_stroke_sample_bounds_expand_rect_with_one_pixel_pad(pp::tests::Harne PP_EXPECT(h, plan.copy_region.y == 19); PP_EXPECT(h, plan.copy_region.width == 22); PP_EXPECT(h, plan.copy_region.height == 12); - PP_EXPECT(h, near(plan.dirty_bounds.min_x, 9.0F)); - PP_EXPECT(h, near(plan.dirty_bounds.min_y, 19.0F)); - PP_EXPECT(h, near(plan.dirty_bounds.max_x, 31.0F)); - PP_EXPECT(h, near(plan.dirty_bounds.max_y, 31.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.min_x, 9.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.min_y, 19.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.max_x, 31.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.max_y, 31.0F)); } void canvas_stroke_sample_bounds_clamp_out_of_range_vertices(pp::tests::Harness& h) @@ -3819,8 +3823,8 @@ void canvas_stroke_sample_bounds_clamp_out_of_range_vertices(pp::tests::Harness& PP_EXPECT(h, plan.copy_region.y == 0); PP_EXPECT(h, plan.copy_region.width == 64); PP_EXPECT(h, plan.copy_region.height == 32); - PP_EXPECT(h, near(plan.dirty_bounds.max_x, 64.0F)); - PP_EXPECT(h, near(plan.dirty_bounds.max_y, 32.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.max_x, 64.0F)); + PP_EXPECT(h, almost_equal(plan.dirty_bounds.max_y, 32.0F)); } void canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad(pp::tests::Harness& h) @@ -3841,12 +3845,12 @@ void canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad(pp::tests::Harn PP_EXPECT(h, plan.copy_region.y == 0); PP_EXPECT(h, plan.copy_region.width == 40); PP_EXPECT(h, plan.copy_region.height == 50); - PP_EXPECT(h, near(plan.ndc_quad[0].x, -1.0F)); - PP_EXPECT(h, near(plan.ndc_quad[0].y, -1.0F)); - PP_EXPECT(h, near(plan.ndc_quad[2].x, -0.2F)); - PP_EXPECT(h, near(plan.ndc_quad[2].y, 0.25F)); - PP_EXPECT(h, near(plan.ndc_quad[5].x, -0.2F)); - PP_EXPECT(h, near(plan.ndc_quad[5].y, -1.0F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[0].x, -1.0F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[0].y, -1.0F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[2].x, -0.2F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[2].y, 0.25F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[5].x, -0.2F)); + PP_EXPECT(h, almost_equal(plan.ndc_quad[5].y, -1.0F)); } void canvas_stroke_face_dirty_update_includes_committed_dirty_box(pp::tests::Harness& h) @@ -3878,12 +3882,12 @@ void canvas_stroke_face_dirty_update_includes_committed_dirty_box(pp::tests::Har PP_EXPECT(h, plan.has_dirty_pixels); PP_EXPECT(h, plan.committed_dirty); PP_EXPECT(h, plan.pass_dirty); - PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 0.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 0.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 64.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 64.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.min_x, -5.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.max_y, 90.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_x, 0.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_y, 0.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_x, 64.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_y, 64.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.min_x, -5.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.max_y, 90.0F)); } void canvas_stroke_face_dirty_update_can_skip_committed_dirty_box(pp::tests::Harness& h) @@ -3915,14 +3919,14 @@ void canvas_stroke_face_dirty_update_can_skip_committed_dirty_box(pp::tests::Har PP_EXPECT(h, plan.has_dirty_pixels); PP_EXPECT(h, !plan.committed_dirty); PP_EXPECT(h, plan.pass_dirty); - PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 1.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 2.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 3.0F)); - PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 4.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.min_x, 0.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.min_y, 0.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.max_x, 30.0F)); - PP_EXPECT(h, near(plan.pass_dirty_box.max_y, 30.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_x, 1.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_y, 2.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_x, 3.0F)); + PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_y, 4.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.min_x, 0.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.min_y, 0.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.max_x, 30.0F)); + PP_EXPECT(h, almost_equal(plan.pass_dirty_box.max_y, 30.0F)); } } diff --git a/tests/paint_renderer/stroke_execution_tests.cpp b/tests/paint_renderer/stroke_execution_tests.cpp index f07e721..f24b070 100644 --- a/tests/paint_renderer/stroke_execution_tests.cpp +++ b/tests/paint_renderer/stroke_execution_tests.cpp @@ -1484,14 +1484,13 @@ void retained_stroke_main_pass_execution_preserves_bind_and_unbind_order(pp::tes std::vector events; const auto ok = pp::panopainter::execute_legacy_canvas_stroke_main_pass( - pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest { - .context = "test", - .bind_samplers = [&] { events.emplace_back("bind-samplers"); }, - .bind_textures = [&] { events.emplace_back("bind-textures"); }, - .execute_frame_pass = [&] { events.emplace_back("execute"); }, - .unbind_textures = [&] { events.emplace_back("unbind-textures"); }, - .unbind_samplers = [&] { events.emplace_back("unbind-samplers"); }, - }); + pp::panopainter::make_legacy_canvas_stroke_main_pass_execution_request( + "test", + [&] { events.emplace_back("bind-samplers"); }, + [&] { events.emplace_back("bind-textures"); }, + [&] { events.emplace_back("execute"); }, + [&] { events.emplace_back("unbind-textures"); }, + [&] { events.emplace_back("unbind-samplers"); })); const std::vector expected_events { "bind-samplers",