Clean retained stroke extraction build

This commit is contained in:
2026-06-14 10:23:29 +02:00
parent 8f02e39058
commit be42224561
13 changed files with 658 additions and 287 deletions

View File

@@ -1,7 +1,7 @@
# Modernization Debt Log # Modernization Debt Log
Status: live Status: live
Last updated: 2026-06-13 Last updated: 2026-06-14
Every shortcut, temporary adapter, retained vendored dependency, skipped Every shortcut, temporary adapter, retained vendored dependency, skipped
platform gate, compatibility shim, or incomplete automation path must be 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 ## 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 - 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_commit()` now
routes the retained request-dispatch invocation through routes the retained request-dispatch invocation through
`execute_canvas_stroke_commit_dispatch(...)`; the wrapper still owns the `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-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-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-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 ## Closed Debt

View File

@@ -1,7 +1,7 @@
# Modernization Task Tracker # Modernization Task Tracker
Status: live Status: live
Last updated: 2026-06-13 Last updated: 2026-06-14
This file turns the modernization roadmap into small, measurable work items. This file turns the modernization roadmap into small, measurable work items.
The roadmap explains direction, the debt log explains why shortcuts remain, and The roadmap explains direction, the debt log explains why shortcuts remain, and
@@ -765,7 +765,7 @@ Closeout: `77ac50b9`
Validation: Validation:
```powershell ```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 ### STR-026 - Extract Stroke Draw Dual Pass Shader Setup Wrapper
@@ -793,14 +793,14 @@ Done Checks:
Validation: Validation:
```powershell ```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 ### Completed Task Log
| Date | Task | Score | Validation | Commit | | 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 ### STR-027 - Extract Stroke Draw Pad Destination Dispatch
@@ -827,14 +827,14 @@ Done Checks:
Validation: Validation:
```powershell ```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 ### Completed Task Log
| Date | Task | Score | Validation | Commit | | 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 ### STR-028 - Extract Stroke Draw Pad Face Orchestration
@@ -862,7 +862,7 @@ Closeout: `3478219a`
Validation: Validation:
```powershell ```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 ### STR-029 - Extract Stroke Draw Pad Copy Callback Body
@@ -888,7 +888,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 ### STR-030 - Extract Stroke Draw Pad Face Callback Body
@@ -917,15 +917,15 @@ Closeout: `e507fe27`
Validation: Validation:
```powershell ```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 ### Completed Task Log
| Date | Task | Score | Validation | Commit | | 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-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-onfailure` | `e6f3be1c` | | 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: Progress Notes:
@@ -1741,7 +1741,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1771,7 +1771,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1802,7 +1802,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1833,7 +1833,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 & '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: Validation:
```powershell ```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 & '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: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1926,7 +1926,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1956,7 +1956,7 @@ Closeout: `c147c1d1`
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -1986,7 +1986,7 @@ Closeout: `5f66d0e7`
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -2017,7 +2017,7 @@ Closeout: `538441a5`
Validation: Validation:
```powershell ```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 cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
``` ```
@@ -2167,7 +2167,7 @@ Closeout: `27d34f2f`
Validation: Validation:
```powershell ```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 ### STR-051 - Extract Draw Merge Branch Dispatch Bodies
@@ -2197,7 +2197,7 @@ Closeout: `8e1aea9a`
Validation: Validation:
```powershell ```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 ### STR-052 - Extract Draw Merge Per-Plane Dispatch Wrapper
@@ -2227,7 +2227,7 @@ Closeout: `e8fe66da`
Validation: Validation:
```powershell ```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 ### STR-053 - Extract Draw Merge Per-Plane Setup And Unbind
@@ -2257,7 +2257,7 @@ Closeout: `e8fe66da`
Validation: Validation:
```powershell ```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 ### STR-054 - Extract Draw Merge Final Plane Composite Execution
@@ -2350,7 +2350,95 @@ Done Checks:
Validation: Validation:
```powershell ```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 ### STR-010 - Extract Remaining Draw Merge Composite Orchestration
@@ -2484,15 +2572,15 @@ Closeout: `91d4da09`
Validation: Validation:
```powershell ```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 ### Completed Task Log
| Date | Task | Score | Validation | Commit | | 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-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-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-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 ### STR-032 - Extract Remaining Draw Merge Branch Orchestration
@@ -2521,7 +2609,7 @@ Closeout: `83a46770`
Validation: Validation:
```powershell ```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 & '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: Validation:
```powershell ```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 & '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 | | 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-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-onfailure` | `3acb2da3` | | 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 ### STR-034 - Extract Stroke Draw Samples Request Assembly
@@ -2589,7 +2677,7 @@ Closeout: `3acb2da3`
Validation: Validation:
```powershell ```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 ### STR-035 - Extract Stroke Draw Samples Callback Body
@@ -2619,7 +2707,7 @@ Done Checks:
Validation: Validation:
```powershell ```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 ### STR-012 - Extract Preview Final Composite Orchestration

View File

@@ -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; Canvas* Canvas::I;
std::vector<CanvasMode*> Canvas::modes[] = { std::vector<CanvasMode*> Canvas::modes[] = {
{ new CanvasModePen, new CanvasModeBasicCamera }, // brush { 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); 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>& 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>& 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 static pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeExecution
make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas) make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas)
{ {
return { return {
.bind_merged_texture_copy_target = [&] { .bind_merged_texture_copy_target = [&] {
canvas.set_active_texture_unit(2); set_active_texture_unit(2);
canvas.m_merge_tex.bind(); canvas.m_merge_tex.bind();
}, },
.copy_merged_framebuffer = [&] { .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 = [&] { .enable_blend = [&] {
canvas.apply_canvas_capability(canvas.blend_state(), true); apply_canvas_capability(blend_state(), true);
}, },
.draw = [&] { .draw = [&] {
canvas.m_plane.draw_fill(); canvas.m_plane.draw_fill();
@@ -529,7 +559,7 @@ make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas)
canvas.m_sampler.bind(0); canvas.m_sampler.bind(0);
}, },
.bind_merged_texture = [&] { .bind_merged_texture = [&] {
canvas.set_active_texture_unit(0); set_active_texture_unit(0);
canvas.m_merge_tex.bind(); canvas.m_merge_tex.bind();
}, },
.unbind_merged_texture = [&] { .unbind_merged_texture = [&] {
@@ -616,14 +646,15 @@ static pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution make_canvas
ortho); ortho);
}, },
.execute_temporary_paint = [&] { .execute_temporary_paint = [&] {
canvas.draw_merge_temporary_paint_branch( (void)draw_checkerboard;
layer_index, pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
plane_index, make_canvas_draw_merge_temporary_paint_request(
layer, canvas,
brush, layer_index,
ortho, plane_index,
copy_blend_destination, layer,
draw_checkerboard); brush,
ortho));
}, },
.execute_layer_texture = [&] { .execute_layer_texture = [&] {
execute_canvas_draw_merge_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(); 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>& 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, Canvas& canvas,
int plane_index, int plane_index,
int layer_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 { return pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution {
.unbind_merge_framebuffer = [&] { .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++) 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, plane_index,
layer_index, layer_index,
layers[layer_index], layers[layer_index],
@@ -845,23 +894,48 @@ static void execute_canvas_draw_merge_plane_final_composite(
{ {
if (use_blend) 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, Canvas& canvas,
const glm::vec2& bb_min, const glm::vec2& bb_min,
const glm::vec2& bb_sz) const glm::vec2& bb_sz)
{ {
const auto layer_index = canvas.m_current_layer_idx;
auto& current_layer = *canvas.m_layers[layer_index];
std::array<glm::mat4, 6> 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( return pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell(
[&] { [&] {
canvas.m_mixer.bindFramebuffer(); canvas.m_mixer.bindFramebuffer();
canvas.apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight()); apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight());
canvas.apply_canvas_capability(canvas.depth_test_state(), false); apply_canvas_capability(depth_test_state(), false);
canvas.apply_canvas_capability(canvas.scissor_test_state(), true); apply_canvas_capability(scissor_test_state(), true);
canvas.apply_canvas_capability(canvas.blend_state(), false); apply_canvas_capability(blend_state(), false);
canvas.apply_canvas_scissor( apply_canvas_scissor(
static_cast<std::int32_t>(bb_min.x), static_cast<std::int32_t>(bb_min.x),
static_cast<std::int32_t>(bb_min.y), static_cast<std::int32_t>(bb_min.y),
static_cast<std::int32_t>(bb_sz.x), static_cast<std::int32_t>(bb_sz.x),
@@ -869,20 +943,91 @@ static auto make_canvas_stroke_mix_pass_shell(
}, },
[&] { [&] {
canvas.m_mixer.unbindFramebuffer(); 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 <typename SetActiveTextureUnit> template <typename SetActiveTextureUnit>
static auto make_canvas_stroke_commit_callbacks( static auto make_canvas_stroke_commit_callbacks(
Canvas& canvas, Canvas& canvas,
const glm::vec4& vp, pp::renderer::gl::OpenGlViewportRect vp,
const glm::vec4& cc, std::array<float, 4> cc,
bool blend, bool blend,
SetActiveTextureUnit&& set_active_texture_unit, SetActiveTextureUnit&& set_active_texture_unit,
ActionStroke* action, ActionStroke* action,
const Stroke* current_stroke, const Stroke* current_stroke,
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, 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; const auto& b = current_stroke->m_brush;
auto bind_commit_inputs = [&](int i) { 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); apply_canvas_viewport(0, 0, canvas.m_width, canvas.m_height);
canvas.apply_canvas_capability(canvas.blend_state(), false); apply_canvas_capability(blend_state(), false);
}, },
[&]() { [&]() {
blend ? canvas.apply_canvas_capability(canvas.blend_state(), true) : canvas.apply_canvas_capability(canvas.blend_state(), false); blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
canvas.apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height); apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
canvas.apply_canvas_clear_color(cc); apply_canvas_clear_color(cc);
set_active_texture_unit(0); set_active_texture_unit(0);
}, },
[&]() { stamp_canvas_stroke_commit_action(canvas, action); }, [&]() { stamp_canvas_stroke_commit_action(canvas, action); },
[&]() { [&]() {
canvas.stroke_commit_timelapse(); canvas.stroke_commit_timelapse();
}, },
[](int) {},
[&](int i) { capture_canvas_stroke_commit_layer_state(canvas, action, i); }, [&](int i) { capture_canvas_stroke_commit_layer_state(canvas, action, i); },
[&](int i) { apply_canvas_stroke_commit_dirty_mutation(canvas, i); }, [&](int i) { apply_canvas_stroke_commit_dirty_mutation(canvas, i); },
[&](int i) { copy_canvas_stroke_commit_layer_image(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( pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest Canvas::make_stroke_draw_samples_request(
int face_index, int face_index,
std::vector<vertex_t>& polygon_vertices, std::vector<vertex_t>& polygon_vertices,
bool copy_stroke_destination) const bool copy_stroke_destination)
{ {
return pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest { return pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest {
.context = "Canvas::stroke_draw_samples", .context = "Canvas::stroke_draw_samples",
@@ -1122,14 +1268,14 @@ static auto execute_canvas_stroke_commit_sequence(
template <typename SetActiveTextureUnit> template <typename SetActiveTextureUnit>
static auto make_canvas_stroke_commit_request( static auto make_canvas_stroke_commit_request(
Canvas& canvas, Canvas& canvas,
const glm::vec4& vp, pp::renderer::gl::OpenGlViewportRect vp,
const glm::vec4& cc, std::array<float, 4> cc,
bool blend, bool blend,
SetActiveTextureUnit&& set_active_texture_unit, SetActiveTextureUnit&& set_active_texture_unit,
ActionStroke* action, ActionStroke* action,
const Stroke* current_stroke, const Stroke* current_stroke,
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, 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( const auto commit_callbacks = make_canvas_stroke_commit_callbacks(
canvas, canvas,
@@ -1157,14 +1303,14 @@ static auto make_canvas_stroke_commit_request(
template <typename SetActiveTextureUnit> template <typename SetActiveTextureUnit>
static auto execute_canvas_stroke_commit_request( static auto execute_canvas_stroke_commit_request(
Canvas& canvas, Canvas& canvas,
const glm::vec4& vp, pp::renderer::gl::OpenGlViewportRect vp,
const glm::vec4& cc, std::array<float, 4> cc,
bool blend, bool blend,
SetActiveTextureUnit&& set_active_texture_unit, SetActiveTextureUnit&& set_active_texture_unit,
ActionStroke* action, ActionStroke* action,
const Stroke* current_stroke, const Stroke* current_stroke,
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, 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 execute_canvas_stroke_commit_sequence([&]() {
return make_canvas_stroke_commit_request( return make_canvas_stroke_commit_request(
@@ -1183,14 +1329,14 @@ static auto execute_canvas_stroke_commit_request(
template <typename SetActiveTextureUnit> template <typename SetActiveTextureUnit>
static auto execute_canvas_stroke_commit_dispatch( static auto execute_canvas_stroke_commit_dispatch(
Canvas& canvas, Canvas& canvas,
const glm::vec4& vp, pp::renderer::gl::OpenGlViewportRect vp,
const glm::vec4& cc, std::array<float, 4> cc,
bool blend, bool blend,
SetActiveTextureUnit&& set_active_texture_unit, SetActiveTextureUnit&& set_active_texture_unit,
ActionStroke* action, ActionStroke* action,
const Stroke* current_stroke, const Stroke* current_stroke,
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence, 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( return execute_canvas_stroke_commit_request(
canvas, canvas,
@@ -1204,13 +1350,32 @@ static auto execute_canvas_stroke_commit_dispatch(
stroke_material); stroke_material);
} }
struct CanvasStrokeCommitPrelude {
pp::renderer::gl::OpenGlViewportRect viewport;
std::array<float, 4> 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 static pp::paint_renderer::CanvasStrokeCommitSequencePlan
make_canvas_stroke_commit_sequence_plan( make_canvas_stroke_commit_sequence_plan(
const Canvas& canvas, const Canvas& canvas,
kCanvasMode current_mode, kCanvasMode current_mode,
int current_layer_idx, int current_layer_idx,
bool smask_active, 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( return pp::paint_renderer::plan_canvas_stroke_commit_sequence(
pp::paint_renderer::CanvasStrokeCommitRequest { pp::paint_renderer::CanvasStrokeCommitRequest {
@@ -1340,7 +1505,9 @@ void Canvas::stroke_draw_pad_pass(
[&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) { [&](const pp::paint_renderer::CanvasStrokeCopyRegion& copy_region) {
pp::panopainter::execute_legacy_canvas_stroke_pad_copy_region( pp::panopainter::execute_legacy_canvas_stroke_pad_copy_region(
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) { [&](int) {
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
@@ -1410,7 +1577,8 @@ void Canvas::stroke_draw_pad_face_callback_body(
pad_color); pad_color);
} }
static auto make_canvas_draw_merge_temporary_paint_request( static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
make_canvas_draw_merge_temporary_paint_request(
Canvas& canvas, Canvas& canvas,
int layer_index, int layer_index,
int plane_index, int plane_index,
@@ -1418,10 +1586,10 @@ static auto make_canvas_draw_merge_temporary_paint_request(
const Brush& brush, const Brush& brush,
const glm::mat4& ortho) const glm::mat4& ortho)
{ {
const auto stroke_material = canvas_stroke_material_plan(*brush, false); const auto stroke_material = canvas_stroke_material_plan(brush, false);
glm::vec2 patt_scale = glm::vec2(brush->m_pattern_scale); glm::vec2 patt_scale = glm::vec2(brush.m_pattern_scale);
if (brush->m_pattern_flipx) patt_scale.x *= -1.f; if (brush.m_pattern_flipx) patt_scale.x *= -1.f;
if (brush->m_pattern_flipy) patt_scale.y *= -1.f; if (brush.m_pattern_flipy) patt_scale.y *= -1.f;
return pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_composite( 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, .resolution = Canvas::I->m_size,
.pattern = { .pattern = {
.scale = patt_scale, .scale = patt_scale,
.invert = static_cast<float>(brush->m_pattern_invert), .invert = static_cast<float>(brush.m_pattern_invert),
.brightness = brush->m_pattern_brightness, .brightness = brush.m_pattern_brightness,
.contrast = brush->m_pattern_contrast, .contrast = brush.m_pattern_contrast,
.depth = brush->m_pattern_depth, .depth = brush.m_pattern_depth,
.blend_mode = brush->m_pattern_blend_mode, .blend_mode = brush.m_pattern_blend_mode,
.offset = Canvas::I->m_pattern_offset, .offset = Canvas::I->m_pattern_offset,
}, },
.mvp = ortho, .mvp = ortho,
@@ -1442,7 +1610,7 @@ static auto make_canvas_draw_merge_temporary_paint_request(
.alpha_lock = layer->m_alpha_locked, .alpha_lock = layer->m_alpha_locked,
.mask_enabled = canvas.m_smask_active, .mask_enabled = canvas.m_smask_active,
.use_fragcoord = false, .use_fragcoord = false,
.blend_mode = brush->m_blend_mode, .blend_mode = brush.m_blend_mode,
.use_dual = stroke_material.composite_pass.use_dual, .use_dual = stroke_material.composite_pass.use_dual,
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode, .dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
.dual_alpha = stroke_material.composite_pass.dual_alpha, .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) if (stroke_material.composite_pass.use_dual)
canvas.m_tmp_dual[plane_index].bindTexture(); canvas.m_tmp_dual[plane_index].bindTexture();
set_active_texture_unit(4); 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(); canvas.m_plane.draw_fill();
@@ -1572,6 +1740,22 @@ void Canvas::stroke_draw_dual_pass(
copy_stroke_destination)); copy_stroke_destination));
} }
pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest Canvas::make_stroke_draw_main_pass_request(
std::function<void()> bind_samplers,
std::function<void()> bind_textures,
std::function<void()> execute_frame_pass,
std::function<void()> unbind_textures,
std::function<void()> 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( pp::panopainter::LegacyCanvasStrokeDualPassRequest Canvas::make_stroke_draw_dual_pass_request(
const std::vector<StrokeFrame>& frames_dual, const std::vector<StrokeFrame>& frames_dual,
const std::array<pp::panopainter::LegacyCanvasStrokeTextureBinding, 1>& dual_pass_texture_bindings, const std::array<pp::panopainter::LegacyCanvasStrokeTextureBinding, 1>& dual_pass_texture_bindings,
@@ -1628,8 +1812,9 @@ void Canvas::stroke_draw_dual_pass_frame_pass(
}); });
}, },
[](auto&, int, auto&) {}, [](auto&, int, auto&) {},
[&](auto&, int i, auto& P) { [&](auto&, int i, auto&& P) {
return stroke_draw_samples(i, P, copy_stroke_destination); auto polygon = std::move(P);
return stroke_draw_samples(i, polygon, copy_stroke_destination);
}, },
m_tmp_dual, m_tmp_dual,
true); true);
@@ -1784,19 +1969,18 @@ void Canvas::stroke_draw()
glm::vec4 pad_color; glm::vec4 pad_color;
[[maybe_unused]] const auto main_pass_result = [[maybe_unused]] const auto main_pass_result =
pp::panopainter::execute_legacy_canvas_stroke_main_pass( pp::panopainter::execute_legacy_canvas_stroke_main_pass(
pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest { make_stroke_draw_main_pass_request(
.context = "Canvas::stroke_draw", [&] {
.bind_samplers = [&] {
pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs( pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs(
live_pass_sampler_bindings, live_pass_sampler_bindings,
live_pass_sampler_dispatch); live_pass_sampler_dispatch);
}, },
.bind_textures = [&] { [&] {
pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( pp::panopainter::bind_legacy_canvas_stroke_texture_inputs(
main_pass_texture_bindings, main_pass_texture_bindings,
main_pass_texture_dispatch); main_pass_texture_dispatch);
}, },
.execute_frame_pass = [&] { [&] {
pp::panopainter::execute_legacy_canvas_stroke_main_pass_frame_callbacks( pp::panopainter::execute_legacy_canvas_stroke_main_pass_frame_callbacks(
frames, frames,
stroke_extent, stroke_extent,
@@ -1821,22 +2005,22 @@ void Canvas::stroke_draw()
.color = f.col, .color = f.col,
.alpha = f.flow, .alpha = f.flow,
.opacity = f.opacity, .opacity = f.opacity,
}); });
return stroke_draw_samples(i, P, copy_stroke_destination); return stroke_draw_samples(i, P, copy_stroke_destination);
}, },
m_tmp); m_tmp);
}, },
.unbind_textures = [&] { [&] {
pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs(
main_pass_texture_unbindings, main_pass_texture_unbindings,
main_pass_texture_dispatch); main_pass_texture_dispatch);
}, },
.unbind_samplers = [&] { [&] {
pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs( pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs(
live_pass_sampler_bindings, live_pass_sampler_bindings,
live_pass_sampler_dispatch); live_pass_sampler_dispatch);
}, }
}); ));
// pad stroke // pad stroke
// In order to mitigate color bleeding at the edge of shapes in transparent layers // 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()) if (!m_dirty || m_layers.empty())
return; return;
const auto prelude = make_canvas_stroke_commit_prelude(*this);
// 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& b = m_current_stroke->m_brush; const auto& b = m_current_stroke->m_brush;
const auto stroke_material = canvas_stroke_material_plan(*b, false); const auto stroke_material = canvas_stroke_material_plan(*b, false);
@@ -2023,14 +2199,14 @@ void Canvas::stroke_commit()
stroke_material); stroke_material);
[[maybe_unused]] const auto commit_result = execute_canvas_stroke_commit_dispatch( [[maybe_unused]] const auto commit_result = execute_canvas_stroke_commit_dispatch(
*this, *this,
vp, prelude.viewport,
cc, prelude.clear_color,
blend, prelude.blend,
[&](int texture_slot) { [&](int texture_slot) {
set_active_texture_unit(texture_slot); set_active_texture_unit(texture_slot);
}, },
action, prelude.action,
m_current_stroke, m_current_stroke.get(),
stroke_commit_sequence, stroke_commit_sequence,
stroke_material); stroke_material);
} }

View File

@@ -7,6 +7,7 @@
#include "canvas_layer.h" #include "canvas_layer.h"
#include "canvas_actions.h" #include "canvas_actions.h"
#include "canvas_modes.h" #include "canvas_modes.h"
#include "legacy_canvas_stroke_execution_services.h"
#include <stack> #include <stack>
#include "mp4enc.h" #include "mp4enc.h"
@@ -282,7 +283,7 @@ private:
pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest make_stroke_draw_samples_request( pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest make_stroke_draw_samples_request(
int face_index, int face_index,
std::vector<vertex_t>& polygon_vertices, std::vector<vertex_t>& polygon_vertices,
bool copy_stroke_destination) const; bool copy_stroke_destination);
pp::panopainter::LegacyCanvasStrokeTextureInputDispatch make_stroke_draw_samples_destination_texture_dispatch( pp::panopainter::LegacyCanvasStrokeTextureInputDispatch make_stroke_draw_samples_destination_texture_dispatch(
int face_index); int face_index);
void stroke_draw_dual_pass( void stroke_draw_dual_pass(
@@ -293,6 +294,12 @@ private:
const std::array<bool, 6>& include_dual_dirty, const std::array<bool, 6>& include_dual_dirty,
bool uses_pattern, bool uses_pattern,
bool copy_stroke_destination); bool copy_stroke_destination);
pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest make_stroke_draw_main_pass_request(
std::function<void()> bind_samplers,
std::function<void()> bind_textures,
std::function<void()> execute_frame_pass,
std::function<void()> unbind_textures,
std::function<void()> unbind_samplers);
pp::panopainter::LegacyCanvasStrokeDualPassRequest make_stroke_draw_dual_pass_request( pp::panopainter::LegacyCanvasStrokeDualPassRequest make_stroke_draw_dual_pass_request(
const std::vector<StrokeFrame>& frames_dual, const std::vector<StrokeFrame>& frames_dual,
const std::array<pp::panopainter::LegacyCanvasStrokeTextureBinding, 1>& dual_pass_texture_bindings, const std::array<pp::panopainter::LegacyCanvasStrokeTextureBinding, 1>& dual_pass_texture_bindings,
@@ -306,6 +313,8 @@ private:
const pp::renderer::Extent2D& stroke_extent, const pp::renderer::Extent2D& stroke_extent,
const std::array<bool, 6>& include_dual_dirty, const std::array<bool, 6>& include_dual_dirty,
bool copy_stroke_destination); bool copy_stroke_destination);
public:
Image thumbnail_read(std::string file_path); Image thumbnail_read(std::string file_path);
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>, int frame, bool save_history); void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>, int frame, bool save_history);
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>, Layer& layer, int frame, bool save_history); void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>, Layer& layer, int frame, bool save_history);

View File

@@ -17,6 +17,8 @@
namespace pp::panopainter { namespace pp::panopainter {
void setup_legacy_stroke_dual_shader(bool uses_pattern);
struct LegacyStrokeSampleExecutionRequest { struct LegacyStrokeSampleExecutionRequest {
std::string_view context; std::string_view context;
glm::vec2 target_size {}; glm::vec2 target_size {};
@@ -192,6 +194,24 @@ struct LegacyCanvasStrokeMainPassExecutionRequest {
std::function<void()> unbind_samplers; std::function<void()> unbind_samplers;
}; };
[[nodiscard]] inline LegacyCanvasStrokeMainPassExecutionRequest make_legacy_canvas_stroke_main_pass_execution_request(
std::string_view context,
std::function<void()> bind_samplers,
std::function<void()> bind_textures,
std::function<void()> execute_frame_pass,
std::function<void()> unbind_textures,
std::function<void()> 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( [[nodiscard]] inline LegacyCanvasStrokeSamplerDispatch make_legacy_canvas_stroke_live_pass_sampler_dispatch(
std::function<void(int)> bind_brush_tip_sampler, std::function<void(int)> bind_brush_tip_sampler,
std::function<void()> unbind_brush_tip_sampler, std::function<void()> unbind_brush_tip_sampler,

View File

@@ -4,6 +4,7 @@
#include "../libs/glm/glm/ext/matrix_clip_space.hpp" #include "../libs/glm/glm/ext/matrix_clip_space.hpp"
#include "legacy_canvas_stroke_shader_services.h" #include "legacy_canvas_stroke_shader_services.h"
#include "legacy_canvas_stroke_preview_services.h"
#include "legacy_canvas_stroke_services.h" #include "legacy_canvas_stroke_services.h"
#include "paint_renderer/compositor.h" #include "paint_renderer/compositor.h"
#include "texture.h" #include "texture.h"

View File

@@ -93,6 +93,30 @@ struct StrokePreviewCompositePassInputs {
Sampler& linear_sampler; Sampler& linear_sampler;
Sampler& repeat_sampler; Sampler& repeat_sampler;
std::function<void()> draw_composite; std::function<void()> 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<void()> 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( pp::panopainter::LegacyNodeStrokePreviewMixPassRequest make_stroke_preview_mix_pass_request(
@@ -384,6 +408,8 @@ std::array<pp::paint_renderer::CanvasStrokePoint, 4> make_stroke_preview_sample_
}; };
} }
void upload_stroke_preview_brush_vertices(DynamicShape& brush_shape, std::span<const vertex_t> vertices);
pp::panopainter::LegacyStrokeSampleExecutionRequest make_stroke_preview_sample_request( pp::panopainter::LegacyStrokeSampleExecutionRequest make_stroke_preview_sample_request(
std::array<vertex_t, 4>& vertices, std::array<vertex_t, 4>& vertices,
const std::array<pp::paint_renderer::CanvasStrokePoint, 4>& sample_points, const std::array<pp::paint_renderer::CanvasStrokePoint, 4>& sample_points,
@@ -768,6 +794,8 @@ void NodeStrokePreview::draw_stroke_immediate()
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence( const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence(
make_stroke_draw_immediate_pass_sequence_request( make_stroke_draw_immediate_pass_sequence_request(
m_stroke,
m_dual_stroke,
*b, *b,
pass_orchestration, pass_orchestration,
dual_brush, dual_brush,
@@ -784,6 +812,7 @@ void NodeStrokePreview::draw_stroke_immediate()
NodeStrokePreview::StrokeMainLivePassRequest NodeStrokePreview::StrokeMainLivePassRequest
NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request( NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request(
Stroke& stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
bool copy_stroke_destination, bool copy_stroke_destination,
@@ -810,7 +839,7 @@ NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request(
m_rtt.clear(); m_rtt.clear();
}, },
.compute_frames = [&] { .compute_frames = [&] {
return stroke_draw_compute(m_stroke, zoom); return stroke_draw_compute(stroke, zoom);
}, },
.before_frame = [&](auto& frame) { .before_frame = [&](auto& frame) {
if (brush.m_tip_mix > 0.f) 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( void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass(
Stroke& dual_stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
std::shared_ptr<Brush> dual_brush, std::shared_ptr<Brush> dual_brush,
@@ -858,7 +888,7 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass(
m_rtt.clear(); m_rtt.clear();
}, },
[&] { [&] {
return stroke_draw_compute(m_dual_stroke, zoom); return stroke_draw_compute(dual_stroke, zoom);
}, },
[](auto& frame) { [](auto& frame) {
frame.col = { 0, 0, 0, 1 }; frame.col = { 0, 0, 0, 1 };
@@ -885,6 +915,8 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass(
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest
NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request(
Stroke& stroke,
Stroke& dual_stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
std::shared_ptr<Brush> dual_brush, std::shared_ptr<Brush> dual_brush,
@@ -901,6 +933,7 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request(
}, },
.execute_dual_pass = [&] { .execute_dual_pass = [&] {
execute_stroke_draw_immediate_dual_pass( execute_stroke_draw_immediate_dual_pass(
dual_stroke,
brush, brush,
pass_orchestration, pass_orchestration,
dual_brush, dual_brush,
@@ -922,6 +955,7 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request(
[[maybe_unused]] const bool main_live_ok = [[maybe_unused]] const bool main_live_ok =
pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass( pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass(
make_stroke_draw_immediate_main_live_pass_request( make_stroke_draw_immediate_main_live_pass_request(
stroke,
brush, brush,
pass_orchestration, pass_orchestration,
copy_stroke_destination, copy_stroke_destination,
@@ -930,21 +964,21 @@ NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request(
}, },
.finish_main_pass = [&] {}, .finish_main_pass = [&] {},
.execute_final_composite = [&] { .execute_final_composite = [&] {
std::function<void()> draw_composite = [&] {
m_plane.draw_fill();
};
execute_stroke_preview_final_composite_and_copy( execute_stroke_preview_final_composite_and_copy(
StrokePreviewCompositePassInputs { StrokePreviewCompositePassInputs(
.resolution = size, size,
.pattern_scale = brush.m_pattern_scale, glm::vec2(brush.m_pattern_scale),
.brush = brush, brush,
.composite_pass = material.composite_pass, material.composite_pass,
.background_texture = m_tex_background, m_tex_background,
.stroke_texture = m_tex, m_tex,
.dual_texture = m_tex_dual, m_tex_dual,
.linear_sampler = m_sampler_linear, m_sampler_linear,
.repeat_sampler = m_sampler_linear_repeat, m_sampler_linear_repeat,
.draw_composite = [&] { std::move(draw_composite)),
m_plane.draw_fill();
},
},
m_tex_preview, m_tex_preview,
size); size);
}, },
@@ -983,7 +1017,7 @@ NodeStrokePreview::make_stroke_draw_mix_execution_request(
*m_brush, *m_brush,
m_sampler_linear, m_sampler_linear,
m_tex_background, m_tex_background,
m_rtt, m_tex,
m_tex_dual, m_tex_dual,
gl, gl,
bb_min, bb_min,

View File

@@ -3,6 +3,7 @@
#include "rtt.h" #include "rtt.h"
#include "brush.h" #include "brush.h"
#include "texture.h" #include "texture.h"
#include "legacy_node_stroke_preview_execution_services.h"
class NodeStrokePreview : public NodeBorder class NodeStrokePreview : public NodeBorder
{ {
@@ -54,6 +55,7 @@ public:
glm::vec4 stroke_draw_samples(std::array<vertex_t, 4>& P, Texture2D& blend_tex, bool copy_stroke_destination); glm::vec4 stroke_draw_samples(std::array<vertex_t, 4>& P, Texture2D& blend_tex, bool copy_stroke_destination);
std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke, float zoom) const; std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke, float zoom) const;
StrokeMainLivePassRequest make_stroke_draw_immediate_main_live_pass_request( StrokeMainLivePassRequest make_stroke_draw_immediate_main_live_pass_request(
Stroke& stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
bool copy_stroke_destination, bool copy_stroke_destination,
@@ -65,6 +67,7 @@ public:
const StrokeFrame& frame, const StrokeFrame& frame,
const glm::vec2& size); const glm::vec2& size);
void execute_stroke_draw_immediate_dual_pass( void execute_stroke_draw_immediate_dual_pass(
Stroke& dual_stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
std::shared_ptr<Brush> dual_brush, std::shared_ptr<Brush> dual_brush,
@@ -72,6 +75,8 @@ public:
float zoom, float zoom,
const glm::vec2& size); const glm::vec2& size);
pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest make_stroke_draw_immediate_pass_sequence_request( pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest make_stroke_draw_immediate_pass_sequence_request(
Stroke& stroke,
Stroke& dual_stroke,
const Brush& brush, const Brush& brush,
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
std::shared_ptr<Brush> dual_brush, std::shared_ptr<Brush> dual_brush,

View File

@@ -1315,6 +1315,7 @@ pp::foundation::Result<CanvasBlendGatePlan> plan_canvas_blend_gate(
CanvasBlendGateRequest request) noexcept CanvasBlendGateRequest request) noexcept
{ {
CanvasBlendGatePlan gate; 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) { for (std::size_t i = 0; i < request.layer_blend_modes.size(); ++i) {
pp::paint::BlendMode layer_blend = pp::paint::BlendMode::normal; pp::paint::BlendMode layer_blend = pp::paint::BlendMode::normal;
@@ -1331,21 +1332,10 @@ pp::foundation::Result<CanvasBlendGatePlan> plan_canvas_blend_gate(
continue; continue;
} }
gate.shader_blend = true; if (gate.first_complex_layer_index < 0) {
gate.complex_blend = true; gate.first_complex_layer_index = static_cast<int>(i);
gate.first_complex_layer_index = static_cast<int>(i); first_complex_layer_blend = layer_blend;
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;
} }
return pp::foundation::Result<CanvasBlendGatePlan>::success(gate);
} }
pp::paint::StrokeBlendMode stroke_blend = pp::paint::StrokeBlendMode::normal; pp::paint::StrokeBlendMode stroke_blend = pp::paint::StrokeBlendMode::normal;
@@ -1363,7 +1353,8 @@ pp::foundation::Result<CanvasBlendGatePlan> plan_canvas_blend_gate(
gate.dual_brush_complex = request.dual_brush_blend; gate.dual_brush_complex = request.dual_brush_blend;
gate.pattern_complex = request.pattern_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<CanvasBlendGatePlan>::success(gate); return pp::foundation::Result<CanvasBlendGatePlan>::success(gate);
} }
@@ -1373,6 +1364,7 @@ pp::foundation::Result<CanvasBlendGatePlan> plan_canvas_blend_gate(
features, features,
StrokeCompositeRequest { StrokeCompositeRequest {
.extent = request.extent, .extent = request.extent,
.layer_blend_mode = first_complex_layer_blend,
.stroke_blend_mode = stroke_blend, .stroke_blend_mode = stroke_blend,
.dual_brush_blend = request.dual_brush_blend, .dual_brush_blend = request.dual_brush_blend,
.pattern_blend = request.pattern_blend, .pattern_blend = request.pattern_blend,

View File

@@ -249,9 +249,11 @@ public:
[[nodiscard]] std::string clipboard_text() override [[nodiscard]] std::string clipboard_text() override
{ {
#if defined(__IOS__) || defined(__OSX__)
const auto family = pp::platform::current_platform_family(); const auto family = pp::platform::current_platform_family();
if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos)
return active_apple_document_platform_services().clipboard_text(); return active_apple_document_platform_services().clipboard_text();
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
return android_get_clipboard(); return android_get_clipboard();
#else #else
@@ -261,9 +263,11 @@ public:
[[nodiscard]] bool set_clipboard_text(std::string_view text) override [[nodiscard]] bool set_clipboard_text(std::string_view text) override
{ {
#if defined(__IOS__) || defined(__OSX__)
const auto family = pp::platform::current_platform_family(); const auto family = pp::platform::current_platform_family();
if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos)
return active_apple_document_platform_services().set_clipboard_text(text); return active_apple_document_platform_services().set_clipboard_text(text);
#endif
const std::string value(text); const std::string value(text);
#ifdef __ANDROID__ #ifdef __ANDROID__
return android_set_clipboard(value); return android_set_clipboard(value);
@@ -275,7 +279,11 @@ public:
void set_cursor_visible(bool visible) override void set_cursor_visible(bool visible) override
{ {
#if defined(__IOS__) || defined(__OSX__)
active_apple_document_platform_services().set_cursor_visible(visible); active_apple_document_platform_services().set_cursor_visible(visible);
#else
(void)visible;
#endif
} }
void set_virtual_keyboard_visible(bool visible) override 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())) if (!pp::platform::platform_saves_native_ui_state(pp::platform::current_platform_family()))
return; return;
#if defined(__IOS__) || defined(__OSX__)
active_apple_document_platform_services().save_ui_state(); active_apple_document_platform_services().save_ui_state();
#endif
} }
[[nodiscard]] bool enables_live_asset_reloading() override [[nodiscard]] bool enables_live_asset_reloading() override
@@ -629,12 +639,20 @@ public:
void display_file(std::string_view path) override void display_file(std::string_view path) override
{ {
#if defined(__IOS__) || defined(__OSX__)
active_apple_document_platform_services().display_file(path); active_apple_document_platform_services().display_file(path);
#else
(void)path;
#endif
} }
void share_file(std::string_view path) override void share_file(std::string_view path) override
{ {
#if defined(__IOS__) || defined(__OSX__)
active_apple_document_platform_services().share_file(path); active_apple_document_platform_services().share_file(path);
#else
(void)path;
#endif
} }
void request_app_close() override void request_app_close() override

View File

@@ -272,6 +272,20 @@ add_executable(pp_paint_renderer_compositor_tests
target_link_libraries(pp_paint_renderer_compositor_tests PRIVATE target_link_libraries(pp_paint_renderer_compositor_tests PRIVATE
pp_paint_renderer pp_paint_renderer
pp_test_harness) 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) add_test(NAME pp_paint_renderer_compositor_tests COMMAND pp_paint_renderer_compositor_tests)
set_tests_properties(pp_paint_renderer_compositor_tests PROPERTIES set_tests_properties(pp_paint_renderer_compositor_tests PROPERTIES

View File

@@ -1,6 +1,10 @@
#include "pch.h"
#include "assets/image_pixels.h" #include "assets/image_pixels.h"
#include "brush.h"
#include "legacy_canvas_draw_merge_services.h" #include "legacy_canvas_draw_merge_services.h"
#include "legacy_canvas_stroke_commit_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 "legacy_node_stroke_preview_execution_services.h"
#include "paint_renderer/compositor.h" #include "paint_renderer/compositor.h"
#include "renderer_api/recording_renderer.h" #include "renderer_api/recording_renderer.h"
@@ -13,6 +17,9 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
// 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::foundation::StatusCode;
using pp::paint::BlendMode; using pp::paint::BlendMode;
using pp::paint::Rgba; using pp::paint::Rgba;
@@ -68,14 +75,14 @@ using pp::document::LayerFacePixels;
namespace { namespace {
bool near(float a, float b) bool almost_equal(float a, float b)
{ {
return std::fabs(a - b) < 0.0001F; 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( 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, status.ok());
PP_EXPECT(h, near(destination[0].a, 0.625F)); PP_EXPECT(h, almost_equal(destination[0].a, 0.625F));
PP_EXPECT(h, near(destination[0].r, 0.44F)); PP_EXPECT(h, almost_equal(destination[0].r, 0.44F));
PP_EXPECT(h, near(destination[0].g, 0.32F)); PP_EXPECT(h, almost_equal(destination[0].g, 0.32F));
PP_EXPECT(h, near(destination[0].b, 0.4F)); PP_EXPECT(h, almost_equal(destination[0].b, 0.4F));
} }
void invisible_and_zero_opacity_layers_are_noops(pp::tests::Harness& h) 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, destination,
Extent2D { .width = 1, .height = 1 }, Extent2D { .width = 1, .height = 1 },
LayerCompositeView { .pixels = foreground, .opacity = 1.0F, .visible = false }).ok()); LayerCompositeView { .pixels = foreground, .opacity = 1.0F, .visible = false }).ok());
PP_EXPECT(h, near(destination[0].r, original.r)); PP_EXPECT(h, almost_equal(destination[0].r, original.r));
PP_EXPECT(h, near(destination[0].g, original.g)); PP_EXPECT(h, almost_equal(destination[0].g, original.g));
PP_EXPECT(h, near(destination[0].b, original.b)); PP_EXPECT(h, almost_equal(destination[0].b, original.b));
PP_EXPECT(h, near(destination[0].a, original.a)); PP_EXPECT(h, almost_equal(destination[0].a, original.a));
PP_EXPECT(h, composite_layer( PP_EXPECT(h, composite_layer(
destination, destination,
Extent2D { .width = 1, .height = 1 }, Extent2D { .width = 1, .height = 1 },
LayerCompositeView { .pixels = foreground, .opacity = 0.0F, .visible = true }).ok()); LayerCompositeView { .pixels = foreground, .opacity = 0.0F, .visible = true }).ok());
PP_EXPECT(h, near(destination[0].r, original.r)); PP_EXPECT(h, almost_equal(destination[0].r, original.r));
PP_EXPECT(h, near(destination[0].g, original.g)); PP_EXPECT(h, almost_equal(destination[0].g, original.g));
PP_EXPECT(h, near(destination[0].b, original.b)); PP_EXPECT(h, almost_equal(destination[0].b, original.b));
PP_EXPECT(h, near(destination[0].a, original.a)); PP_EXPECT(h, almost_equal(destination[0].a, original.a));
} }
void rejects_invalid_sizes_and_opacity(pp::tests::Harness& h) 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().composited_layer_count == 2U);
PP_EXPECT(h, result.value().face_payload_count == 2U); PP_EXPECT(h, result.value().face_payload_count == 2U);
PP_EXPECT(h, result.value().pixels.size() == 2U); PP_EXPECT(h, result.value().pixels.size() == 2U);
PP_EXPECT(h, near(result.value().pixels[0].r, 1.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[0].r, 1.0F));
PP_EXPECT(h, near(result.value().pixels[0].g, 0.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[0].g, 0.0F));
PP_EXPECT(h, near(result.value().pixels[0].b, 0.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[0].b, 0.0F));
PP_EXPECT(h, near(result.value().pixels[0].a, 1.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[0].a, 1.0F));
PP_EXPECT(h, near(result.value().pixels[1].r, 0.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[1].r, 0.0F));
PP_EXPECT(h, near(result.value().pixels[1].g, 0.5F)); PP_EXPECT(h, almost_equal(result.value().pixels[1].g, 0.5F));
PP_EXPECT(h, near(result.value().pixels[1].b, 0.5F)); PP_EXPECT(h, almost_equal(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[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().visited_layer_count == 2U);
PP_EXPECT(h, result.value().composited_layer_count == 1U); PP_EXPECT(h, result.value().composited_layer_count == 1U);
PP_EXPECT(h, result.value().face_payload_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, almost_equal(result.value().pixels[0].r, 0.0F));
PP_EXPECT(h, near(result.value().pixels[0].g, 0.0F)); PP_EXPECT(h, almost_equal(result.value().pixels[0].g, 0.0F));
PP_EXPECT(h, near(result.value().pixels[0].b, 1.0F)); PP_EXPECT(h, almost_equal(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].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().composited_layer_face_count == 3U);
PP_EXPECT(h, result.value().face_payload_count == 3U); PP_EXPECT(h, result.value().face_payload_count == 3U);
PP_EXPECT(h, result.value().faces[0].pixels.size() == 1U); 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, almost_equal(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, almost_equal(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].b, 0.0F));
PP_EXPECT(h, result.value().faces[1].pixels.size() == 1U); 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, almost_equal(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, almost_equal(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].b, 0.25F));
PP_EXPECT(h, result.value().faces[5].pixels.size() == 1U); 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, almost_equal(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, almost_equal(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, almost_equal(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].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.use_pattern);
PP_EXPECT(h, dual.composite_pass.dual_blend_mode == 3); PP_EXPECT(h, dual.composite_pass.dual_blend_mode == 3);
PP_EXPECT(h, dual.composite_pass.pattern_blend_mode == 4); 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)); PP_EXPECT(h, has_texture_binding(dual, CanvasStrokeTextureRole::dual_brush_tip, 4));
const auto dual_composite_pattern = plan_canvas_stroke_material( 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( const auto dispatch = pp::panopainter::make_legacy_canvas_stroke_live_pass_sampler_dispatch(
[&](int slot) { [&](int slot) {
steps.emplace_back("activate:" + std::to_string(slot)); steps.emplace_back("activate:" + std::to_string(slot));
},
[&] {
steps.emplace_back("bind-brush"); steps.emplace_back("bind-brush");
}, },
[&] { [&] {
steps.emplace_back("unbind-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("bind-pattern");
}, },
[&] { [&] {
steps.emplace_back("unbind-pattern"); steps.emplace_back("unbind-pattern");
}, },
[&] { [&](int slot) {
steps.emplace_back("activate:" + std::to_string(slot));
steps.emplace_back("bind-mixer"); steps.emplace_back("bind-mixer");
}, },
[&] { [&] {
steps.emplace_back("unbind-mixer"); steps.emplace_back("unbind-mixer");
},
[&] {
steps.emplace_back("bind-stencil");
},
[&] {
steps.emplace_back("unbind-stencil");
}); });
pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs( 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", "bind-pattern",
"activate:3", "activate:3",
"bind-mixer", "bind-mixer",
"activate:3",
"unbind-mixer", "unbind-mixer",
"activate:2",
"unbind-pattern", "unbind-pattern",
"activate:1",
"unbind-stencil", "unbind-stencil",
"activate:0",
"unbind-brush", "unbind-brush",
}; };
PP_EXPECT(h, steps == expected); PP_EXPECT(h, steps == expected);
@@ -2088,7 +2092,7 @@ void legacy_canvas_stroke_dual_pass_request_preserves_order(pp::tests::Harness&
"unbind", "unbind",
}; };
PP_EXPECT(h, result.ok); PP_EXPECT(h, result.ok);
PP_EXPECT(h, result.composed_planes == 1U); PP_EXPECT(h, result.composed_planes == 0U);
PP_EXPECT(h, steps == expected); 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_dual);
PP_EXPECT(h, plan.material.composite_pass.use_pattern); 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, 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, plan.material.composite_pass.pattern_blend_mode == request.pattern_blend_mode);
PP_EXPECT(h, near(plan.shader.resolution, request.resolution)); PP_EXPECT(h, almost_equal(plan.shader.resolution, request.resolution));
PP_EXPECT(h, near(plan.shader.pattern_scale, glm::vec2(-0.25F, -0.25F))); PP_EXPECT(h, almost_equal(plan.shader.pattern_scale, glm::vec2(-0.25F, -0.25F)));
PP_EXPECT(h, near(plan.shader.pattern_invert, 1.0F)); PP_EXPECT(h, almost_equal(plan.shader.pattern_invert, 1.0F));
PP_EXPECT(h, near(plan.shader.pattern_brightness, request.pattern_brightness)); PP_EXPECT(h, almost_equal(plan.shader.pattern_brightness, request.pattern_brightness));
PP_EXPECT(h, near(plan.shader.pattern_contrast, request.pattern_contrast)); PP_EXPECT(h, almost_equal(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.pattern_depth, request.pattern_depth));
PP_EXPECT(h, plan.shader.pattern_blend_mode == request.pattern_blend_mode); 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.blend_mode == request.blend_mode);
PP_EXPECT(h, plan.shader.use_dual == plan.material.composite_pass.use_dual); 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, 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); 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, ok);
PP_EXPECT(h, near(observed_shader.resolution, glm::vec2(128.0F, 64.0F))); PP_EXPECT(h, almost_equal(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.pattern_scale, glm::vec2(-0.25F, 0.25F)));
PP_EXPECT(h, observed_shader.use_dual); PP_EXPECT(h, observed_shader.use_dual);
PP_EXPECT(h, observed_shader.use_pattern); PP_EXPECT(h, observed_shader.use_pattern);
PP_EXPECT(h, observed_shader.dual_blend_mode == 9); 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<std::string> expected_steps { const std::vector<std::string> expected_steps {
"save", "save",
@@ -3128,17 +3132,17 @@ void legacy_node_stroke_preview_main_live_pass_preserves_order(pp::tests::Harnes
}; };
run({}); run({});
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"setup_blend", "setup_blend",
"bind_textures", "bind_textures",
"compute", "compute",
"clear", "clear",
"copy", "copy",
"finish", "finish",
}); }));
run({ Frame { .id = 7 } }); run({ Frame { .id = 7 } });
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"setup_blend", "setup_blend",
"bind_textures", "bind_textures",
"compute", "compute",
@@ -3148,7 +3152,7 @@ void legacy_node_stroke_preview_main_live_pass_preserves_order(pp::tests::Harnes
"draw:7", "draw:7",
"copy", "copy",
"finish", "finish",
}); }));
const bool invalid = pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass<Frame>( const bool invalid = pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass<Frame>(
pp::panopainter::LegacyNodeStrokePreviewMainLivePassRequestT<Frame> {}); pp::panopainter::LegacyNodeStrokePreviewMainLivePassRequestT<Frame> {});
@@ -3182,16 +3186,16 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t
}; };
run(false, false); run(false, false);
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"unit:0", "unit:0",
"bind_tip", "bind_tip",
"unit:2", "unit:2",
"bind_pattern", "bind_pattern",
"unit:3", "unit:3",
}); }));
run(true, true); run(true, true);
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"unit:0", "unit:0",
"bind_tip", "bind_tip",
"unit:1", "unit:1",
@@ -3200,7 +3204,7 @@ void legacy_node_stroke_preview_main_pass_texture_dispatch_preserves_order(pp::t
"bind_pattern", "bind_pattern",
"unit:3", "unit:3",
"bind_mixer", "bind_mixer",
}); }));
} }
void legacy_node_stroke_preview_final_composite_and_copy_helpers_preserve_order(pp::tests::Harness& h) 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, composite_ok);
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"setup", "setup",
"bind_samplers", "bind_samplers",
"bind_inputs", "bind_inputs",
"draw", "draw",
}); }));
steps.clear(); steps.clear();
const bool copy_ok = pp::panopainter::copy_legacy_node_stroke_preview_result( 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, copy_ok);
PP_EXPECT(h, steps == std::vector<std::string> { PP_EXPECT(h, (steps == std::vector<std::string> {
"copy:0,0,0,0,32,16", "copy:0,0,0,0,32,16",
}); }));
} }
void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_inputs(pp::tests::Harness& h) 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, .preview_point_count = 4,
}); });
PP_EXPECT(h, near(plan.stroke_max_size, 60.0F)); PP_EXPECT(h, almost_equal(plan.stroke_max_size, 60.0F));
PP_EXPECT(h, near(plan.dual_stroke_max_size, 15.0F)); PP_EXPECT(h, almost_equal(plan.dual_stroke_max_size, 15.0F));
PP_EXPECT(h, plan.dual_enabled); 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, plan.points.size() == 4U);
PP_EXPECT(h, near(plan.points[0].position.x, 17.0F)); PP_EXPECT(h, almost_equal(plan.points[0].position.x, 17.0F));
PP_EXPECT(h, near(plan.points[0].position.y, 80.0F)); PP_EXPECT(h, almost_equal(plan.points[0].position.y, 80.0F));
PP_EXPECT(h, near(plan.points[0].position.z, 0.0F)); PP_EXPECT(h, almost_equal(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].pressure, 0.0F));
PP_EXPECT(h, near(plan.points[1].pressure, 0.55F)); PP_EXPECT(h, almost_equal(plan.points[1].pressure, 0.55F));
PP_EXPECT(h, near(plan.points[2].pressure, 1.0F)); PP_EXPECT(h, almost_equal(plan.points[2].pressure, 1.0F));
PP_EXPECT(h, near(plan.points[3].pressure, 0.55F)); PP_EXPECT(h, almost_equal(plan.points[3].pressure, 0.55F));
const auto pressure_fallback = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup( const auto pressure_fallback = pp::panopainter::plan_legacy_node_stroke_preview_stroke_setup(
pp::panopainter::LegacyNodeStrokePreviewStrokeSetupRequest { pp::panopainter::LegacyNodeStrokePreviewStrokeSetupRequest {
@@ -3304,10 +3308,10 @@ void legacy_node_stroke_preview_stroke_setup_plan_preserves_curve_and_dual_input
.preview_point_count = 0, .preview_point_count = 0,
}); });
PP_EXPECT(h, near(pressure_fallback.stroke_max_size, 20.0F)); PP_EXPECT(h, almost_equal(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.dual_stroke_max_size, 40.0F));
PP_EXPECT(h, !pressure_fallback.dual_enabled); 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()); 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.use_pattern);
PP_EXPECT(h, plan.material.composite_pass.pattern_blend_mode == 3); 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, 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_mixer);
PP_EXPECT(h, plan.composite.uses_dual == plan.material.composite_pass.use_dual); 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::mixer, 3));
PP_EXPECT(h, has_preview_texture_slot(plan.composite, StrokePreviewTextureRole::pattern, 4)); 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, almost_equal(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, almost_equal(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, almost_equal(plan.stroke_shader.pattern.invert, 1.0F));
PP_EXPECT(h, near(plan.stroke_shader.pattern.brightness, 0.2F)); PP_EXPECT(h, almost_equal(plan.stroke_shader.pattern.brightness, 0.2F));
PP_EXPECT(h, near(plan.stroke_shader.pattern.contrast, 0.3F)); PP_EXPECT(h, almost_equal(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.pattern.depth, 0.4F));
PP_EXPECT(h, plan.stroke_shader.pattern.blend_mode == 3); 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_destination_feedback);
PP_EXPECT(h, !plan.stroke_shader.uses_pattern); PP_EXPECT(h, !plan.stroke_shader.uses_pattern);
PP_EXPECT(h, !plan.stroke_shader.set_opacity); PP_EXPECT(h, !plan.stroke_shader.set_opacity);
PP_EXPECT(h, near(plan.stroke_shader.mix_alpha, 0.0F)); PP_EXPECT(h, almost_equal(plan.stroke_shader.mix_alpha, 0.0F));
PP_EXPECT(h, near(plan.stroke_shader.wet, 0.0F)); PP_EXPECT(h, almost_equal(plan.stroke_shader.wet, 0.0F));
PP_EXPECT(h, near(plan.stroke_shader.noise, 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) 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().pattern_complex);
PP_EXPECT(h, plan.value().first_complex_layer_index == 1); PP_EXPECT(h, plan.value().first_complex_layer_index == 1);
PP_EXPECT(h, plan.value().reads_destination_color); PP_EXPECT(h, plan.value().reads_destination_color);
PP_EXPECT(h, plan.value().requires_auxiliary_texture); PP_EXPECT(h, !plan.value().requires_auxiliary_texture);
PP_EXPECT(h, plan.value().requires_texture_copy); PP_EXPECT(h, !plan.value().requires_texture_copy);
PP_EXPECT(h, plan.value().requires_render_target_blit); PP_EXPECT(h, !plan.value().requires_render_target_blit);
PP_EXPECT(h, plan.value().path == StrokeCompositePath::framebuffer_fetch); 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<std::string> expected { const std::vector<std::string> expected {
"bind-mix", "bind-mix",
"setup:4:1", "setup:4:1.000000",
"bind-layer:4", "bind-layer:4",
"bind-stroke:4", "bind-stroke:4",
"bind-mask: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.y == 19);
PP_EXPECT(h, plan.copy_region.width == 22); PP_EXPECT(h, plan.copy_region.width == 22);
PP_EXPECT(h, plan.copy_region.height == 12); PP_EXPECT(h, plan.copy_region.height == 12);
PP_EXPECT(h, near(plan.dirty_bounds.min_x, 9.0F)); PP_EXPECT(h, almost_equal(plan.dirty_bounds.min_x, 9.0F));
PP_EXPECT(h, near(plan.dirty_bounds.min_y, 19.0F)); PP_EXPECT(h, almost_equal(plan.dirty_bounds.min_y, 19.0F));
PP_EXPECT(h, near(plan.dirty_bounds.max_x, 31.0F)); PP_EXPECT(h, almost_equal(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.max_y, 31.0F));
} }
void canvas_stroke_sample_bounds_clamp_out_of_range_vertices(pp::tests::Harness& h) 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.y == 0);
PP_EXPECT(h, plan.copy_region.width == 64); PP_EXPECT(h, plan.copy_region.width == 64);
PP_EXPECT(h, plan.copy_region.height == 32); PP_EXPECT(h, plan.copy_region.height == 32);
PP_EXPECT(h, near(plan.dirty_bounds.max_x, 64.0F)); PP_EXPECT(h, almost_equal(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_y, 32.0F));
} }
void canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad(pp::tests::Harness& h) 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.y == 0);
PP_EXPECT(h, plan.copy_region.width == 40); PP_EXPECT(h, plan.copy_region.width == 40);
PP_EXPECT(h, plan.copy_region.height == 50); PP_EXPECT(h, plan.copy_region.height == 50);
PP_EXPECT(h, near(plan.ndc_quad[0].x, -1.0F)); PP_EXPECT(h, almost_equal(plan.ndc_quad[0].x, -1.0F));
PP_EXPECT(h, near(plan.ndc_quad[0].y, -1.0F)); PP_EXPECT(h, almost_equal(plan.ndc_quad[0].y, -1.0F));
PP_EXPECT(h, near(plan.ndc_quad[2].x, -0.2F)); PP_EXPECT(h, almost_equal(plan.ndc_quad[2].x, -0.2F));
PP_EXPECT(h, near(plan.ndc_quad[2].y, 0.25F)); PP_EXPECT(h, almost_equal(plan.ndc_quad[2].y, 0.25F));
PP_EXPECT(h, near(plan.ndc_quad[5].x, -0.2F)); PP_EXPECT(h, almost_equal(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[5].y, -1.0F));
} }
void canvas_stroke_face_dirty_update_includes_committed_dirty_box(pp::tests::Harness& h) 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.has_dirty_pixels);
PP_EXPECT(h, plan.committed_dirty); PP_EXPECT(h, plan.committed_dirty);
PP_EXPECT(h, plan.pass_dirty); PP_EXPECT(h, plan.pass_dirty);
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 0.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_x, 0.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 0.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_y, 0.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 64.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_x, 64.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 64.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_y, 64.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_x, -5.0F)); PP_EXPECT(h, almost_equal(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.pass_dirty_box.max_y, 90.0F));
} }
void canvas_stroke_face_dirty_update_can_skip_committed_dirty_box(pp::tests::Harness& h) 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.has_dirty_pixels);
PP_EXPECT(h, !plan.committed_dirty); PP_EXPECT(h, !plan.committed_dirty);
PP_EXPECT(h, plan.pass_dirty); PP_EXPECT(h, plan.pass_dirty);
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 1.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_x, 1.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 2.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.min_y, 2.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 3.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_x, 3.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 4.0F)); PP_EXPECT(h, almost_equal(plan.accumulated_dirty_box.max_y, 4.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_x, 0.0F)); PP_EXPECT(h, almost_equal(plan.pass_dirty_box.min_x, 0.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_y, 0.0F)); PP_EXPECT(h, almost_equal(plan.pass_dirty_box.min_y, 0.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.max_x, 30.0F)); PP_EXPECT(h, almost_equal(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.pass_dirty_box.max_y, 30.0F));
} }
} }

View File

@@ -1484,14 +1484,13 @@ void retained_stroke_main_pass_execution_preserves_bind_and_unbind_order(pp::tes
std::vector<std::string> events; std::vector<std::string> events;
const auto ok = pp::panopainter::execute_legacy_canvas_stroke_main_pass( const auto ok = pp::panopainter::execute_legacy_canvas_stroke_main_pass(
pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest { pp::panopainter::make_legacy_canvas_stroke_main_pass_execution_request(
.context = "test", "test",
.bind_samplers = [&] { events.emplace_back("bind-samplers"); }, [&] { events.emplace_back("bind-samplers"); },
.bind_textures = [&] { events.emplace_back("bind-textures"); }, [&] { events.emplace_back("bind-textures"); },
.execute_frame_pass = [&] { events.emplace_back("execute"); }, [&] { events.emplace_back("execute"); },
.unbind_textures = [&] { events.emplace_back("unbind-textures"); }, [&] { events.emplace_back("unbind-textures"); },
.unbind_samplers = [&] { events.emplace_back("unbind-samplers"); }, [&] { events.emplace_back("unbind-samplers"); }));
});
const std::vector<std::string> expected_events { const std::vector<std::string> expected_events {
"bind-samplers", "bind-samplers",