mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-07 20:41:50 +00:00
068c46cf8b
* Render: restore saved shots, progressive images and exports * Render: register existing live and coat command tests * Render: isolate lens saves and retain bounded previews Save only lens parameters on existing CPU/GPU jobs while keeping unrelated draft settings dirty. Retain pinned checkpoints through preview and status, and release host-only snapshots outside the status lock. Use the admitted PNG bound for registered-executor checkpoint slots. Preserve executor work credits, final publication and regrade ownership. Add regression coverage and align help, translations and capability documentation. * Render: preserve live feedback and address review regressions * Preserve saved cameras when applying Render library edits Keep the saved camera when lighting or maps are applied to an existing shot. Fit and centre the measured Render host using the painted picture. Carry forward the upstream CPU and GPU preset and ZoomTool contracts.
185 lines
12 KiB
Markdown
185 lines
12 KiB
Markdown
# Progressive product images
|
||
|
||
This integration is a draft. Final combined CPU, wasm and GPU verification and
|
||
full-resolution showcase acceptance remain incomplete. Test descriptions below
|
||
state intended coverage, not a claim that every backend has passed.
|
||
|
||
Native applications can register `solidcraft_gpu::path::host()` alongside the
|
||
existing CPU image host. `render.backends` then exposes `builtin/gpu-path` with
|
||
Preview, Image, PNG, Pbr, Progressive and Refraction. The browser keeps its CPU image host.
|
||
Device discovery follows `SOLIDCRAFT_GPU` and `WGPU_BACKEND`; a device which cannot
|
||
create the compute pipeline does not register an available path executor.
|
||
The native UI retains a factory for the viewport's selected adapter at installation,
|
||
without opening another device or compiling path shaders in Design (including safe-mode startup).
|
||
The first entry into Render starts preparation once, asynchronously; if the viewport arrives
|
||
later, that installation starts the already-requested preparation. Document changes retain
|
||
the pending/ready/failed host, and failures are not retried on each viewport installation.
|
||
It opens its independent job device on the viewport's selected adapter,
|
||
so software fallback and safe mode do not rediscover a failing hardware driver.
|
||
An incompatible explicit GPU policy leaves progressive rendering unavailable there.
|
||
A driver that crashes the process while it compiles the path pipeline (#9236) is beyond error
|
||
scopes and unwind guards, so a running setup keeps `gpu-path-setup.json` (its adapter key) in the
|
||
settings folder and removes it when the setup answers or the app closes normally. A launch that
|
||
finds it for the same adapter key leaves the setup failed with that explanation until the user
|
||
chooses **Try again**; a driver update changes the key and so tries again.
|
||
The path tracer runs on Vulkan, or on Metal on macOS (#3217). A viewport on D3D12 is reopened on the
|
||
same GPU through Vulkan. Where there is no Vulkan or Metal driver (Windows over
|
||
Remote Desktop or on the WARP software adapter, older drivers), the path executor reports
|
||
itself unavailable and images render on the CPU. On an RTX 4090, D3D12 was never faster:
|
||
equal per sample with DXC and about 55% slower with FXC, and it compiles the path shader
|
||
at every start (about 82 s with DXC, about 2 hours with FXC), where Vulkan's compiled
|
||
pipelines persist between runs.
|
||
|
||
In the Render workspace, select **GPU path tracing** and samples per pixel before
|
||
checking or starting an image. These controls are transient image-job
|
||
intent that can also be retained in typed saved setups. Each new saved concept
|
||
uses the pending-format mechanism, without manually changing a version number.
|
||
The canvas switches between live product preview and a large completed-image result,
|
||
with Fit and 100% framing. Fixed-sampling jobs publish an immutable PNG after every
|
||
complete nonfinal production pass, using the same transport, denoising and finishing
|
||
as the completed image. Partially computed passes are not displayed. The host retains
|
||
at most two prepaid snapshots; pinned external snapshots may skip a publication without
|
||
stalling final rendering, and this is counted in `preview_retention_skips`. Screen repaints may coalesce fast complete-pass updates.
|
||
Provisional PNGs never become exportable results or retained linear EXR masters.
|
||
Adaptive jobs also publish each complete pilot pass and production iteration. Pilot
|
||
images show the pilot mean; those samples remain excluded from the final master.
|
||
Production images normalize unfinished sums by their completed iteration count and
|
||
retain already finished pixel means. Neither readback nor the optional preview
|
||
denoiser writes the production accumulation. Progress labels distinguish pilots
|
||
from production iterations because production counts vary per pixel. The host
|
||
target includes pilots plus the configured maximum production count.
|
||
|
||
Adaptive readback reserves one additional float4 plane (16 bytes per pixel). When
|
||
denoising is selected, another independently reserved float4 plane supplies a
|
||
normalized display input to the same filter; final denoising keeps its original
|
||
production input. Final PNG and raw EXR remain identical with preview work disabled.
|
||
|
||
```json
|
||
{"command":"render.start","params":{"settings":{"width":800,"height":600,"exposure_ev":0},"progressive":true,"samples":64,"max_depth":8,"seed":0}}
|
||
```
|
||
|
||
`render.preflight` accepts the same input. It resolves the Progressive capability
|
||
to the installed GPU host and performs admission without reserving memory. Start
|
||
checks again and returns the existing session/serial/generation identity. Progress
|
||
reports complete samples per pixel; a partially computed sample is not counted.
|
||
Cancel, status, retained-image ownership and atomic PNG export use the same host
|
||
protocol as CPU jobs. Defaults are 64 samples, depth 8 and seed 0; the bounds are
|
||
1–4096 samples and 1–16 bounces. Sampling controls require `progressive: true`.
|
||
|
||
Runtime request-only [glass overrides](render-transmission.md) and an optional
|
||
[thin-lens camera](render-thin-lens.md) and [clear coat](render-clear-coat.md) are available through those same commands.
|
||
Neither adds saved document fields. Positive aperture requires perspective.
|
||
|
||
```sh
|
||
solidcraft-cli render examples/render-path-studio.json --out enclosure.png --progressive --samples 64 --max-depth 8 --seed 0 --width 800 --height 600
|
||
```
|
||
|
||
The CLI explicitly fails if a progressive request has no suitable device. Ordinary
|
||
CPU requests retain their prior behavior. GPU PNG export averages linear radiance,
|
||
applies saved exposure and the selected tone map (Reinhard by default), then
|
||
encodes sRGB once. Runtime `aces_fitted` is described in
|
||
[studio lighting](render-studio-lighting.md). A
|
||
transparent background uses straight alpha; background color is independent of
|
||
illumination.
|
||
|
||
The original integrator uses software BVH traversal, opaque GGX/Smith/Schlick and
|
||
the symmetric diffuse attenuation defined by `render::surface`. Each hit evaluates
|
||
the three existing directional studio lights with shadow visibility. Continuation
|
||
samples a mixture of cosine-weighted diffuse and GGX normals with the combined
|
||
PDF; Russian roulette begins after four hits. There are indirect bounces, but no
|
||
environment illumination in the default legacy lighting profile. All legacy opaque colors use
|
||
linear-sRGB base color, metallic 0, roughness 0.5, IOR 1.5. Explicit face appearances
|
||
take precedence over body appearances.
|
||
|
||
Explicit optical appearances can now select smooth dielectric reflection,
|
||
refraction, Beer–Lambert absorption and ideal thin sheets; see
|
||
[the transmission contract](render-transmission.md). Preview opacity remains a
|
||
separate scalar-alpha approximation. Opacity below one without an explicit
|
||
transmission record is rejected by the path executor. Runtime
|
||
[area lights](render-studio-lighting.md), [sun/HDR environment lighting](render-environment.md)
|
||
and [opaque planar color/normal maps](render-runtime-textures.md) are available
|
||
through explicit job inputs. They do not add saved document fields. An optional bounded edge-aware a-trous
|
||
[denoiser](render-denoise.md) filters progressive and final display images while preserving
|
||
raw accumulation. Optional raw scene-linear EXR masters are retained only for completed
|
||
images, before display filters. Texture LOD/mipmap selection and Final mode remain
|
||
unimplemented by this executor; a path-traced preview does not declare those capabilities.
|
||
|
||
Each job builds a BVH over its immutable captured meshes with a sixteen-bin
|
||
surface-area heuristic on triangle centres; there is no cross-document cache to
|
||
confuse scene generations. A split is accepted only when a median split of its
|
||
larger side would still keep the tree within 30 levels, the shader's 32-entry
|
||
traversal stack; otherwise that node falls back to the median split. Traversal
|
||
tests both child boxes at their parent and visits the nearer first. On the
|
||
exploded coffee machine at 1080p and 8 samples per pixel, this halves render
|
||
time on an NVIDIA GB10 (opaque 4.95 s to 2.49 s, closed glass 5.65 s to
|
||
2.79 s) with bit-identical images. Positions are
|
||
rebased around the camera target before f32 upload. The upload packs indexed 32-byte position/normal vertices, 16-byte triangle records
|
||
(including material IDs), 64-byte resolved materials, four-byte planar patch IDs
|
||
and 32-byte BVH nodes. Geometry arrays share one buffer. The progressive executor
|
||
requires six storage buffers per stage for geometry, BVH, accumulation,
|
||
environment, textures and medium-failure counts; raster device requirements remain unchanged.
|
||
Geometry must be within 1e7 mm of the camera target. Opaque and thin-sheet ray
|
||
offsets use max(1e-5 mm, extent × 1e-7); closed glass instead retains an anchor
|
||
and local displacement with strictly positive intersections, as described in
|
||
[closed-glass boundaries](render-glass-boundaries.md). These are bounded preview
|
||
precision policies, not a robust CAD intersection oracle.
|
||
|
||
Each GPU dispatch computes at most 262,144 pixel paths at one sample index. The
|
||
worker waits for that dispatch before checking cancellation and issuing another.
|
||
A driver wait has a 30-second timeout; cancellation cannot preempt a stalled GPU
|
||
dispatch. Encoding yields every four rows. Invalid indices/normals, nonfinite
|
||
geometry, excessive dimensions and sampling controls are errors.
|
||
|
||
The GPU host admits at most 1,048,576 input triangles, 4096 pixels per side and
|
||
4,194,304 pixels in all. The actual storage-buffer limit may lower these caps.
|
||
The source geometry cap is 128 MiB and the per-host pool is 512 MiB, including
|
||
retained PNG leases. Conservative estimates account for CPU BVH construction,
|
||
serialized and device geometry, accumulation, readback, RGBA and PNG buffers.
|
||
Allocator/driver bookkeeping is not an OS quota. CPU and GPU workers have separate
|
||
pools and each retains the established two-entry queue bound; a document still
|
||
has at most two live jobs across both executors.
|
||
|
||
Validation lives in `gpu::path::tests` and engine render job tests. Set
|
||
`SOLIDCRAFT_REQUIRE_GPU=1` to make absence of an adapter fail device tests rather
|
||
than skip them. BRDF parity is checked against the f64 oracle with 0.3% relative
|
||
plus 2e-5 absolute tolerance. The near-white furnace allows 0.07 absolute error:
|
||
the existing single-scattering Schlick model is not a perfectly conserving pure
|
||
Lambertian surface, even at IOR 1. Same-adapter determinism compares the actual
|
||
linear buffers bit-for-bit; cross-adapter bitwise identity is not promised.
|
||
|
||
The ignored `path_performance` test builds a 1,048,576-triangle procedural sphere
|
||
and measures 1920×1080 dispatches, BVH construction and upload. Select sample count
|
||
with `SOLIDCRAFT_PATH_BENCH_SAMPLES` (default 1). Run it explicitly with a clear GPU
|
||
timing window; it is excluded from normal CI.
|
||
|
||
## Dispatch and device-loss behavior
|
||
|
||
Each new path job begins with 64 paths. Completed submissions target approximately
|
||
20 ms and grow at most twofold, bounded to 64–16384 paths; a short image tail is
|
||
smaller. Denoiser guide/filter passes use the same controller. Measured wall time
|
||
includes scheduling contention, so this is a conservative responsiveness policy,
|
||
not a promised GPU deadline or a substitute for the OS watchdog. Sample/seed and
|
||
pixel identities are unchanged by tile boundaries.
|
||
|
||
Actual device-loss callbacks, uncaptured device errors and failed completion waits
|
||
retire that native executor. Existing and new jobs refuse further device work;
|
||
preflight/session metadata reports it unavailable without inventing new capabilities.
|
||
The application must deliberately recreate a host to recover. Merely registering the
|
||
same cached host or opening another document does not advertise it as healthy again.
|
||
|
||
|
||
### Shared index-matched base response
|
||
|
||
The opaque base lobe uses the same Fresnel limit as `OpaqueSurface`: when the
|
||
base IOR is exactly one, the dielectric fraction has no interface reflection at
|
||
any angle. A metallic mixture retains its independently weighted conductor
|
||
fraction. This applies to the specular term and both diffuse transmission factors.
|
||
The existing actual-GPU BRDF oracle checks the limit at normal, oblique and grazing
|
||
angles against the f64 surface, including mixed metallic values. Clear-coat and
|
||
physical transmission contracts are unchanged by this base-lobe correction.
|
||
|
||
The normal GPU Samples editor keeps the exact requested count, including values
|
||
such as 17 or 31; every complete pass is published. Merely opening a saved setup
|
||
does not round its count. **Use previous Render image defaults** retains the
|
||
previous power-of-two rounding for an edited GPU Samples value.
|