Develop a JPEG through the same pipeline as a RAW
DemosaicedImage gains a second producer, from_rgba8, alongside the CFA path. Nothing about the type is CFA-specific — it is "an image on the GPU, ready to adjust" — which is what lets develop mode work on a JPEG without the edit graph or any operation knowing the source was not a RAW file. The one real difference is the transfer function: sensor data is linear, a JPEG is gamma-encoded. Every operation assumes linear scene-referred colour (exposure is a multiply, and doubling a gamma-encoded value is not a stop), so the shader prologue linearises once, at the only point where the two source kinds still differ. The flag rides in as_shot_wb.w, which was padding. For a JPEG the white balance uniform is neutral and the colour matrix is identity, so both stay unconditional multiplies rather than becoming branches. max_dimension is exposed because it is a hardware limit the caller must plan around, not a failure to report afterwards: a 13728x8928 film scan exceeds the common 8192 texture limit, and fitting it first is the only way to develop it at all. Assisted-by: LLM
This commit is contained in:
@@ -190,6 +190,9 @@ pub fn compose_with_framing(ops: &[Box<dyn Operation>], framing: &Framing) -> Co
|
||||
\x20 cam_to_srgb_1: vec4<f32>,\n\
|
||||
\x20 cam_to_srgb_2: vec4<f32>,\n\
|
||||
\x20 // As-shot white balance, the neutral point for the WB control.\n\
|
||||
\x20 // `.w` is not padding: it flags a non-linear source (1.0 for a\n\
|
||||
\x20 // gamma-encoded JPEG, 0.0 for demosaiced sensor data), which the\n\
|
||||
\x20 // prologue reads to decide whether to linearise.\n\
|
||||
\x20 as_shot_wb: vec4<f32>,\n",
|
||||
);
|
||||
uniform_values.resize(BASE_UNIFORM_FIELDS, 0.0);
|
||||
@@ -293,6 +296,19 @@ fn encode_srgb(c: vec3<f32>) -> vec3<f32> {{
|
||||
return select(hi, lo, c <= vec3<f32>(0.0031308));
|
||||
}}
|
||||
|
||||
// The inverse, for sources that arrive already display-encoded.
|
||||
//
|
||||
// A JPEG is uploaded with its bytes untouched, so its values are gamma-encoded
|
||||
// where the demosaicer's are linear. Every operation below assumes linear
|
||||
// scene-referred colour — exposure is a multiply, and doubling a gamma-encoded
|
||||
// value is not a stop — so the encoding is undone here, once, at the only
|
||||
// point where the two source kinds still differ.
|
||||
fn decode_srgb(c: vec3<f32>) -> vec3<f32> {{
|
||||
let lo = c / 12.92;
|
||||
let hi = pow((max(c, vec3<f32>(0.04045)) + 0.055) / 1.055, vec3<f32>(2.4));
|
||||
return select(hi, lo, c <= vec3<f32>(0.04045));
|
||||
}}
|
||||
|
||||
@compute @workgroup_size(8, 8, 1)
|
||||
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {{
|
||||
let dims = textureDimensions(output);
|
||||
@@ -301,17 +317,29 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {{
|
||||
}}
|
||||
|
||||
{prologue}
|
||||
// A non-linear source is already display-encoded; undo that so the
|
||||
// operations below see linear colour whatever the source was.
|
||||
let non_linear = u.as_shot_wb.w > 0.5;
|
||||
if (non_linear) {{
|
||||
c = decode_srgb(c);
|
||||
}}
|
||||
|
||||
// As-shot white balance. Applied unconditionally, before any operation,
|
||||
// because it is part of *interpreting* the sensor rather than an edit: a
|
||||
// Bayer sensor's green photosites collect far more signal than its red
|
||||
// and blue, so raw camera-space values are strongly green and no amount
|
||||
// of later correction recovers a neutral image from them. The white
|
||||
// balance operation, when active, applies its own offset on top of this.
|
||||
//
|
||||
// A non-linear source has already had this applied in-camera; the uniform
|
||||
// is neutral there, so this is a multiply by one rather than a branch.
|
||||
c = c * u.as_shot_wb.rgb;
|
||||
{body}
|
||||
// Camera space -> linear sRGB. Applied after the adjustments so white
|
||||
// balance and exposure act on sensor-native values, which is where they
|
||||
// are physically meaningful.
|
||||
//
|
||||
// Identity for a non-linear source, which is already in sRGB primaries.
|
||||
c = vec3<f32>(
|
||||
dot(u.cam_to_srgb_0.rgb, c),
|
||||
dot(u.cam_to_srgb_1.rgb, c),
|
||||
|
||||
Reference in New Issue
Block a user