Commit Graph
257 Commits
Author SHA1 Message Date
517d0a9eea Merge origin/main into #9887 (Indexed Color Matte)
Keeps main's Fade preview path in filter_preview.rs and passes the PR's
tool colours to the non-Fade preview; catalogs keep both sides' rows.

Co-Authored-By: Firstbober <firstbober@tutanota.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:23:31 +01:00
David Mann 017c4aab9e Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	docs/scorecard.md
2026-11-06 22:57:46 +01:00
Firstbober 7f96ce5343 Preserve Indexed profiles and preview current tool colors 2026-11-06 19:26:52 +01:00
Firstbober 2fbec8b533 fix: preserve document colours for indexed mattes 2026-11-06 19:14:59 +01:00
Firstbober b57ec9f729 fix: preserve indexed matte when picker is canceled 2026-11-06 19:14:59 +01:00
Firstbober 3a7a0aaa1e feat: add Indexed Color matte control 2026-11-06 19:14:58 +01:00
2ff8f419cb ci: run the GPU tests on lavapipe on Linux and fail if they skip (#7975)
The Linux runner has no GPU, so the GPU tests ran on Mesa llvmpipe over
GL, which can't render Rgba32Float: 57 GPU checks (50 GPU parity, 3
canvas, 2 adjustment preview parity, 2 effect-map recovery) returned
early and passed without comparing anything. A new step after Test
installs mesa-vulkan-drivers and runs the nextest `gpu` group on
lavapipe (Vulkan), reusing Test's build, and fails unless the parity
tests report the Vulkan backend and no test printed a skip.

No code change: photocraft's tests take whatever adapter wgpu returns,
software adapters included. Follows the CI half of lightcraft#1148.

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 18:44:13 +01:00
FredApps d2ce418bb3 Merge pull request #11641 from wanikhawar/claude/agitated-jones-8e1a8e
A little free memory no longer refuses every PSD; the refusal says what to do
2026-11-06 18:36:17 +01:00
FredApps d41e29a24f fix(ui): identify the active scratch directory in warnings 2026-11-06 17:51:33 +01:00
FredApps 8d2ee0787f Merge scratch query updates into memory admission policy 2026-11-06 17:29:23 +01:00
FredApps aee46a2fc6 Merge remote-tracking branch 'origin/main' into fix/10164-final-prune-u2 2026-11-06 17:28:48 +01:00
FredApps c8e4376ec6 Merge pull request #11513 from wanikhawar/claude/investigate-issue-e27e90
Windows: count scratch room when opening large files; refusal names the build's limit
2026-11-06 17:26:22 +01:00
Khawar Zamman Wani 146d49f5a2 PSD write recipes: keep every exported candidate and pin the base file (#11607)
* PSD write recipes: keep every exported candidate and pin the base file

A case that failed after export dropped out of manifest.json, losing the
file a reference-editor check most needs. The CLI also reopened the corpus
path after the hash was taken.

- Keep the candidate and its hash once export succeeds.
- Run the CLI on a copy of the hashed bytes, so it never opens the corpus.
- Compare numbers by value, so 17 equals 17.0.
- tracking-split also checks runs 0 and 2 and all three run lengths.

Part of #6130.

* PSD write recipes: compare large integers exactly, reject case-only id clashes

Converting to f64 made 9007199254740993 equal 9007199254740992. Ids that
differ only by letter case name one output directory on a case-insensitive
filesystem, so they are now rejected as duplicates.

* PSD write recipes: test that the CLI receives the hashed bytes

* PSD write recipes: reject the contour library commands

Their path param can read or write any file, including the pinned base and
the corpus, and they edit no document.
2026-11-06 17:23:40 +01:00
Khawar Zamman Wani 1ce1bced95 PSD admission: a little free memory no longer refuses every file
With 1 GiB or less of free RAM, or 512 MiB or less of commit headroom, the
hard limit was exactly 0, so even a small file was refused with a message that
didn't say memory was low.

The reserve now shrinks with the measurement: up to a quarter of free RAM opens
automatically, the rest goes to approval, and an approved import always leaves
at least 256 MiB free. Limits are unchanged for automatic opening above 4/3 GiB
free and for approval from 4 GiB free. A refusal set by measured memory now
gives the free amount and says to close other apps and try again, and the
approval prompt warns when little memory would be left.

An unreadable cgroup still measures Some(0) and stays refused.
2026-11-06 17:03:50 +05:30
Khawar Zamman Wani 349a03b6b1 Refusal text states the lower limit, links the download and shows readable sizes
The 32-bit message ended mid-phrase. It now says the cap applies or less if
less memory is free, and separates the cause from the next step. Windows
scratch tests check the returned numbers belong to the temp directory's volume.
2026-11-06 14:01:03 +05:30
Khawar Zamman Wani 1eb3218a4b Merge remote-tracking branch 'origin/main' into claude/investigate-issue-e27e90 2026-11-06 12:37:29 +05:30
Khawar Zamman Wani 7c2127b6bc PNG import in steps: stream the rows into tiles, turn upright in bands
PngImport decoded the whole image and then copied it into a second, tile surface (about
+400 MB for a 100 MP RGBA8 file, enough to kill a browser tab). A PNG whose rows come in
final order now streams: PngDecodeRows::step_stream hands each group of rows on, they
become tiles at once (the PngStream the one-shot streamed import also uses) and are
dropped, then the prune scan runs in batches. decode_rows is the same step_stream driven
to the end, so there is one path. Interlaced, animated and early-eXIf-oriented files are
decoded whole as before; a late eXIf sends a streamed import back to a whole decode.

The turn upright of an EXIF orientation 2-8 was one whole-buffer pass in the poll of the
last rows; OrientSteps (photocraft-codecs) does it in bands of 64 rows through the same
band writer as Image::oriented, and PngImport runs it as a stage of its own.

Memory-budget errors keep their type and text: the stream is checked as the one-shot
streamed import is, and, like the whole-image path, a layer under 32 MiB is not.
Docs for the stepped place updated.
2026-11-06 09:13:41 +05:30
Khawar Zamman Wani 123b2032c4 Web build: Place runs a slice per frame, so a large PNG no longer freezes the page (#10164, rebased onto main)
The remaining commits of the stack, applied on top of the squash-merged #10147:

- PNG decodes in resumable steps of rows (PngDecodeRows, shared with decode_rows)
- PNG imports as a document in resumable steps (io PngImport, text metadata and
  document build in bounded steps)
- Jobs can run a slice at a time where there are no threads (StepWork,
  cooperative sessions, Session::poll_jobs)
- Place decodes, flattens and resizes in slices (PlaceSteps), reading a path
  and keeping the frame, memory gate and typed memory-budget errors main has
- The web build places dropped and picked files a slice per frame, with a
  bounded place inbox
- A measurement of the stepped place; docs for jobs without threads
2026-11-06 08:51:17 +05:30
David Mann 66c328dc2b Merge commit '9bef3b2dc8b84c1b6cefc8ce0dc2b01d089cd9e8' into HEAD
# Conflicts:
#	docs/scorecard.md
2026-11-06 02:29:28 +01:00
6326117c53 Web build: big operations that won't fit fail with an error instead of trapping, and a trap says so (#10129)
* Raster: ask the allocator whether a big operation fits; PSD save reserves its whole output

New photocraft_raster::headroom: ensure(need) tries to reserve the need plus a margin and frees it
at once (web only; native always passes), below(bytes) tells whether less than that can be
allocated, and simulate_available fakes the answer for tests and diagnostics.

PsdFile::to_bytes reserved only the pixel data, so embedded smart-object data and other tagged
blocks grew the output by doubling, which on the web is one unrecoverable huge realloc. It now
reserves the exact encoded length.

* Big operations that won't fit in memory fail with an error instead of trapping

Place, Image Size, a smart-object re-render and Save now ask the allocator whether their estimated
need can be allocated before they start (photocraft_engine::memory_gate, estimates per operation,
photocraft_io::estimate_export_bytes for saves). A refusal changes nothing and says what the
operation needed and what to do (save, Edit > Purge > All, close documents).

A standing notice warns when less than 512 MiB can be allocated, with hysteresis, so the user can
save before anything traps. Notices can now be sticky, which keeps them past the auto-hide delay.

* Web build: a trap says so instead of freezing the page, and ?free-mb simulates low memory

index.html holds a hidden, static 'PhotoCraft stopped' message with a Reload link. web.rs reveals
it when the module traps (the window error event, or an unhandled rejection from a spawned
future), tells running out of memory from an internal error by the panic message a chained panic
hook kept, and skips the Leave site prompt once stopped. ?free-mb=N makes the memory gates and the
low-memory warning see only N MiB, for checking them in a browser.

* Docs: web build memory handling in the gaps list and the parity assessment

* Engine: use is_multiple_of in the megabyte formatter

* Cargo.lock: the web shell depends on photocraft-raster

* Web boot page: carry the stopped message too, as the test that keeps the two pages equal requires

* Save check counts one copy of the document, and runs once per save

The encoded file's buffer is reserved fallibly, so a save it doesn't fit
in fails with an error instead of trapping; counting it as well refused
saves that would have fitted. On the background-save path the check ran
in write_document and again in start_save, which other callers reach
directly; it now runs only in start_save there.

* Review fixes: warning check allocates nothing, PSD merged image counted, automation saves checked

The low-memory warning's periodic check reads the size of linear memory
instead of reserving a block: wasm memory never shrinks, so a trial every
few seconds raised the high-water mark by up to 768 MiB for nothing. The
operation checks keep their trial reservation.

PSD and PSB saves always build a canvas-sized merged image (a placeholder
without maximum compatibility) and hold it raw and encoded; the save
estimate now counts it. The synchronous automation save checks memory
before encoding, as File > Save does, and its test asserts the memory
error.

The trap listeners go in before the app is built, so a trap while
building it shows the stopped message too, and a memory access out of
bounds reads as unexpected rather than as running out of memory.

* Cover layered PSD preflight limitation

* Fix layered PSD test iteration

* Docs: layered PSD preflight limitation in the gaps list

* Web OOM gate: gate direct exports, truthful advice for unbounded PSD sources (#10024)

* Web OOM gate: estimate layered PSDs per layer instead of refusing every real PSD

The PSD check admitted a file only when its color-mode data, image
resources and layer section were all empty. Every Photoshop file has
image resources (at least the resolution), so on the web nearly every
real PSD was refused for Place, PSD smart objects could not render,
and Image Size was refused for documents holding one, whatever the
free memory (u64::MAX never fits).

The color-mode data and image resources hold no pixels, so they are
now only skipped. A layered file reads its layer count from the layer
info (signed, absolute value) and adds a canvas-sized surface and mask
per layer to the flat estimate. Files that are not 8-bit RGB or
grayscale, keep their layers in a Layr tagged block, or whose sections
can't be read stay unbounded and refused, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Web stopped page: match trap messages ignoring case

Safari reports the allocation-failure abort as "Unreachable code
should not be executed" and Firefox says "out of memory", which the
case-sensitive matching missed: the trap was not recognised, or was
shown as an unexpected stop instead of running out of memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export estimate: count the merged image OpenRaster writes

The ORA writer keeps the layers but also flattens the document for
mergedimage.png, a 16 B/px composite of the canvas, which the
estimate left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:04:59 +01:00
Khawar Zamman Wani af2914fd17 Refusal wording holds when memory sets the 32-bit limit; keep non-UTF-8 scratch paths
On a 32-bit build, free RAM or commit headroom can set the limit instead of the
cap, and then 'install the 64-bit build' was wrong. The message now mentions the
cap and says the 64-bit build may open the file.

The verbatim prefix is now removed through path components, so a scratch path with
a non-UTF-8 name still finds its disk. The UNC rewrite is gone: sysinfo lists only
fixed and removable volumes, so a network path can never match. That limitation is
now documented.
2026-11-05 23:22:13 +05:30
Khawar Zamman Wani 83f492f445 Windows scratch room is measured; hard memory refusal names the build's limit
fs::canonicalize returns verbatim paths on Windows, whose prefix never equals a
disk's plain mount point, so free_space always returned None there. That removed
the scratch allowance from import admission (unless a size limit was set) and
turned off the low-disk check.

The PsdHardBudget message said 'on this machine' even when the limit is the fixed
cap of the 32-bit desktop or web build. It now says so and names the build to use.
2026-11-05 22:07:47 +05:30
Khawar Zamman Wani f54d605e2c Add recipe-driven checks for PSD exports (#10307)
* Add recipe-driven PSD export checks

* Exercise PSD recipe runner with the headless CLI

* Make PSD oracle tests isolate temporary paths

* Keep inspect output unchanged; PSD write runner as an xtask library

- info --detail adds text runs, anti-aliasing and full layer-effect settings;
  the control channel and MCP inspect output is unchanged.
- The CLI test uses xtask's new library target instead of #[path] includes.
- The runner records revision and dirty state as unknown outside a git checkout.

* psd-write-oracle: name the layer in each check, document versioning, add recipe tests

* Clean up PSD oracle test fixtures on failure with tempfile::TempDir and add docstrings
2026-11-05 17:11:56 +01:00
Khawar Zamman WaniandFredApps 384ff664d6 perf: JPEG/PNG open bench with per-phase timings and peak memory (#10259) (#10271)
* perf: JPEG/PNG open bench with per-phase timings and peak memory (#10259)

Adds the flat_open_bench example (import, admission, decode, orient, tiles,
first composite and editable per case, each case in its own process for its
peak RSS), registers it and scenarios P83 to P86 (not enforced) in
perf/budgets.toml, and re-exports image_to_document (doc-hidden) so the bench
can time tile construction. No change to import behaviour.

* fix(compose): preserve special Fill semantics for CMYK adjustments

* Clarify flat-open benchmark RSS provenance

* Run flat-open benchmark provenance regression in CI

* Place benchmark regression module after production items

* chore: drop leftover CMYK proptest seeds from measurement PR

Keeps #10271 scoped to the flat JPEG/PNG open bench. The compose seeds belonged to the CMYK Fill work that already landed via #11001.

---------

Co-authored-by: FredApps <fredapps@users.noreply.github.com>
2026-11-05 13:49:37 +01:00
Khawar Zamman WaniandFredApps 13b481f892 Expose optional GPU composition and export in photocraft-cli (#10912)
* Add headless GPU backend foundation for composition and flat export (issue #8062 PR 1)

* Fix headless GPU readback bounds, API compliance, and error preservation (#8062)

* Fix GPU readback bounds, context thread spawn error, and test parity (#8062)

* Fix BandRenderer Send bound, PNG reborrows, and clippy lints (#8062)

* Fix effect shadow test construction and remove dead code wrappers (#8062)

* Use short reborrows for Headless renderer without lifetime escaping (#8062)

* Fix clippy collapsible_if and ensure multi-band geometry in flat export tests (#8062)

* Fix automation Rect import, add renderer diagnostics, and harden flat export retries (#8062)

* Expose optional GPU rendering in photocraft-cli (#8062)

* Fix GPU feature test APIs and native target gates

* Fix CLI locked metadata, bounded benchmark params, and protocol diagnostics (#8062)

* Verify unsupported GPU effects before testing band seams

* Fix CLI renderer borrows and GPU-enabled test compilation

* Use compositor buffer ownership API after upstream memory accounting change

* Fix GPU CLI lint failures and validate run environment policy

* Update export renderer test helper for owned compositor buffers

* Fix needless benchmark layer name borrow

* Fix headless GPU backend review findings (#10842)

- release a closed document's GPU caches through a BandRenderer hook
- bound the monitored readback wait and report a stalled GPU as device loss
- reject 32-bit float documents before band readback so exports fall back to CPU
- keep previews at 8-bit RGBA and report the palette/Duotone renderer bypass
- retain renderer diagnostics when encoding fails
- strengthen renderer, save-path and GPU diagnostics tests

* Use valid batch arguments and inspect method in GPU CLI tests

* Add GPU close-hook and 8-bit preview regression tests (#10842)

* Fix GPU CLI review findings (#10912)

- guard the benchmark's modulo divisors for one-pixel dimensions
- count a cold export as GPU only when the renderer context was used
- report every batch file's export warnings, deduplicating only GPU diagnostics
- drain renderer diagnostics before propagating convert and run save errors
- cover renderer use in the GPU precedence, bridge and serve tests

* fix(io): correct renderer binding mutability

* test(cli): verify narrow benchmark inputs and GPU diagnostics

* Fix remaining headless GPU review findings (#10842)

- release a document's GPU caches when file.close, file.closeAll or
  file.closeOthers removes it through a command
- honor cancellation while band readback waits, polling in 100 ms slices
- fault the device after a readback timeout so later exports skip it
- report single-layer, CMYK ink-mixing, ORA and PDF CPU paths to a
  requested renderer
- keep fallback warnings in their export instead of leaking them into the
  next one
- requeue renderer diagnostics when a renderer-aware save's final write
  fails
- write MCP/serve diagnostics without panicking on a broken stderr
- document the actual colour-space contract and drop F32 from the GPU
  depth list

* Fix remaining headless GPU review findings (#10842)

- release a document's GPU caches when file.close, file.closeAll or
  file.closeOthers removes it through a command
- honor cancellation while band readback waits, polling in 100 ms slices
- fault the device after a readback timeout so later exports skip it
- report single-layer, CMYK ink-mixing, ORA and PDF CPU paths to a
  requested renderer
- keep fallback warnings in their export instead of leaking them into the
  next one
- requeue renderer diagnostics when a renderer-aware save's final write
  fails
- write MCP/serve diagnostics without panicking on a broken stderr
- document the actual colour-space contract and drop F32 from the GPU
  depth list

* Fix remaining GPU CLI review findings (#10912)

- reject non-UTF-8 PHOTOCRAFT_GPU values instead of silently using the CPU
- release a batch item's document caches before taking the renderer to the
  next item, and report fallbacks once
- count warm benchmark runs that fell back to CPU in the summary
- write serve diagnostics without panicking on a broken stderr
- assert that the batch test's --gpu policy reaches the renderer

* Use question mark for cancellable readback errors

* Use question mark for cancellable readback errors

* Keep GPU export diagnostics with their attempt and stop bands on cancel

Encode native .pcraft bytes before draining renderer diagnostics, and
requeue export warnings when a workspace write fails, so callers still
report the adapter or fallback reason with the error.

Move a failed GPU attempt's queued diagnostics into its CPU retry result
instead of leaving them for a later successful export to report.

Stop GPU band readback at the next band after cancellation, and check the
interrupt before each CpuRenderer sink delivery.

Band readback uploads half-precision textures, so reject U16 alongside
F32: their samples cannot survive the upload. Tighten the 8-bit CPU/GPU
parity checks to 1/255.

* Keep GPU export diagnostics with their attempt and stop bands on cancel

Encode native .pcraft bytes before draining renderer diagnostics, and
requeue export warnings when a workspace write fails, so callers still
report the adapter or fallback reason with the error.

Move a failed GPU attempt's queued diagnostics into its CPU retry result
instead of leaving them for a later successful export to report.

Stop GPU band readback at the next band after cancellation, and check the
interrupt before each CpuRenderer sink delivery.

Band readback uploads half-precision textures, so reject U16 alongside
F32: their samples cannot survive the upload. Tighten the 8-bit CPU/GPU
parity checks to 1/255.

* Report partial warm fallbacks and CPU fallback on stderr

The averaged GPU Warm row now says how many warm runs fell back to the
CPU and were excluded from the average, through the existing helper.

The single-layer convert diagnostic test checks that the CPU fallback is
reported on stderr, in GPU-enabled and CPU-only builds alike.

* Keep headless export warnings when a workspace write fails (#10842)

A capability-scoped save encodes the export, then writes it; when the write
fails, the export warnings (folded together with renderer diagnostics) were
pushed back through `BandRenderer::push_diagnostic`, whose default is a no-op.
A custom renderer that overrides only `drain_diagnostics` therefore lost the
adapter or fallback reason that belonged with the error.

Keep them in `Headless` instead and return them from the next
`drain_diagnostics`, alongside the renderer's own queue. The regression uses a
renderer without a `push_diagnostic` override and checks the warnings survive
the failed write and drain exactly once.

Also name the actual source of the depth limit in the headless GPU matrix:
layer content is uploaded as half-precision textures, not band readback.

* Stop CPU bands and CPU retries on cancellation (#10912)

The CPU retry after a retryable GPU error composes through
`FlatSource::bands`, whose shared `emit` sink did not poll the export
interrupt: a cancel was only observed after the whole composite finished.
Check it once per band, as `CpuRenderer` does, for both RGB and CMYK ink
bands. The flat and streamed-PNG retry branches also check before starting
the full CPU composite again, so a cancelled export returns
`IoError::Cancelled` instead of re-rendering the document.

Tests: band-sink cancellation for RGB and CMYK inks, a renderer call counter
proving a second export reaches the renderer, and a pending `wait_slices`
poll observing cancellation set mid-wait.

* Merge origin/main into GPU foundation (#10842)

* Keep GPU-path diagnostics on every failure path, honour cancel in native copy

- save: export warnings of a failed local write stay in Headless pending diagnostics
- render: preview fallback warnings are returned, drained, and added to the doc.render reply
- io: renderer-neutral fallback wording; native single-layer copy checks cancellation per band
- gpu: gate wait_slices tests off wasm32 (#10842)

* Address CodeRabbit review: keep fallback reasons on failed retries, report native-copy and quick-export CPU use, guard diagnostics drain (#10912)

* Accept render diagnostics from the doc.render reply in the serve GPU test (#10912)

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 05:39:59 +01:00
Khawar Zamman WaniandFredApps 1089932ae9 Add a headless GPU backend for composition and flat export (#10842)
* Add headless GPU backend foundation for composition and flat export (issue #8062 PR 1)

* Fix headless GPU readback bounds, API compliance, and error preservation (#8062)

* Fix GPU readback bounds, context thread spawn error, and test parity (#8062)

* Fix BandRenderer Send bound, PNG reborrows, and clippy lints (#8062)

* Fix effect shadow test construction and remove dead code wrappers (#8062)

* Use short reborrows for Headless renderer without lifetime escaping (#8062)

* Fix clippy collapsible_if and ensure multi-band geometry in flat export tests (#8062)

* Fix automation Rect import, add renderer diagnostics, and harden flat export retries (#8062)

* Fix GPU feature test APIs and native target gates

* Verify unsupported GPU effects before testing band seams

* Use compositor buffer ownership API after upstream memory accounting change

* Update export renderer test helper for owned compositor buffers

* Fix headless GPU backend review findings (#10842)

- release a closed document's GPU caches through a BandRenderer hook
- bound the monitored readback wait and report a stalled GPU as device loss
- reject 32-bit float documents before band readback so exports fall back to CPU
- keep previews at 8-bit RGBA and report the palette/Duotone renderer bypass
- retain renderer diagnostics when encoding fails
- strengthen renderer, save-path and GPU diagnostics tests

* Add GPU close-hook and 8-bit preview regression tests (#10842)

* fix(io): correct renderer binding mutability

* Fix remaining headless GPU review findings (#10842)

- release a document's GPU caches when file.close, file.closeAll or
  file.closeOthers removes it through a command
- honor cancellation while band readback waits, polling in 100 ms slices
- fault the device after a readback timeout so later exports skip it
- report single-layer, CMYK ink-mixing, ORA and PDF CPU paths to a
  requested renderer
- keep fallback warnings in their export instead of leaking them into the
  next one
- requeue renderer diagnostics when a renderer-aware save's final write
  fails
- write MCP/serve diagnostics without panicking on a broken stderr
- document the actual colour-space contract and drop F32 from the GPU
  depth list

* Use question mark for cancellable readback errors

* Keep GPU export diagnostics with their attempt and stop bands on cancel

Encode native .pcraft bytes before draining renderer diagnostics, and
requeue export warnings when a workspace write fails, so callers still
report the adapter or fallback reason with the error.

Move a failed GPU attempt's queued diagnostics into its CPU retry result
instead of leaving them for a later successful export to report.

Stop GPU band readback at the next band after cancellation, and check the
interrupt before each CpuRenderer sink delivery.

Band readback uploads half-precision textures, so reject U16 alongside
F32: their samples cannot survive the upload. Tighten the 8-bit CPU/GPU
parity checks to 1/255.

* Keep headless export warnings when a workspace write fails (#10842)

A capability-scoped save encodes the export, then writes it; when the write
fails, the export warnings (folded together with renderer diagnostics) were
pushed back through `BandRenderer::push_diagnostic`, whose default is a no-op.
A custom renderer that overrides only `drain_diagnostics` therefore lost the
adapter or fallback reason that belonged with the error.

Keep them in `Headless` instead and return them from the next
`drain_diagnostics`, alongside the renderer's own queue. The regression uses a
renderer without a `push_diagnostic` override and checks the warnings survive
the failed write and drain exactly once.

Also name the actual source of the depth limit in the headless GPU matrix:
layer content is uploaded as half-precision textures, not band readback.

* Stop CPU bands and CPU retries on cancellation (#10912)

The CPU retry after a retryable GPU error composes through
`FlatSource::bands`, whose shared `emit` sink did not poll the export
interrupt: a cancel was only observed after the whole composite finished.
Check it once per band, as `CpuRenderer` does, for both RGB and CMYK ink
bands. The flat and streamed-PNG retry branches also check before starting
the full CPU composite again, so a cancelled export returns
`IoError::Cancelled` instead of re-rendering the document.

Tests: band-sink cancellation for RGB and CMYK inks, a renderer call counter
proving a second export reaches the renderer, and a pending `wait_slices`
poll observing cancellation set mid-wait.

* Merge origin/main into GPU foundation (#10842)

* Keep GPU-path diagnostics on every failure path, honour cancel in native copy

- save: export warnings of a failed local write stay in Headless pending diagnostics
- render: preview fallback warnings are returned, drained, and added to the doc.render reply
- io: renderer-neutral fallback wording; native single-layer copy checks cancellation per band
- gpu: gate wait_slices tests off wasm32 (#10842)

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 04:53:25 +01:00
skylar taylor-barrick 68b6dbfa79 Merge pull request #10750 from RickiNano/perf/bench-cmd-refresh-split
perf(bench): split command and refresh time; refresh like the app; stop rows timing setup
2026-11-04 12:39:54 +01:00
David Mann 4bbe9c78de Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	docs/scorecard.md
2026-11-03 20:32:22 +01:00
David Mann 7329c700bb Merge remote-tracking branch 'origin/main' into integration-batch-13
# Conflicts:
#	apps/photocraft-cli/src/args.rs
#	crates/engine/src/jobs.rs
#	crates/engine/src/jobs/tests.rs
2026-11-03 13:52:30 +01:00
Khawar Zamman Wani 259b5590ae Merge origin/main (655295b2a2) into PR #10897 branch
Keep the PSD memory admission work and upstream's scratch storage
together. Conflicts resolved:
- Cargo.lock: both sysinfo versions are required. 0.40.1 serves
  photocraft-io's adaptive import budget; 0.37.2 serves
  photocraft-raster's scratch volume and memory supervision. Cargo
  metadata resolved the lock with no other changes.
- crates/engine/src/lib.rs: Session keeps pending_preflights and
  next_pending_preflight beside scratch_runtime and scratch_epoch.
  Session derives Default, so neither set needs a manual initializer.

Upstream: 655295b2a2
2026-11-03 12:54:59 +05:30
FredApps 8ce599da3a Merge remote-tracking branch 'upstream/main' into pr-5330 2026-11-03 07:12:38 +01:00
dotCooCoo fef15729aa Merge main into feat/pcraft-full-composite
Main now takes the manifest envelope from craft-pcraft-format, which has
no full_composite member. The save writes the member after the envelope
when it writes composite/full.png, and read_full_composite reads it back.
2026-11-02 17:02:14 -08:00
David Mann eb3c2044d4 Merge #10755: Support newer recorded Action events
# Conflicts:
#	crates/engine/src/cmd/artboard_cmds.rs
#	crates/engine/src/cmd/atn_cmds.rs
#	crates/engine/src/cmd/atn_cmds/events.rs
#	crates/engine/src/cmd/atn_cmds/steps_make.rs
#	crates/engine/tests/it/main.rs
#	docs/atn.md
#	docs/development.md
#	docs/file-format-parity.md
2026-11-03 00:44:15 +01:00
David Mann b0aa230ae8 Merge #10765: Actions: support direct Gradient Map and Lab-range Replace Color
# Conflicts:
#	crates/engine/src/cmd/atn_cmds.rs
#	crates/engine/src/cmd/atn_cmds/events.rs
#	crates/engine/tests/it/main.rs
#	docs/atn.md
#	docs/development.md
#	docs/file-format-parity.md
2026-11-03 00:38:44 +01:00
FredApps fb684cd114 Merge remote-tracking branch 'upstream/main' into pr-5330 2026-11-03 00:02:18 +01:00
FredApps b0f3c7516b Merge current main into codex/scratch-storage
Resolve conflicts with main's prefs UI split, session/execute.rs move, GPU memory
budget (gpuMemoryMb, 0 = auto, kept from main) and effective_memory_usage_mb history
budget. Port the Memory Usage % and Scratch Disks preferences into prefs_ui, the edit
integrity guard into session/execute.rs, and adapt main's new pixel readers to the
guarded TileBytes API. Cargo.lock regenerated; scorecard regenerated.
2026-11-02 22:16:22 +01:00
Khawar Zamman Wani 5992650b36 fix: address PSD admission review and enable platform memory consent 2026-11-03 01:26:13 +05:30
David Mann 673bfb4d9c Merge remote-tracking branch 'origin/main' into integration-batch-12
# Conflicts:
#	docs/file-format-parity.md
2026-11-02 20:15:23 +01:00
FredApps 9236d27eb6 Merge current main into fix/gnome-window-decorations 2026-11-02 19:10:43 +01:00
Khawar Zamman Wani 582a285b5d fix: enforce scoped PSD memory admission and complete retry integration 2026-11-02 19:01:15 +05:30
Khawar Zamman Wani bcc060180f feat(io,engine,ui): adaptive PSD/PSB memory budget and interactive confirmation
- Distinguish available physical RAM from swap and commit headroom
- Adaptive soft and hard import thresholds with native fallback
- Interactive preflight confirmation modal before pixel decoding
- Headless and command parameters for explicit high-memory approval
- One-shot source-bound validation rejecting altered sources or degraded RAM
- Process-wide serialized decode gate with reentrancy support
- Documentation and synthetic regression test coverage
2026-11-02 17:11:03 +05:30
David Mann d570b77abb Merge PR #10753: Support recorded layer, document and layer comp references
With our fix-up ea4112a4ce on top of the author's head 686f08c884. docs/atn.md kept from the batch (regenerated at the end); development.md and parity doc rows as unions.
2026-11-02 02:40:55 +01:00
David Mann 5bc852379a Merge PR #10743: Read Photoshop Actions version 12 descriptors
With our fix-up 1f524c378b on top of the author's head 713aa92ba5. Resolved with main: the version check sits in main's parse_layout (it merged cleanly); doc comments combined; atn_contract no longer expects version 12 to be refused and pins that an empty version 12 set parses; one ATTRIBUTION row for all ATN fixtures; the fixture README states which files were encoded how; development.md no longer counts the fixtures.
2026-11-02 02:13:56 +01:00
yoriswind ed71465b89 Apply measured Artboard background settings without resizing 2026-11-01 16:58:20 -08:00
yoriswind 6aa4a52391 Merge main and preserve both ATN development notes 2026-11-01 16:16:56 -08:00
aiongg fab871dadb Merge pull request #10535 from davidmann4/integration-batch-11
Integration batch 11: 9 ATN PRs on main
2026-11-01 19:11:02 -05:00
dotCooCoo e7829eb449 Merge main into feat/pcraft-full-composite 2026-11-01 15:30:48 -08:00
yoriswind be36a01846 docs: explain direct adjustment validation helpers 2026-11-01 14:17:28 -08:00
yoriswind 0fb31eb63d docs: document supported direct adjustment forms and limits 2026-11-01 14:04:20 -08:00
yoriswind 21b6546907 Resolve recorded Action reference forms at playback 2026-11-01 12:55:02 -08:00