web: hand the RAW develop's plane to Skia as half, so the GPU keeps its shadows
An RGBA_F32 image with an sRGB tag comes back off the GPU backend sampled on a 1/255 grid; the same shader on a raster surface returns the floats untouched. The plane is raw/65535, so the shadows the black level is there to keep sit at 1e-3 and quantise to zero -- a 3010x2012 develop landed 41189 pixels under luma 2 with the dark end speckled blue/yellow, against none on the raster surface. A half is uploaded as float, so the plane stays exact either way. Rejects the earlier guess that the render target's colour space was to blame: gpu+rt-srgb and gpu+img-untagged came back byte-identical to gpu. scripts/half-check.mjs checks the conversion: the named encodings, and no plane value in a 14-bit sensor's range moving more than 4.8e-4 relative.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
// with an OffscreenCanvas if the develop ever blocks the UI visibly.
|
||||
import LibRaw from 'libraw-wasm';
|
||||
import { cameraMatch, type Mat3 } from './cameraMatch';
|
||||
import { f32ToF16 } from './halfFloat';
|
||||
import { Skia } from './skiaShim';
|
||||
|
||||
// What `imageData()` returns for the settings below: 16-bit, 3 channels, with
|
||||
@@ -136,6 +137,9 @@ export async function developRaw(bytes: Uint8Array): Promise<Uint8Array> {
|
||||
|
||||
const bandH = Math.max(1, Math.min(h, Math.floor(BAND_PIXELS / w)));
|
||||
const f32 = new Float32Array(w * bandH * 4);
|
||||
// The band goes up as half, not float32: the GPU backend puts an F32 image
|
||||
// on the 1/255 grid and the shadows quantise to black (see halfFloat.ts).
|
||||
const half = new Uint16Array(w * bandH * 4);
|
||||
for (let y0 = 0; y0 < h; y0 += bandH) {
|
||||
const rows = Math.min(bandH, h - y0);
|
||||
let o = 0;
|
||||
@@ -145,10 +149,11 @@ export async function developRaw(bytes: Uint8Array): Promise<Uint8Array> {
|
||||
f32[o++] = data[i + 2] / SAMPLE_MAX;
|
||||
f32[o++] = 1;
|
||||
}
|
||||
f32ToF16(f32, half, w * rows * 4);
|
||||
const band = Skia.Image.MakeImage(
|
||||
{ width: w, height: rows, colorType: Skia.ColorType.RGBA_F32, alphaType: Skia.AlphaType.Unpremul },
|
||||
new Uint8Array(f32.buffer, 0, w * rows * 16),
|
||||
w * 16
|
||||
{ width: w, height: rows, colorType: Skia.ColorType.RGBA_F16, alphaType: Skia.AlphaType.Unpremul },
|
||||
new Uint8Array(half.buffer, 0, w * rows * 8),
|
||||
w * 8
|
||||
);
|
||||
if (!band) throw new Error('band image failed');
|
||||
const child = band.makeShaderOptions(
|
||||
|
||||
Reference in New Issue
Block a user