From c02b401a9aa001f7cc68a0f791f247ebcee41286 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Fri, 2 Oct 2026 22:09:52 -0400 Subject: [PATCH] Apply a camera profile's HueSatMap and LookTable after exposure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The second half of D20: a camera_profile scene operation at order 25 that converts working colour into linear ProPhoto, runs the DNG SDK's HSV lookup through the HueSatMap and then the LookTable, and converts back. Hue and saturation do not change under the uniform gains before it, so a 2.5-D HueSatMap gives the same answer as straight after the matrix, and the look sees the photographer's exposure as it does in the SDK. Two departures for scene-referred values: value is not clamped on the way out, and a colour outside ProPhoto passes through. The operation holds only the switch (on by default) and a look strength of 0-200 %. It is composed while the switch is on — a new Operation::composes() separates "does something" from "moved from the defaults", so an untouched raw renders through its profile and still writes nothing. The tables come from the source: dr-gpu uploads the ones DemosaicedImage carries into a storage buffer at @binding(8), whose two-entry header tells the fragment whether there is anything to apply, and binds a header of zeros for every other source. apply_reference is the lookup on the CPU. The GPU test holds the shader to it over 256 colours, through synthetic tables strong enough that a wrong index shows, and through the library's real Adobe Standard tables when the 6D DNG is present. --- core/dr-gpu/src/adjust.rs | 70 +++ core/dr-gpu/src/demosaic.rs | 14 + core/dr-gpu/tests/camera_profile.rs | 249 ++++++++ core/dr-pipeline/ops/camera_profile.yaml | 19 + core/dr-pipeline/src/graph.rs | 19 +- core/dr-pipeline/src/lib.rs | 10 + core/dr-pipeline/src/operation.rs | 22 +- core/dr-pipeline/src/ops/camera_profile.rs | 678 +++++++++++++++++++++ core/dr-pipeline/src/ops/mod.rs | 2 + core/dr-pipeline/tests/declared_parity.rs | 3 +- docs/dev/camera-profiles.md | 22 +- docs/dev/requirements.md | 2 +- docs/dev/traceability.md | 58 +- 13 files changed, 1117 insertions(+), 51 deletions(-) create mode 100644 core/dr-gpu/tests/camera_profile.rs create mode 100644 core/dr-pipeline/ops/camera_profile.yaml create mode 100644 core/dr-pipeline/src/ops/camera_profile.rs diff --git a/core/dr-gpu/src/adjust.rs b/core/dr-gpu/src/adjust.rs index 4b270f7..5c0186a 100644 --- a/core/dr-gpu/src/adjust.rs +++ b/core/dr-gpu/src/adjust.rs @@ -71,6 +71,14 @@ pub struct AdjustPass { empty_film_lut: wgpu::TextureView, /// The loaded stock's tables, once uploaded. See [`Self::set_film`]. film: Option, + /// TRACES: FR-DEV-3e + /// Bound at `@binding(8)` for a source with no camera profile tables: the + /// two-entry header of zeros that tells the fragment there is nothing to + /// apply (D20). + empty_profile: wgpu::Buffer, + /// The current source's tables, uploaded, keyed by + /// [`DemosaicedImage::id`] — one upload per source rather than per frame. + profile: Option<(u64, wgpu::Buffer)>, /// TRACES: FR-DEV-3 | FR-DEV-3d /// The neighbourhood stage — sharpening, noise reduction, clarity and the /// rest of FR-DEV-3's detail set, which cannot be fused into the shader @@ -512,6 +520,37 @@ impl AdjustPass { } /// The curve texture to bind: the loaded stock's, or the placeholder. + /// TRACES: FR-DEV-3e + /// A source's camera profile tables as the storage buffer + /// `@binding(8)` reads, laid out by `dr_pipeline`'s `profile_buffer`. + fn upload_profile(ctx: &GpuContext, tables: Option<&dr_types::ProfileTables>) -> wgpu::Buffer { + let data = dr_pipeline::ops::camera_profile::profile_buffer(tables); + ctx.device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("adjust-profile-tables"), + contents: bytemuck::cast_slice(&data), + usage: wgpu::BufferUsages::STORAGE, + }) + } + + /// TRACES: FR-DEV-3e + /// The buffer to bind for `source`: its tables, uploaded once per source, + /// or the empty header. A cheap handle, cloned out so a caller holding + /// other borrows of `self` can bind it. + fn profile_buffer(&mut self, source: &DemosaicedImage) -> wgpu::Buffer { + let Some(tables) = source.profile_tables() else { + return self.empty_profile.clone(); + }; + if let Some((id, buffer)) = &self.profile { + if *id == source.id() { + return buffer.clone(); + } + } + let buffer = Self::upload_profile(&self.ctx, Some(tables)); + self.profile = Some((source.id(), buffer.clone())); + buffer + } + fn film_curves_view(&self) -> &wgpu::TextureView { self.film .as_ref() @@ -645,6 +684,8 @@ impl AdjustPass { empty_film_curves, empty_film_lut, film: None, + empty_profile: Self::upload_profile(ctx, None), + profile: None, detail: DetailRunner::new(ctx), linear_bind_group_layout, linear_pipeline_layout, @@ -775,6 +816,17 @@ impl AdjustPass { }, count: None, }, + // The camera profile's tables (FR-DEV-3e, D20). + wgpu::BindGroupLayoutEntry { + binding: 8, + visibility: wgpu::ShaderStages::COMPUTE, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, ], }) } @@ -973,6 +1025,7 @@ impl AdjustPass { usage: wgpu::BufferUsages::UNIFORM, }); + let profile = self.profile_buffer(source); let pipeline = self .cache .get(&shader.structure_hash) @@ -1020,6 +1073,10 @@ impl AdjustPass { binding: 7, resource: wgpu::BindingResource::TextureView(&sample_out), }, + wgpu::BindGroupEntry { + binding: 8, + resource: profile.as_entire_binding(), + }, ], }); @@ -1139,6 +1196,7 @@ impl AdjustPass { // be read off `self` at the point the bind group is built. let film_curves = self.film_curves_view().clone(); let film_lut = self.film_lut_view().clone(); + let profile = self.profile_buffer(source); let mut enc = self .ctx @@ -1202,6 +1260,10 @@ impl AdjustPass { binding: 7, resource: wgpu::BindingResource::TextureView(&sample_out), }, + wgpu::BindGroupEntry { + binding: 8, + resource: profile.as_entire_binding(), + }, ], }); let pipeline = self @@ -1298,6 +1360,10 @@ impl AdjustPass { binding: 7, resource: wgpu::BindingResource::TextureView(&no_sample_out), }, + wgpu::BindGroupEntry { + binding: 8, + resource: profile.as_entire_binding(), + }, ], }); { @@ -1609,6 +1675,10 @@ impl AdjustPass { binding: 7, resource: wgpu::BindingResource::TextureView(&self.sample.no_sample_out), }, + wgpu::BindGroupEntry { + binding: 8, + resource: self.empty_profile.as_entire_binding(), + }, ], }); diff --git a/core/dr-gpu/src/demosaic.rs b/core/dr-gpu/src/demosaic.rs index 8a4eea3..5c87004 100644 --- a/core/dr-gpu/src/demosaic.rs +++ b/core/dr-gpu/src/demosaic.rs @@ -107,6 +107,11 @@ pub struct DemosaicedImage { height: u32, /// Carried through for the camera→sRGB transform in the adjust pass. color_matrix: [f32; 9], + /// TRACES: FR-DEV-3e + /// The camera profile's tables, carried through with the matrix for the + /// adjust pass to upload (D20). `None` for a JPEG and for a raw with no + /// profile. + profile_tables: Option>, /// As-shot white balance, the neutral starting point for the WB control. as_shot_wb: [f32; 3], /// Whether the texture holds gamma-encoded rather than linear values. @@ -207,6 +212,12 @@ impl DemosaicedImage { self.color_matrix } + /// TRACES: FR-DEV-3e + /// The camera profile's tables this source renders through, if any. + pub fn profile_tables(&self) -> Option<&std::sync::Arc> { + self.profile_tables.as_ref() + } + /// As-shot white balance multipliers, green-normalised. /// /// The white balance control is expressed *relative* to these, so its @@ -318,6 +329,7 @@ impl DemosaicedImage { width, height, color_matrix: IDENTITY_3X3, + profile_tables: None, as_shot_wb: [1.0, 1.0, 1.0], // **The identity, and this is the whole reason the field is here // rather than resolved further down.** A JPEG has already been @@ -478,6 +490,7 @@ impl DemosaicedImage { width, height, color_matrix: raw.color_matrix.unwrap_or(IDENTITY_3X3), + profile_tables: raw.profile_tables.clone(), as_shot_wb: [raw.wb_coeffs[0], raw.wb_coeffs[1], raw.wb_coeffs[2]], non_linear: false, id: next_image_id(), @@ -892,6 +905,7 @@ impl Demosaicer { // Identity where the body is uncalibrated: the image renders with // no colour transform rather than not at all. color_matrix: raw.color_matrix.unwrap_or(IDENTITY_3X3), + profile_tables: raw.profile_tables.clone(), as_shot_wb: [raw.wb_coeffs[0], raw.wb_coeffs[1], raw.wb_coeffs[2]], // Whatever the profile database had for this body (FR-DEV-3e), // resolved at decode because that is the only place the make and diff --git a/core/dr-gpu/tests/camera_profile.rs b/core/dr-gpu/tests/camera_profile.rs new file mode 100644 index 0000000..252da7f --- /dev/null +++ b/core/dr-gpu/tests/camera_profile.rs @@ -0,0 +1,249 @@ +//! TRACES: FR-DEV-3e +//! The camera profile's tables, end to end on a device (D20). +//! +//! `dr-pipeline` holds the lookup to the DNG SDK's algorithm on the CPU +//! (`ops::camera_profile::apply_reference`). Nothing there would notice a +//! shader that disagreed with it — a transposed constant matrix, an index +//! off by one column, a buffer bound in the wrong order — so this renders a +//! frame of 256 different colours through tables that move every one of them +//! a long way, and holds each pixel to the reference. +//! +//! The source is a linear three-sample frame, so the colours arrive exactly +//! as written with no demosaic between, and an identity stands in the view +//! transform's place so the readback is the scene colour, display-encoded. + +use std::sync::Arc; + +use dr_decode::{CfaPattern, CropRect, RawImage}; +use dr_gpu::{AdjustPass, Demosaicer, GpuContext}; +use dr_pipeline::descriptor::{Attribute, LocalizedKey, OpDescriptor, OpId, ParamId}; +use dr_pipeline::operation::{Operation, Stage, Uniform}; +use dr_pipeline::ops::camera_profile::{apply_reference, CameraProfile, APPLY, LOOK}; +use dr_types::{HueSatTable, ProfileOrigin, ProfileTables, Transfer}; + +const SIZE: u32 = 16; + +fn ctx() -> Option { + pollster::block_on(GpuContext::new_headless()).ok() +} + +/// An identity in the view transform's place. +struct IdentityView; + +impl Operation for IdentityView { + fn descriptor(&self) -> Arc { + Arc::new(OpDescriptor { + id: OpId("identity_view"), + label: LocalizedKey("identity_view"), + params: Vec::new(), + attributes: vec![Attribute::Tone], + }) + } + fn set_param(&mut self, _: ParamId, _: f32) {} + fn param(&self, _: ParamId) -> f32 { + 0.0 + } + fn is_active(&self) -> bool { + true + } + fn stage(&self) -> Stage { + Stage::View + } + fn renders(&self) -> bool { + true + } + fn wgsl_body(&self) -> String { + String::new() + } + fn uniforms(&self) -> Vec { + Vec::new() + } +} + +/// 256 colours across hue, saturation and value, kept under the prologue's +/// highlight desaturation and above black. +fn colours() -> Vec<[f32; 3]> { + (0..SIZE * SIZE) + .map(|i| { + let f = |k: u32| { + let x = (i.wrapping_mul(2_654_435_761).rotate_left(k * 7) >> 8) % 1000; + 0.04 + 0.86 * x as f32 / 1000.0 + }; + [f(1), f(2), f(3)] + }) + .collect() +} + +fn frame(tables: Option) -> RawImage { + let data = colours() + .iter() + .flat_map(|c| c.map(|v| (v * 65535.0).round() as u16)) + .collect(); + RawImage { + width: SIZE, + height: SIZE, + data, + cfa_pattern: CfaPattern::Rggb, + black_level: [0; 4], + white_level: u16::MAX, + wb_coeffs: [1.0, 1.0, 1.0, 1.0], + color_matrix: Some([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]), + samples_per_pixel: 3, + profile: None, + profile_tables: tables.map(Arc::new), + make: String::new(), + model: String::new(), + crop: CropRect { + x: 0, + y: 0, + width: SIZE, + height: SIZE, + }, + } +} + +/// Tables that move every colour by a different amount: hue shifts of tens +/// of degrees, saturation scales either side of one, and a 3-D, sRGB-indexed +/// look whose value scale varies down the value axis. +fn strong_tables() -> ProfileTables { + let (hd, sd) = (12u32, 5u32); + let hue_sat = (0..hd * sd) + .map(|i| { + let (h, s) = (i / sd, i % sd); + let a = h as f32 / hd as f32 * std::f32::consts::TAU; + [25.0 * a.sin(), 1.0 + 0.3 * a.cos() * s as f32 / 4.0, 1.0] + }) + .collect(); + let (lh, ls, lv) = (8u32, 4u32, 5u32); + let look = (0..lh * ls * lv) + .map(|i| { + let v = i / (lh * ls); + let h = (i / ls) % lh; + [ + -15.0 + 4.0 * h as f32, + 1.25 - 0.05 * v as f32, + 0.85 + 0.06 * v as f32, + ] + }) + .collect(); + let mut look = HueSatTable::new(lh, ls, lv, true, look).unwrap(); + look.srgb_encoded = true; + ProfileTables { + name: "strong".into(), + origin: ProfileOrigin::Embedded, + hue_sat: Some(HueSatTable::new(hd, sd, 1, false, hue_sat).unwrap()), + look: Some(look), + } +} + +fn render(ctx: &GpuContext, raw: &RawImage, op: CameraProfile) -> Vec<[u8; 3]> { + let source = Demosaicer::new(ctx) + .expect("demosaicer") + .run(raw) + .expect("upload"); + let ops: Vec> = vec![Box::new(op), Box::new(IdentityView)]; + let shader = dr_pipeline::compose(&ops); + let mut adjust = AdjustPass::new(ctx); + adjust.render(&source, &shader, SIZE, SIZE).expect("render"); + let (pixels, _, _) = adjust.export_pixels().expect("readback"); + pixels.chunks_exact(4).map(|p| [p[0], p[1], p[2]]).collect() +} + +fn encode(c: [f32; 3]) -> [i32; 3] { + c.map(|v| (Transfer::Srgb.encode(v.clamp(0.0, 1.0)) * 255.0).round() as i32) +} + +fn assert_agrees(got: &[[u8; 3]], expected: impl Fn([f32; 3]) -> [f32; 3], what: &str) { + let mut moved = 0; + for (i, (c, g)) in colours().into_iter().zip(got).enumerate() { + let want = encode(expected(c)); + let g = g.map(i32::from); + // Two 8-bit steps: the half-float source and intermediate, and the + // rounding either side of the encode. + assert!( + want.iter().zip(g).all(|(w, g)| (w - g).abs() <= 2), + "{what}: pixel {i} {c:?} rendered {g:?}, the reference says {want:?}" + ); + if want != encode(c) { + moved += 1; + } + } + assert!( + moved > 200, + "{what}: only {moved} of 256 colours moved; the test proves little" + ); +} + +#[test] +fn the_shader_agrees_with_the_cpu_reference() { + let Some(ctx) = ctx() else { + eprintln!("skipping: no GPU adapter"); + return; + }; + let tables = strong_tables(); + let got = render(&ctx, &frame(Some(tables.clone())), CameraProfile::new()); + assert_agrees(&got, |c| apply_reference(&tables, c, 1.0), "at defaults"); + + let mut doubled = CameraProfile::new(); + doubled.set_param(LOOK, 200.0); + let got = render(&ctx, &frame(Some(tables.clone())), doubled); + assert_agrees(&got, |c| apply_reference(&tables, c, 2.0), "look at 200%"); +} + +#[test] +fn switched_off_or_absent_the_render_is_unchanged() { + let Some(ctx) = ctx() else { + eprintln!("skipping: no GPU adapter"); + return; + }; + let bare = render(&ctx, &frame(None), CameraProfile::new()); + let mut off = CameraProfile::new(); + off.set_param(APPLY, 0.0); + let switched_off = render(&ctx, &frame(Some(strong_tables())), off); + assert_eq!(bare, switched_off, "the switch off is the matrix alone"); + // Against the source colours, one 8-bit step for the half-float texture + // the source is uploaded in; the exact comparison is the one above. + for (c, g) in colours().into_iter().zip(&bare) { + let want = encode(c); + assert!( + want.iter() + .zip(g) + .all(|(w, g)| (w - i32::from(*g)).abs() <= 1), + "no tables, no change: {c:?} rendered {g:?}" + ); + } +} + +#[test] +fn the_libraries_adobe_standard_renders_as_the_reference_does() { + // The real tables, when the library's 6D DNG is on this machine: a 90×30 + // HueSatMap and a 36×8×16 LookTable, at the sizes no synthetic test + // reaches. + let Some(ctx) = ctx() else { + eprintln!("skipping: no GPU adapter"); + return; + }; + let path = std::env::var_os("DR_DCP_SAMPLE") + .map(std::path::PathBuf::from) + .or_else(|| { + std::env::var_os("HOME").map(|h| { + std::path::PathBuf::from(h).join("Nextcloud/PhotosRaw/2017/2017-08-12/_MG_9080.dng") + }) + }); + let Some(bytes) = path.and_then(|p| std::fs::read(p).ok()) else { + eprintln!("skipping: no sample DNG"); + return; + }; + let tables = dr_decode::dcp::embedded_in(&bytes) + .expect("Adobe Standard") + .tables(5000.0, ProfileOrigin::Embedded); + let got = render(&ctx, &frame(Some(tables.clone())), CameraProfile::new()); + for (i, (c, g)) in colours().into_iter().zip(&got).enumerate() { + let want = encode(apply_reference(&tables, c, 1.0)); + let g = g.map(i32::from); + assert!( + want.iter().zip(g).all(|(w, g)| (w - g).abs() <= 2), + "pixel {i} {c:?} rendered {g:?}, the reference says {want:?}" + ); + } +} diff --git a/core/dr-pipeline/ops/camera_profile.yaml b/core/dr-pipeline/ops/camera_profile.yaml new file mode 100644 index 0000000..9c8d1a4 --- /dev/null +++ b/core/dr-pipeline/ops/camera_profile.yaml @@ -0,0 +1,19 @@ +id: camera_profile +order: 25 +# A `rust:` node publishes its own descriptor; its attributes are on the type +# in `../src/ops/camera_profile.rs`. +rust: CameraProfile + +why_rust: | + It reads the source's profile tables from a storage buffer no declaration can + name, and it is composed at its defaults — a raw whose profile is on is + rendered through it without the photographer having touched anything — + which a declared node cannot say (D20). + +placement: | + After exposure, before contrast (D20, camera-profiles.md §3). Hue and + saturation do not change under the uniform gains before it, so a 2.5-D + HueSatMap gives the same answer here as straight after the matrix; and the + LookTable sees the exposure the photographer chose, as the DNG SDK's does. + Contrast, tone and the colour controls then act on the profiled colour, as + they do in Camera Raw. diff --git a/core/dr-pipeline/src/graph.rs b/core/dr-pipeline/src/graph.rs index b2c478e..2dca41f 100644 --- a/core/dr-pipeline/src/graph.rs +++ b/core/dr-pipeline/src/graph.rs @@ -1170,19 +1170,21 @@ mod tests { // Opening an unedited image must produce the image, not an // interpretation of it. // - // One block, and it is the view transform: a view operation is - // composed at its defaults, because a photograph with no view - // transform is a scan rather than a picture (FR-DEV-3j). It is still - // neutral in the sense that matters here — nothing moved, nothing is - // written — and every adjustment is absent. + // Two blocks, the view transform and the camera profile: both are + // composed at their defaults, because a photograph with no view + // transform is a scan rather than a picture (FR-DEV-3j) and a raw + // with a profile is rendered through it (D20). They are still neutral + // in the sense that matters here — nothing moved, nothing is written + // — and every adjustment is absent. let g = EditGraph::default_chain(); assert!(g.is_neutral()); let source = g.compose().source; assert_eq!( source.matches("---- ").count(), - 1, + 2, "a neutral graph must generate no adjustment blocks" ); + assert!(source.contains("---- camera_profile ----")); assert!(source.contains("---- view_transform ----")); } @@ -1263,13 +1265,14 @@ mod tests { fn only_active_operations_reach_the_shader() { // The composition property, end to end: two adjustments out of seven // available must generate a shader doing exactly two things — and - // the view transform, which every render has (FR-DEV-3j). + // the view transform and camera profile, which every render has + // (FR-DEV-3j, D20). let mut g = EditGraph::default_chain(); g.set_param(exposure::ID, exposure::EXPOSURE, 1.0); g.set_param(white_balance::ID, white_balance::TINT, 25.0); let shader = g.compose(); - assert_eq!(shader.source.matches("---- ").count(), 3); + assert_eq!(shader.source.matches("---- ").count(), 4); assert!(shader.source.contains("---- view_transform ----")); assert!(shader.source.contains("---- exposure ----")); assert!(shader.source.contains("---- white_balance ----")); diff --git a/core/dr-pipeline/src/lib.rs b/core/dr-pipeline/src/lib.rs index cd17ad7..44ad5e9 100644 --- a/core/dr-pipeline/src/lib.rs +++ b/core/dr-pipeline/src/lib.rs @@ -115,6 +115,16 @@ mod tests { } } + // Flipping every switch turns the camera profile *off*, which is + // active — moved from the default — and composes nothing. Put it + // back on; its look strength stays moved, so it is still active and + // now doing something, which is what "fully active" means here (D20). + g.set_param( + crate::ops::camera_profile::ID, + crate::ops::camera_profile::APPLY, + 1.0, + ); + // `film_sim` is the one node a moved parameter cannot activate: it // needs a stock's measured tables, which are not parameters and which // no slider produces. So it is loaded explicitly here. diff --git a/core/dr-pipeline/src/operation.rs b/core/dr-pipeline/src/operation.rs index ebcb2a7..9717b26 100644 --- a/core/dr-pipeline/src/operation.rs +++ b/core/dr-pipeline/src/operation.rs @@ -270,6 +270,19 @@ pub trait Operation: Send + Sync { /// what is actually used. fn is_active(&self) -> bool; + /// TRACES: FR-DEV-3e + /// Whether the composer emits this operation's fragment. + /// + /// Default: exactly when it [`Self::is_active`]. The exception is an + /// operation that *is* part of the rendering at its defaults — the + /// camera profile, which an untouched raw is rendered through (D20) — + /// where "moved from the defaults" and "does something" come apart. Such + /// an operation keeps `is_active` meaning the former, so a sidecar still + /// stores nothing for it, and answers this with the latter. + fn composes(&self) -> bool { + self.is_active() + } + /// The WGSL body of this operation's transform. /// /// Receives `c` (a `vec3` of linear RGB) and must produce the @@ -843,7 +856,7 @@ fn compose_inner( let active: Vec<&dyn Operation> = ops .iter() .map(|o| o.as_ref()) - .filter(|o| o.is_active() && o.detail().is_none()) + .filter(|o| o.composes() && o.detail().is_none()) .collect(); // Whether a detail stage follows. If one does, this pass stops short of @@ -1040,7 +1053,7 @@ fn compose_inner( let local: Vec<&crate::mask::LocalOp> = layers.ops.iter().filter(|l| l.op == id).collect(); // The global side of the blend. A view operation always has one; see // `Stage::View`. - let global = op.is_active() || op.stage() == Stage::View; + let global = op.composes() || op.stage() == Stage::View; if !global && local.is_empty() { continue; } @@ -1333,6 +1346,11 @@ struct Params {{ // bound to 1x1 placeholders whenever the flags say not to touch them. @group(0) @binding(6) var sampled: texture_2d; @group(0) @binding(7) var sample_out: texture_storage_2d; +// The source's camera profile tables (FR-DEV-3e, D20): a two-entry header, +// then the entries (`ops::camera_profile::profile_buffer`). Declared +// unconditionally like the masks, and bound to a header of zeros — no +// tables — for every source without a profile. +@group(0) @binding(8) var profile_table: array>; {WINDOW_HELPER}{sampler_helper}{helper_src}{encode_output} // Display-encoded sRGB back to linear, for sources that arrive that way. diff --git a/core/dr-pipeline/src/ops/camera_profile.rs b/core/dr-pipeline/src/ops/camera_profile.rs new file mode 100644 index 0000000..d0e11c1 --- /dev/null +++ b/core/dr-pipeline/src/ops/camera_profile.rs @@ -0,0 +1,678 @@ +//! TRACES: FR-DEV-3e +//! The camera profile's tables as an operation (D20). +//! +//! The matrix turns camera RGB into colour; a DNG camera profile adds two +//! lookups over hue, saturation and value on top of it — the `HueSatMap`, a +//! calibration, and the `LookTable`, a rendering intent. This operation +//! applies them. `docs/dev/camera-profiles.md` is the design. +//! +//! # Where the tables come from +//! +//! Not from here. They belong to the *source*, like the matrix: `dr-decode` +//! resolves them per file and `dr-gpu` uploads them to the storage buffer +//! every generated shader declares at `@binding(8)`, laid out by +//! [`profile_buffer`]. This operation holds only the photographer's two +//! settings — whether to use the profile, and how strongly to apply its look +//! — so a render path never has to remember to hand it anything. +//! +//! # Why it is composed at its defaults +//! +//! A profile that is on is the rendering, not an edit: an untouched raw +//! renders through it and writes no parameters. So [`Operation::composes`] +//! answers "is the switch on", not "has anything moved". The fragment then +//! branches on the buffer's header, which says whether this source has tables +//! at all; a JPEG, or a raw with no profile, reads two zeros and passes +//! through. +//! +//! # The lookup +//! +//! The DNG SDK's `RefBaselineHueSatMap`, with the two departures §2 of the +//! design gives for scene-referred values: value is not clamped on the way +//! out, and a colour with a negative ProPhoto component passes through. +//! [`apply_reference`] is the same arithmetic on the CPU, and the GPU tests +//! hold the shader to it. + +use std::sync::{Arc, LazyLock}; + +use dr_types::{HueSatTable, ProfileTables}; + +use crate::descriptor::{ + Attribute, LocalizedKey, OpDescriptor, OpId, ParamDescriptor, ParamId, Scale, Unit, +}; +use crate::operation::{Helper, Operation, Uniform}; + +pub const ID: OpId = OpId("camera_profile"); +pub const APPLY: ParamId = ParamId("apply"); +pub const LOOK: ParamId = ParamId("look"); + +/// The look's strength at which the LookTable is applied as the profile +/// states it, in percent. +pub const DEFAULT_LOOK: f32 = 100.0; +/// Twice the profile's look: Lightroom's *Amount* reaches the same. +pub const MAX_LOOK: f32 = 200.0; + +/// Entries of the buffer's header: one `vec4` describing each table — +/// `(hue divisions, saturation divisions, value divisions, sRGB-encoded)`, +/// zero hue divisions meaning absent — before the entries themselves. +pub const HEADER_ENTRIES: usize = 2; + +static DESCRIPTOR: LazyLock> = LazyLock::new(|| { + Arc::new(OpDescriptor { + attributes: vec![Attribute::Colour], + id: ID, + label: LocalizedKey("op.camera_profile"), + params: vec![ + ParamDescriptor::switch_on("apply", "param.camera_profile.apply"), + ParamDescriptor::scalar( + "look", + "param.camera_profile.look", + 0.0, + MAX_LOOK, + DEFAULT_LOOK, + Unit::Percent, + Scale::Linear, + 0, + ), + ], + }) +}); + +/// Linear sRGB (the working space) to linear ProPhoto, and back, row-major, +/// each row scaled to sum to one so that working white is ProPhoto white +/// exactly and a neutral reaches the tables with zero saturation. +fn working_prophoto() -> &'static ([f32; 9], [f32; 9]) { + static M: LazyLock<([f32; 9], [f32; 9])> = LazyLock::new(|| { + let to = normalise_rows(dr_types::ColourSpace::ProPhoto.from_linear_srgb()); + let back = normalise_rows(invert(&to).expect("ProPhoto's matrix is invertible")); + (to, back) + }); + &M +} + +fn normalise_rows(mut m: [f32; 9]) -> [f32; 9] { + for row in m.chunks_exact_mut(3) { + let sum: f32 = row.iter().sum(); + row.iter_mut().for_each(|v| *v /= sum); + } + m +} + +fn invert(m: &[f32; 9]) -> Option<[f32; 9]> { + let [a, b, c, d, e, f, g, h, i] = m.map(f64::from); + let det = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g); + if det.abs() < 1e-12 { + return None; + } + let inv = [ + (e * i - f * h) / det, + (c * h - b * i) / det, + (b * f - c * e) / det, + (f * g - d * i) / det, + (a * i - c * g) / det, + (c * d - a * f) / det, + (d * h - e * g) / det, + (b * g - a * h) / det, + (a * e - b * d) / det, + ]; + Some(inv.map(|v| v as f32)) +} + +fn mul(m: &[f32; 9], c: [f32; 3]) -> [f32; 3] { + std::array::from_fn(|r| m[r * 3] * c[0] + m[r * 3 + 1] * c[1] + m[r * 3 + 2] * c[2]) +} + +/// A row-major matrix as a WGSL `mat3x3`, whose constructor takes columns. +fn wgsl_mat(m: &[f32; 9]) -> String { + let col = |j: usize| format!("vec3({:e}, {:e}, {:e})", m[j], m[3 + j], m[6 + j]); + format!("mat3x3({}, {}, {})", col(0), col(1), col(2)) +} + +static HELPERS: LazyLock<[Helper; 1]> = LazyLock::new(|| { + let (to, back) = working_prophoto(); + let source = format!( + "const PROFILE_FROM_WORKING = {};\nconst PROFILE_TO_WORKING = {};\n{LOOKUP_WGSL}", + wgsl_mat(to), + wgsl_mat(back) + ); + [Helper { + name: "profile_apply", + source: Box::leak(source.into_boxed_str()), + }] +}); + +/// The lookup, in WGSL. Mirrors [`apply_reference`] line for line. +const LOOKUP_WGSL: &str = r#" +fn profile_srgb_encode(v: f32) -> f32 { + if (v <= 0.0031308) { return v * 12.92; } + return 1.055 * pow(v, 1.0 / 2.4) - 0.055; +} + +fn profile_srgb_decode(v: f32) -> f32 { + if (v <= 0.04045) { return v / 12.92; } + return pow((v + 0.055) / 1.055, 2.4); +} + +// The DNG SDK's HSV: hue in [0, 6), saturation (max - min) / max, value max. +fn profile_rgb_to_hsv(c: vec3) -> vec3 { + let v = max(c.r, max(c.g, c.b)); + let gap = v - min(c.r, min(c.g, c.b)); + if (gap <= 0.0) { + return vec3(0.0, 0.0, v); + } + var h: f32; + if (c.r == v) { + h = (c.g - c.b) / gap; + if (h < 0.0) { h += 6.0; } + } else if (c.g == v) { + h = 2.0 + (c.b - c.r) / gap; + } else { + h = 4.0 + (c.r - c.g) / gap; + } + return vec3(h, gap / v, v); +} + +fn profile_hsv_to_rgb(hsv: vec3) -> vec3 { + let s = hsv.y; + let v = hsv.z; + if (s <= 0.0) { + return vec3(v); + } + let h = hsv.x - 6.0 * floor(hsv.x / 6.0); + let i = min(floor(h), 5.0); + let f = h - i; + let p = v * (1.0 - s); + let q = v * (1.0 - s * f); + let t = v * (1.0 - s * (1.0 - f)); + switch (i32(i)) { + case 0: { return vec3(v, t, p); } + case 1: { return vec3(q, v, p); } + case 2: { return vec3(p, v, t); } + case 3: { return vec3(p, q, v); } + case 4: { return vec3(t, p, v); } + default: { return vec3(v, p, q); } + } +} + +fn profile_entry(base: u32, at: u32) -> vec3 { + return profile_table[base + at].xyz; +} + +// (hue shift in degrees, saturation scale, value scale) at `hsv`: bilinear +// over hue and saturation, hue wrapping, and linear over value for a 3-D +// table. Indices are the SDK's. +fn profile_lookup(dims: vec4, base: u32, hsv: vec3) -> vec3 { + let hd = u32(dims.x); + let sd = u32(dims.y); + let vd = u32(dims.z); + + var h0 = 0u; + var h1 = 0u; + var hf = 0.0; + if (hd > 1u) { + let hs = hsv.x * f32(hd) / 6.0; + h0 = min(u32(hs), hd - 1u); + hf = hs - f32(h0); + h1 = h0 + 1u; + if (h1 >= hd) { h1 = 0u; } + } + + let ss = hsv.y * f32(sd - 1u); + let s0 = min(u32(ss), sd - 2u); + let sf = ss - f32(s0); + + var v0 = 0u; + var vf = 0.0; + if (vd > 1u) { + var ve = clamp(hsv.z, 0.0, 1.0); + if (dims.w > 0.5) { ve = profile_srgb_encode(ve); } + let vs = ve * f32(vd - 1u); + v0 = min(u32(vs), vd - 2u); + vf = vs - f32(v0); + } + + let val_step = hd * sd; + let lo = v0 * val_step; + var d = mix( + mix(profile_entry(base, lo + h0 * sd + s0), profile_entry(base, lo + h1 * sd + s0), hf), + mix(profile_entry(base, lo + h0 * sd + s0 + 1u), profile_entry(base, lo + h1 * sd + s0 + 1u), hf), + sf); + if (vd > 1u) { + let hi = lo + val_step; + let e = mix( + mix(profile_entry(base, hi + h0 * sd + s0), profile_entry(base, hi + h1 * sd + s0), hf), + mix(profile_entry(base, hi + h0 * sd + s0 + 1u), profile_entry(base, hi + h1 * sd + s0 + 1u), hf), + sf); + d = mix(d, e, vf); + } + return d; +} + +// One table applied to a ProPhoto colour, its deltas scaled by `amount`. +fn profile_apply(dims: vec4, base: u32, c: vec3, amount: f32) -> vec3 { + let hsv = profile_rgb_to_hsv(c); + var d = profile_lookup(dims, base, hsv); + d = vec3(d.x * amount, max(1.0 + (d.y - 1.0) * amount, 0.0), max(1.0 + (d.z - 1.0) * amount, 0.0)); + let h = hsv.x + d.x * (6.0 / 360.0); + let s = min(hsv.y * d.y, 1.0); + var v = hsv.z * d.z; + if (dims.w > 0.5) { + // The scale is defined on the encoded value; applied as the ratio it + // makes at min(v, 1), so a value above 1.0 is scaled, not clipped. + let vc = min(hsv.z, 1.0); + v = hsv.z; + if (vc > 0.0) { + v = hsv.z * profile_srgb_decode(profile_srgb_encode(vc) * d.z) / vc; + } + } + return profile_hsv_to_rgb(vec3(h, s, v)); +} +"#; + +#[derive(Debug, Clone)] +pub struct CameraProfile { + apply: bool, + look: f32, +} + +impl Default for CameraProfile { + fn default() -> Self { + Self { + apply: true, + look: DEFAULT_LOOK, + } + } +} + +impl CameraProfile { + pub fn new() -> Self { + Self::default() + } +} + +impl Operation for CameraProfile { + fn descriptor(&self) -> Arc { + DESCRIPTOR.clone() + } + + fn set_param(&mut self, id: ParamId, value: f32) { + match id { + APPLY => self.apply = value != 0.0, + LOOK => self.look = value, + _ => log::warn!("camera_profile: unknown parameter {id}"), + } + } + + fn param(&self, id: ParamId) -> f32 { + match id { + APPLY => f32::from(u8::from(self.apply)), + LOOK => self.look, + _ => 0.0, + } + } + + fn is_active(&self) -> bool { + !self.apply || self.look != DEFAULT_LOOK + } + + fn composes(&self) -> bool { + self.apply + } + + fn wgsl_body(&self) -> String { + "\ +let hue_sat_dims = profile_table[0]; +let look_dims = profile_table[1]; +if (hue_sat_dims.x > 0.0 || look_dims.x > 0.0) { + var p = PROFILE_FROM_WORKING * c; + // A colour outside ProPhoto has no HSV the tables were made for; it + // passes through rather than being floored, which would clip it (D19). + if (min(p.r, min(p.g, p.b)) >= 0.0) { + let look_base = 2u + u32(hue_sat_dims.x * hue_sat_dims.y * hue_sat_dims.z); + if (hue_sat_dims.x > 0.0) { + p = profile_apply(hue_sat_dims, 2u, p, 1.0); + } + if (look_dims.x > 0.0 && look > 0.0) { + p = profile_apply(look_dims, look_base, p, look); + } + c = PROFILE_TO_WORKING * p; + } +}" + .into() + } + + fn uniforms(&self) -> Vec { + vec![Uniform { + name: "look", + value: self.look / 100.0, + }] + } + + fn helpers(&self) -> &[Helper] { + HELPERS.as_slice() + } +} + +/// TRACES: FR-DEV-3e +/// The storage buffer a source's tables are uploaded as: the two header +/// `vec4`s, the HueSatMap's entries, then the LookTable's, each entry +/// `(hue shift, saturation scale, value scale, 0)`. +/// +/// Two zero `vec4`s where there are no tables — the placeholder every source +/// without a profile binds, and what makes the fragment pass through. +pub fn profile_buffer(tables: Option<&ProfileTables>) -> Vec<[f32; 4]> { + let header = |t: Option<&HueSatTable>| match t { + Some(t) => [ + t.hue_divisions as f32, + t.sat_divisions as f32, + t.val_divisions as f32, + if t.srgb_encoded { 1.0 } else { 0.0 }, + ], + None => [0.0; 4], + }; + let hue_sat = tables.and_then(|t| t.hue_sat.as_ref()); + let look = tables.and_then(|t| t.look.as_ref()); + let mut out = vec![header(hue_sat), header(look)]; + for t in [hue_sat, look].into_iter().flatten() { + out.extend(t.entries.iter().map(|e| [e[0], e[1], e[2], 0.0])); + } + out +} + +/// TRACES: FR-DEV-3e +/// The fragment's arithmetic on the CPU: a working-space colour through the +/// source's tables, the look at `look` (1.0 = as the profile states it). +/// +/// The reference the shader is tested against, and the statement of the +/// algorithm a reader can step through. +pub fn apply_reference(tables: &ProfileTables, c: [f32; 3], look: f32) -> [f32; 3] { + let (to, back) = working_prophoto(); + let mut p = mul(to, c); + if p.iter().any(|v| *v < 0.0) { + return c; + } + if let Some(t) = &tables.hue_sat { + p = apply_table(t, p, 1.0); + } + if let Some(t) = tables.look.as_ref().filter(|_| look > 0.0) { + p = apply_table(t, p, look); + } + mul(back, p) +} + +fn srgb_encode(v: f32) -> f32 { + if v <= 0.003_130_8 { + v * 12.92 + } else { + 1.055 * v.powf(1.0 / 2.4) - 0.055 + } +} + +fn srgb_decode(v: f32) -> f32 { + if v <= 0.040_45 { + v / 12.92 + } else { + ((v + 0.055) / 1.055).powf(2.4) + } +} + +/// The SDK's `DNG_RGBtoHSV`: hue in `[0, 6)`. +pub fn rgb_to_hsv([r, g, b]: [f32; 3]) -> [f32; 3] { + let v = r.max(g).max(b); + let gap = v - r.min(g).min(b); + if gap <= 0.0 { + return [0.0, 0.0, v]; + } + let h = if r == v { + let h = (g - b) / gap; + if h < 0.0 { + h + 6.0 + } else { + h + } + } else if g == v { + 2.0 + (b - r) / gap + } else { + 4.0 + (r - g) / gap + }; + [h, gap / v, v] +} + +pub fn hsv_to_rgb([h, s, v]: [f32; 3]) -> [f32; 3] { + if s <= 0.0 { + return [v; 3]; + } + let h = h - 6.0 * (h / 6.0).floor(); + let i = h.floor().min(5.0); + let f = h - i; + let p = v * (1.0 - s); + let q = v * (1.0 - s * f); + let t = v * (1.0 - s * (1.0 - f)); + match i as i32 { + 0 => [v, t, p], + 1 => [q, v, p], + 2 => [p, v, t], + 3 => [p, q, v], + 4 => [t, p, v], + _ => [v, p, q], + } +} + +fn lookup(t: &HueSatTable, [h, s, v]: [f32; 3]) -> [f32; 3] { + let (hd, sd, vd) = (t.hue_divisions, t.sat_divisions, t.val_divisions); + let (mut h0, mut h1, mut hf) = (0u32, 0u32, 0.0f32); + if hd > 1 { + let hs = h * hd as f32 / 6.0; + h0 = (hs as u32).min(hd - 1); + hf = hs - h0 as f32; + h1 = if h0 + 1 >= hd { 0 } else { h0 + 1 }; + } + let ss = s * (sd - 1) as f32; + let s0 = (ss as u32).min(sd - 2); + let sf = ss - s0 as f32; + let (mut v0, mut vf) = (0u32, 0.0f32); + if vd > 1 { + let mut ve = v.clamp(0.0, 1.0); + if t.srgb_encoded { + ve = srgb_encode(ve); + } + let vs = ve * (vd - 1) as f32; + v0 = (vs as u32).min(vd - 2); + vf = vs - v0 as f32; + } + let mix = |a: [f32; 3], b: [f32; 3], w: f32| -> [f32; 3] { + std::array::from_fn(|i| a[i] + (b[i] - a[i]) * w) + }; + let at = |v: u32, h: u32, s: u32| t.entries[t.index(h, s, v)]; + let plane = |v: u32| { + mix( + mix(at(v, h0, s0), at(v, h1, s0), hf), + mix(at(v, h0, s0 + 1), at(v, h1, s0 + 1), hf), + sf, + ) + }; + let d = plane(v0); + if vd > 1 { + mix(d, plane(v0 + 1), vf) + } else { + d + } +} + +fn apply_table(t: &HueSatTable, c: [f32; 3], amount: f32) -> [f32; 3] { + let hsv = rgb_to_hsv(c); + let d = lookup(t, hsv); + let d = [ + d[0] * amount, + (1.0 + (d[1] - 1.0) * amount).max(0.0), + (1.0 + (d[2] - 1.0) * amount).max(0.0), + ]; + let h = hsv[0] + d[0] * (6.0 / 360.0); + let s = (hsv[1] * d[1]).min(1.0); + let v = if t.srgb_encoded { + let vc = hsv[2].min(1.0); + if vc > 0.0 { + hsv[2] * srgb_decode(srgb_encode(vc) * d[2]) / vc + } else { + hsv[2] + } + } else { + hsv[2] * d[2] + }; + hsv_to_rgb([h, s, v]) +} + +#[cfg(test)] +mod tests { + use super::*; + use dr_types::ProfileOrigin; + + fn uniform(h: u32, s: u32, v: u32, e: [f32; 3]) -> HueSatTable { + HueSatTable::new(h, s, v, false, vec![e; (h * s * v) as usize]).unwrap() + } + + fn tables(hue_sat: Option, look: Option) -> ProfileTables { + ProfileTables { + name: "test".into(), + origin: ProfileOrigin::Embedded, + hue_sat, + look, + } + } + + fn close(a: [f32; 3], b: [f32; 3], tol: f32) -> bool { + a.iter() + .zip(b) + .all(|(x, y)| (x - y).abs() <= tol * y.abs().max(1.0)) + } + + #[test] + fn it_starts_neutral_and_composed() { + let op = CameraProfile::new(); + assert!(!op.is_active(), "an untouched photograph writes nothing"); + assert!(op.composes(), "and still renders through its profile"); + let mut off = CameraProfile::new(); + off.set_param(APPLY, 0.0); + assert!(off.is_active() && !off.composes()); + } + + #[test] + fn the_working_space_round_trips_through_prophoto() { + let (to, back) = working_prophoto(); + for c in [[1.0, 1.0, 1.0], [0.2, 0.5, 0.1], [4.0, 0.3, 0.02]] { + assert!(close(mul(back, mul(to, c)), c, 1e-5), "{c:?}"); + } + let white = mul(to, [1.0; 3]); + assert!(white.iter().all(|v| (v - 1.0).abs() < 1e-6), "{white:?}"); + } + + #[test] + fn hsv_round_trips() { + for c in [ + [0.9, 0.2, 0.1], + [0.1, 0.7, 0.3], + [0.2, 0.3, 0.8], + [0.5, 0.5, 0.5], + [3.0, 1.0, 2.0], + ] { + assert!(close(hsv_to_rgb(rgb_to_hsv(c)), c, 1e-6), "{c:?}"); + } + } + + #[test] + fn grey_passes_through() { + let t = tables( + Some(uniform(6, 3, 1, [30.0, 1.5, 1.0])), + Some(uniform(6, 3, 1, [-20.0, 1.3, 1.0])), + ); + for v in [0.0, 0.18, 1.0, 8.0] { + let out = apply_reference(&t, [v; 3], 1.0); + assert!(close(out, [v; 3], 1e-5), "{v}: {out:?}"); + } + } + + #[test] + fn an_identity_table_changes_nothing() { + let t = tables( + Some(uniform(90, 30, 1, [0.0, 1.0, 1.0])), + Some(uniform(36, 8, 16, [0.0, 1.0, 1.0])), + ); + for c in [[0.9, 0.2, 0.1], [0.05, 0.4, 0.2], [2.0, 0.5, 0.3]] { + assert!(close(apply_reference(&t, c, 1.0), c, 1e-5), "{c:?}"); + } + } + + #[test] + fn a_saturation_scale_scales_saturation() { + let t = tables(Some(uniform(6, 3, 1, [0.0, 1.2, 1.0])), None); + let (to, _) = working_prophoto(); + let c = [0.6, 0.3, 0.2]; + let before = rgb_to_hsv(mul(to, c)); + let after = rgb_to_hsv(mul(to, apply_reference(&t, c, 1.0))); + assert!( + (after[1] - before[1] * 1.2).abs() < 1e-4, + "{before:?} {after:?}" + ); + assert!((after[0] - before[0]).abs() < 1e-4); + assert!((after[2] - before[2]).abs() < 1e-4); + } + + #[test] + fn hue_interpolation_wraps_from_the_last_column_to_the_first() { + // Four hue columns: a shift only in the first. A hue just short of + // 6.0 (red, from the magenta side) sits between the last column and + // the first, and must take most of the first's shift. + let mut e = vec![[0.0, 1.0, 1.0]; 4 * 2]; + e[0] = [40.0, 1.0, 1.0]; + e[1] = [40.0, 1.0, 1.0]; + let t = HueSatTable::new(4, 2, 1, false, e).unwrap(); + let d = lookup(&t, [5.9, 0.5, 0.5]); + assert!(d[0] > 30.0, "{d:?}"); + // Columns sit at hue 0, 1.5, 3 and 4.5; between the third and the + // fourth, neither of which shifts, nothing moves. + let d = lookup(&t, [3.7, 0.5, 0.5]); + assert!(d[0].abs() < 1e-6, "{d:?}"); + } + + #[test] + fn a_value_above_one_stays_above_one() { + let t = tables(None, Some(uniform(6, 3, 4, [5.0, 1.1, 0.9]))); + let out = apply_reference(&t, [6.0, 3.0, 2.0], 1.0); + assert!(out.iter().any(|v| *v > 1.0), "{out:?}"); + let mut srgb = uniform(6, 3, 4, [0.0, 1.0, 0.9]); + srgb.srgb_encoded = true; + let out = apply_reference(&tables(None, Some(srgb)), [6.0, 3.0, 2.0], 1.0); + assert!(out.iter().all(|v| v.is_finite()) && out[0] > 1.0, "{out:?}"); + } + + #[test] + fn the_look_strength_scales_the_look_alone() { + let hs = uniform(6, 3, 1, [0.0, 1.1, 1.0]); + let look = uniform(6, 3, 1, [0.0, 1.2, 1.0]); + let t = tables(Some(hs.clone()), Some(look)); + let c = [0.5, 0.3, 0.2]; + let none = apply_reference(&t, c, 0.0); + assert!(close( + none, + apply_reference(&tables(Some(hs), None), c, 1.0), + 1e-6 + )); + let (to, _) = working_prophoto(); + let s = |x| rgb_to_hsv(mul(to, x))[1]; + assert!(s(apply_reference(&t, c, 2.0)) > s(apply_reference(&t, c, 1.0))); + } + + #[test] + fn the_buffer_puts_the_header_first_and_the_look_after_the_hue_sat_map() { + assert_eq!(profile_buffer(None), vec![[0.0; 4]; 2]); + let t = tables( + Some(uniform(2, 2, 1, [1.0, 2.0, 3.0])), + Some(uniform(3, 2, 2, [4.0, 5.0, 6.0])), + ); + let b = profile_buffer(Some(&t)); + assert_eq!(b[0], [2.0, 2.0, 1.0, 0.0]); + assert_eq!(b[1], [3.0, 2.0, 2.0, 0.0]); + assert_eq!(b.len(), HEADER_ENTRIES + 4 + 12); + assert_eq!(b[2], [1.0, 2.0, 3.0, 0.0]); + assert_eq!(b[HEADER_ENTRIES + 4], [4.0, 5.0, 6.0, 0.0]); + } +} diff --git a/core/dr-pipeline/src/ops/mod.rs b/core/dr-pipeline/src/ops/mod.rs index 157fa6e..2d8646d 100644 --- a/core/dr-pipeline/src/ops/mod.rs +++ b/core/dr-pipeline/src/ops/mod.rs @@ -66,6 +66,7 @@ // Hand-written nodes. Each is listed in `ops/` with `rust:`, which is what // places it in the chain; these are the implementations that entry points at. pub mod aberration; +pub mod camera_profile; pub mod capture_sharpen; pub mod colour_mixer; pub mod curve; @@ -78,6 +79,7 @@ pub mod view_transform; pub mod vignetting; pub use aberration::Aberration; +pub use camera_profile::CameraProfile; pub use capture_sharpen::CaptureSharpen; pub use colour_mixer::ColourMixer; pub use curve::ToneCurve; diff --git a/core/dr-pipeline/tests/declared_parity.rs b/core/dr-pipeline/tests/declared_parity.rs index 5bdafe0..10e15ed 100644 --- a/core/dr-pipeline/tests/declared_parity.rs +++ b/core/dr-pipeline/tests/declared_parity.rs @@ -33,7 +33,7 @@ //! //! A `rust:` node — `tone_curve`, `colour_mixer`, `film_sim`, //! `capture_sharpen`, `noise_reduction`, `clarity`, `texture`, `dehaze`, -//! `view_transform` — +//! `view_transform`, `camera_profile` — //! names a hand-written type and has no declaration to interpret. It is not skipped //! silently: [`every_declared_node_is_checked`] asserts the two sets partition //! `ops/` between them, so a node that stops being declared cannot quietly @@ -396,6 +396,7 @@ fn every_declared_node_is_checked() { assert_eq!( hand, [ + "camera_profile", "capture_sharpen", "clarity", "colour_mixer", diff --git a/docs/dev/camera-profiles.md b/docs/dev/camera-profiles.md index e9db324..75b2590 100644 --- a/docs/dev/camera-profiles.md +++ b/docs/dev/camera-profiles.md @@ -95,13 +95,13 @@ that differed from the screen would be the result. ### 3.1 The two constants -`P = row-normalise(XYZ→sRGB · Bradford(D50→D65) · ProPhoto→XYZ(D50))` takes ProPhoto to the -working space; the fragment uses `P⁻¹` going in and `P` coming out. These are the same constants -`forward_to_srgb` composes for the forward-matrix route, so for a profile with forward matrices the -round trip is exact: the working colour is `P · FM`-space colour and `P⁻¹` recovers the SDK's -ProPhoto. Row normalisation keeps working-space white at ProPhoto white, so a neutral stays at -`s = 0`. For the colour-matrix route, `P⁻¹` gives the ProPhoto rendering of the same colour, which -is what the SDK derives too. +`P⁻¹` is `ColourSpace::ProPhoto.from_linear_srgb()` — the conversion `dr-types` already derives +from the two spaces' chromaticities, adapting D65 to D50 by Bradford, which the export path uses to +write ProPhoto files — and `P` is its inverse. The fragment uses `P⁻¹` going in and `P` coming +out. Each row of both is scaled to sum to one, so working-space white is ProPhoto white exactly and +a neutral reaches the tables at `s = 0`. For a profile with forward matrices this recovers the +SDK's ProPhoto colour to within the difference between that derivation and `forward_to_srgb`'s +published Bradford constants, which is rounding. ## 4. Where a profile comes from @@ -197,11 +197,13 @@ action sits on that line. - **The CPU reference matches the SDK's algorithm**: grey passes through; a table of `(0°, 1, 1)` everywhere is the identity to 1e-6; a uniform `satScale` of 1.2 scales HSV saturation by 1.2; hue interpolation wraps between the last and first column. -- **The shader agrees with the CPU reference** within 1e-4 on a ramp across hue, saturation and - values up to 16.0, on a device. +- **The shader agrees with the CPU reference** on a device, within two 8-bit codes of the + display-encoded readback (the only readback the adjust pass has), over 256 colours that tables + of tens of degrees and ±30 % saturation move, and over the library's real Adobe Standard tables + (`dr-gpu/tests/camera_profile.rs`). - **Scene-referred.** A value above 1.0 leaves the stage above 1.0 (`scene_referred_until_the_view` covers the operation). -- **Neutral.** `apply` off, or no tables, composes a shader whose output equals today's to the bit. +- **Neutral.** `apply` off renders to the bit what a source with no tables renders. - **Two illuminants.** A HueSatMap at blend weight 0 is Data1, at 1 is Data2. - **Matching.** An embedded profile beats a directory one; a DCP for "Canon EOS 6D" matches a CR2 whose rawler make/model is "Canon"/"EOS 6D"; no match leaves the matrix. diff --git a/docs/dev/requirements.md b/docs/dev/requirements.md index d64a2f6..993823b 100644 --- a/docs/dev/requirements.md +++ b/docs/dev/requirements.md @@ -459,7 +459,7 @@ FR-DEV-3j's default, for every body. ΔE2000 validation against ColorChecker ref once DCP support lands. For item 4: the lookup follows the DNG SDK's on `[0, 1]` and leaves values above 1.0 above it; grey and an identity table pass through unchanged; the shader agrees with the CPU reference; with -the switch off, or no profile, the render is unchanged to the bit (camera-profiles.md §8). +the switch off the render is to the bit the one with no profile (camera-profiles.md §8). **FR-DEV-3f — Look emulation.** Support HaldCLUT import, which inherits the existing free film simulation ecosystem at near-zero implementation cost, plus reading the in-RAF film simulation tag diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md index 425d1cc..34601fc 100644 --- a/docs/dev/traceability.md +++ b/docs/dev/traceability.md @@ -9,8 +9,8 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n | Metric | Value | |---|---| -| Source files scanned | 483 | -| TRACES tags found | 2010 | +| Source files scanned | 486 | +| TRACES tags found | 2020 | | Requirements defined | 193 | | Requirements deferred (post-v1) | 24 | | Requirements covered | 165 | @@ -71,48 +71,48 @@ _None._ | FR-DEV-19 | [`core/dr-pipeline/src/mask.rs:1341`](../../core/dr-pipeline/src/mask.rs#L1341) | | FR-DEV-19a | [`core/dr-gpu/src/mask.rs:655`](../../core/dr-gpu/src/mask.rs#L655), [`core/dr-gpu/src/mask.rs:773`](../../core/dr-gpu/src/mask.rs#L773), [`core/dr-gpu/tests/local_adjustments.rs:793`](../../core/dr-gpu/tests/local_adjustments.rs#L793), [`core/dr-gpu/tests/local_adjustments.rs:841`](../../core/dr-gpu/tests/local_adjustments.rs#L841), [`core/dr-pipeline/src/mask.rs:1022`](../../core/dr-pipeline/src/mask.rs#L1022), [`core/dr-pipeline/src/mask.rs:1635`](../../core/dr-pipeline/src/mask.rs#L1635), [`core/dr-pipeline/src/mask.rs:3282`](../../core/dr-pipeline/src/mask.rs#L3282), [`core/dr-pipeline/src/mask.rs:3403`](../../core/dr-pipeline/src/mask.rs#L3403), [`core/dr-pipeline/src/mask.rs:3438`](../../core/dr-pipeline/src/mask.rs#L3438), [`core/dr-pipeline/src/mask.rs:929`](../../core/dr-pipeline/src/mask.rs#L929), [`core/dr-pipeline/src/mask.rs:964`](../../core/dr-pipeline/src/mask.rs#L964), [`core/dr-pipeline/src/sidecar.rs:1259`](../../core/dr-pipeline/src/sidecar.rs#L1259), [`core/dr-pipeline/tests/mask_sidecar.rs:1347`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1347), [`core/dr-pipeline/tests/mask_sidecar.rs:1369`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1369), [`core/dr-pipeline/tests/mask_sidecar.rs:1395`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1395), [`ui/dr-ui/src/develop/masks.rs:432`](../../ui/dr-ui/src/develop/masks.rs#L432), [`ui/dr-ui/src/develop/masks.rs:493`](../../ui/dr-ui/src/develop/masks.rs#L493), [`ui/dr-ui/src/develop/masks.rs:512`](../../ui/dr-ui/src/develop/masks.rs#L512), [`ui/dr-ui/src/develop/masks.rs:547`](../../ui/dr-ui/src/develop/masks.rs#L547), [`ui/dr-ui/src/develop/session.rs:205`](../../ui/dr-ui/src/develop/session.rs#L205), [`ui/dr-ui/src/labels.rs:73`](../../ui/dr-ui/src/labels.rs#L73), [`ui/dr-ui/src/masks_ui.rs:1083`](../../ui/dr-ui/src/masks_ui.rs#L1083), [`ui/dr-ui/src/masks_ui.rs:1140`](../../ui/dr-ui/src/masks_ui.rs#L1140), [`ui/dr-ui/src/masks_ui.rs:1196`](../../ui/dr-ui/src/masks_ui.rs#L1196), [`ui/dr-ui/src/masks_ui.rs:1555`](../../ui/dr-ui/src/masks_ui.rs#L1555), [`ui/dr-ui/src/masks_ui.rs:1578`](../../ui/dr-ui/src/masks_ui.rs#L1578), [`ui/dr-ui/src/masks_ui.rs:270`](../../ui/dr-ui/src/masks_ui.rs#L270), [`ui/dr-ui/ui/app.slint:2694`](../../ui/dr-ui/ui/app.slint#L2694), [`ui/dr-ui/ui/masks.slint:151`](../../ui/dr-ui/ui/masks.slint#L151), [`ui/dr-ui/ui/masks.slint:176`](../../ui/dr-ui/ui/masks.slint#L176), [`ui/dr-ui/ui/masks.slint:339`](../../ui/dr-ui/ui/masks.slint#L339), [`ui/dr-ui/ui/masks.slint:379`](../../ui/dr-ui/ui/masks.slint#L379), [`ui/dr-ui/ui/masks.slint:422`](../../ui/dr-ui/ui/masks.slint#L422), [`ui/dr-ui/ui/masks.slint:468`](../../ui/dr-ui/ui/masks.slint#L468), [`ui/dr-ui/ui/masks.slint:796`](../../ui/dr-ui/ui/masks.slint#L796), [`ui/dr-ui/ui/masks.slint:881`](../../ui/dr-ui/ui/masks.slint#L881) | | FR-DEV-19b | [`ui/dr-ui/src/develop/mask_ops.rs:606`](../../ui/dr-ui/src/develop/mask_ops.rs#L606), [`ui/dr-ui/src/develop/masks.rs:595`](../../ui/dr-ui/src/develop/masks.rs#L595), [`ui/dr-ui/src/develop/session.rs:214`](../../ui/dr-ui/src/develop/session.rs#L214), [`ui/dr-ui/src/develop/session.rs:221`](../../ui/dr-ui/src/develop/session.rs#L221), [`ui/dr-ui/src/labels.rs:67`](../../ui/dr-ui/src/labels.rs#L67), [`ui/dr-ui/src/masks_ui.rs:1229`](../../ui/dr-ui/src/masks_ui.rs#L1229), [`ui/dr-ui/src/masks_ui.rs:1448`](../../ui/dr-ui/src/masks_ui.rs#L1448), [`ui/dr-ui/src/masks_ui.rs:1476`](../../ui/dr-ui/src/masks_ui.rs#L1476), [`ui/dr-ui/src/masks_ui.rs:1849`](../../ui/dr-ui/src/masks_ui.rs#L1849), [`ui/dr-ui/src/masks_ui.rs:908`](../../ui/dr-ui/src/masks_ui.rs#L908), [`ui/dr-ui/ui/app.slint:2229`](../../ui/dr-ui/ui/app.slint#L2229), [`ui/dr-ui/ui/app.slint:861`](../../ui/dr-ui/ui/app.slint#L861), [`ui/dr-ui/ui/masks.slint:1156`](../../ui/dr-ui/ui/masks.slint#L1156), [`ui/dr-ui/ui/masks.slint:479`](../../ui/dr-ui/ui/masks.slint#L479), [`ui/dr-ui/ui/masks.slint:800`](../../ui/dr-ui/ui/masks.slint#L800), [`ui/dr-ui/ui/masks.slint:874`](../../ui/dr-ui/ui/masks.slint#L874), [`ui/dr-ui/ui/masks.slint:894`](../../ui/dr-ui/ui/masks.slint#L894) | -| FR-DEV-19c | [`core/dr-gpu/src/mask.rs:727`](../../core/dr-gpu/src/mask.rs#L727), [`core/dr-gpu/tests/local_adjustments.rs:1000`](../../core/dr-gpu/tests/local_adjustments.rs#L1000), [`core/dr-gpu/tests/local_adjustments.rs:1035`](../../core/dr-gpu/tests/local_adjustments.rs#L1035), [`core/dr-gpu/tests/local_adjustments.rs:1080`](../../core/dr-gpu/tests/local_adjustments.rs#L1080), [`core/dr-gpu/tests/local_adjustments.rs:943`](../../core/dr-gpu/tests/local_adjustments.rs#L943), [`core/dr-pipeline/src/graph.rs:957`](../../core/dr-pipeline/src/graph.rs#L957), [`core/dr-pipeline/src/mask.rs:1843`](../../core/dr-pipeline/src/mask.rs#L1843), [`core/dr-pipeline/src/mask.rs:1869`](../../core/dr-pipeline/src/mask.rs#L1869), [`core/dr-pipeline/src/mask.rs:1884`](../../core/dr-pipeline/src/mask.rs#L1884), [`core/dr-pipeline/src/mask.rs:2006`](../../core/dr-pipeline/src/mask.rs#L2006), [`core/dr-pipeline/src/mask.rs:2065`](../../core/dr-pipeline/src/mask.rs#L2065), [`core/dr-pipeline/src/mask.rs:2309`](../../core/dr-pipeline/src/mask.rs#L2309), [`core/dr-pipeline/src/mask.rs:2621`](../../core/dr-pipeline/src/mask.rs#L2621), [`core/dr-pipeline/src/operation.rs:1090`](../../core/dr-pipeline/src/operation.rs#L1090), [`core/dr-pipeline/src/operation.rs:2122`](../../core/dr-pipeline/src/operation.rs#L2122), [`core/dr-pipeline/src/operation.rs:725`](../../core/dr-pipeline/src/operation.rs#L725), [`ui/dr-ui/src/develop/mask_ops.rs:1199`](../../ui/dr-ui/src/develop/mask_ops.rs#L1199), [`ui/dr-ui/src/develop/mask_ops.rs:1235`](../../ui/dr-ui/src/develop/mask_ops.rs#L1235), [`ui/dr-ui/src/develop/mask_ops.rs:318`](../../ui/dr-ui/src/develop/mask_ops.rs#L318), [`ui/dr-ui/src/develop/mask_ops.rs:58`](../../ui/dr-ui/src/develop/mask_ops.rs#L58), [`ui/dr-ui/src/develop/masks.rs:12`](../../ui/dr-ui/src/develop/masks.rs#L12), [`ui/dr-ui/src/develop/masks.rs:176`](../../ui/dr-ui/src/develop/masks.rs#L176), [`ui/dr-ui/src/develop/masks.rs:21`](../../ui/dr-ui/src/develop/masks.rs#L21), [`ui/dr-ui/src/develop/masks.rs:43`](../../ui/dr-ui/src/develop/masks.rs#L43), [`ui/dr-ui/src/develop/render.rs:355`](../../ui/dr-ui/src/develop/render.rs#L355), [`ui/dr-ui/src/develop/session.rs:240`](../../ui/dr-ui/src/develop/session.rs#L240), [`ui/dr-ui/src/develop/session.rs:249`](../../ui/dr-ui/src/develop/session.rs#L249), [`ui/dr-ui/src/masks_ui.rs:1024`](../../ui/dr-ui/src/masks_ui.rs#L1024), [`ui/dr-ui/src/masks_ui.rs:1448`](../../ui/dr-ui/src/masks_ui.rs#L1448), [`ui/dr-ui/src/masks_ui.rs:152`](../../ui/dr-ui/src/masks_ui.rs#L152), [`ui/dr-ui/src/masks_ui.rs:1849`](../../ui/dr-ui/src/masks_ui.rs#L1849), [`ui/dr-ui/src/masks_ui.rs:291`](../../ui/dr-ui/src/masks_ui.rs#L291), [`ui/dr-ui/src/masks_ui.rs:317`](../../ui/dr-ui/src/masks_ui.rs#L317), [`ui/dr-ui/src/masks_ui.rs:677`](../../ui/dr-ui/src/masks_ui.rs#L677), [`ui/dr-ui/src/masks_ui.rs:996`](../../ui/dr-ui/src/masks_ui.rs#L996), [`ui/dr-ui/ui/icons.slint:340`](../../ui/dr-ui/ui/icons.slint#L340), [`ui/dr-ui/ui/masks.slint:1121`](../../ui/dr-ui/ui/masks.slint#L1121), [`ui/dr-ui/ui/masks.slint:184`](../../ui/dr-ui/ui/masks.slint#L184), [`ui/dr-ui/ui/masks.slint:294`](../../ui/dr-ui/ui/masks.slint#L294), [`ui/dr-ui/ui/masks.slint:543`](../../ui/dr-ui/ui/masks.slint#L543), [`ui/dr-ui/ui/masks.slint:70`](../../ui/dr-ui/ui/masks.slint#L70), [`ui/dr-ui/ui/masks.slint:808`](../../ui/dr-ui/ui/masks.slint#L808), [`ui/dr-ui/ui/masks.slint:876`](../../ui/dr-ui/ui/masks.slint#L876), [`ui/dr-ui/ui/masks.slint:968`](../../ui/dr-ui/ui/masks.slint#L968) | -| FR-DEV-2 | [`core/dr-gpu/tests/scene_referred.rs:144`](../../core/dr-gpu/tests/scene_referred.rs#L144), [`core/dr-gpu/tests/scene_referred.rs:1`](../../core/dr-gpu/tests/scene_referred.rs#L1), [`core/dr-gpu/tests/view_transform.rs:153`](../../core/dr-gpu/tests/view_transform.rs#L153), [`core/dr-gpu/tests/view_transform.rs:1`](../../core/dr-gpu/tests/view_transform.rs#L1), [`core/dr-gpu/tests/view_transform.rs:89`](../../core/dr-gpu/tests/view_transform.rs#L89), [`core/dr-pipeline/src/declared/decl.rs:279`](../../core/dr-pipeline/src/declared/decl.rs#L279), [`core/dr-pipeline/src/operation.rs:2441`](../../core/dr-pipeline/src/operation.rs#L2441), [`core/dr-pipeline/src/operation.rs:2682`](../../core/dr-pipeline/src/operation.rs#L2682), [`core/dr-pipeline/src/operation.rs:356`](../../core/dr-pipeline/src/operation.rs#L356), [`core/dr-pipeline/src/operation.rs:430`](../../core/dr-pipeline/src/operation.rs#L430), [`core/dr-pipeline/src/operation.rs:450`](../../core/dr-pipeline/src/operation.rs#L450), [`core/dr-pipeline/src/operation.rs:492`](../../core/dr-pipeline/src/operation.rs#L492), [`core/dr-pipeline/src/ops/curve.rs:491`](../../core/dr-pipeline/src/ops/curve.rs#L491), [`core/dr-pipeline/src/view.rs:1`](../../core/dr-pipeline/src/view.rs#L1), [`core/dr-pipeline/src/view.rs:211`](../../core/dr-pipeline/src/view.rs#L211) | -| FR-DEV-20 | [`core/dr-gpu/src/adjust.rs:2266`](../../core/dr-gpu/src/adjust.rs#L2266), [`core/dr-pipeline/src/framing.rs:1377`](../../core/dr-pipeline/src/framing.rs#L1377), [`core/dr-pipeline/src/framing.rs:170`](../../core/dr-pipeline/src/framing.rs#L170), [`core/dr-pipeline/src/framing.rs:401`](../../core/dr-pipeline/src/framing.rs#L401), [`core/dr-pipeline/src/framing.rs:495`](../../core/dr-pipeline/src/framing.rs#L495), [`core/dr-pipeline/src/framing.rs:652`](../../core/dr-pipeline/src/framing.rs#L652), [`core/dr-pipeline/src/framing.rs:663`](../../core/dr-pipeline/src/framing.rs#L663), [`core/dr-pipeline/src/framing.rs:88`](../../core/dr-pipeline/src/framing.rs#L88), [`core/dr-pipeline/src/framing.rs:92`](../../core/dr-pipeline/src/framing.rs#L92), [`core/dr-pipeline/src/framing.rs:938`](../../core/dr-pipeline/src/framing.rs#L938), [`core/dr-pipeline/src/framing.rs:994`](../../core/dr-pipeline/src/framing.rs#L994), [`core/dr-pipeline/src/preset.rs:1001`](../../core/dr-pipeline/src/preset.rs#L1001), [`core/dr-pipeline/src/sidecar.rs:2197`](../../core/dr-pipeline/src/sidecar.rs#L2197), [`ui/dr-ui/src/develop/framing.rs:1185`](../../ui/dr-ui/src/develop/framing.rs#L1185), [`ui/dr-ui/src/develop/framing.rs:418`](../../ui/dr-ui/src/develop/framing.rs#L418), [`ui/dr-ui/src/develop/framing.rs:474`](../../ui/dr-ui/src/develop/framing.rs#L474), [`ui/dr-ui/src/develop/framing.rs:480`](../../ui/dr-ui/src/develop/framing.rs#L480), [`ui/dr-ui/src/develop/framing.rs:489`](../../ui/dr-ui/src/develop/framing.rs#L489), [`ui/dr-ui/src/develop_ui.rs:1310`](../../ui/dr-ui/src/develop_ui.rs#L1310), [`ui/dr-ui/src/develop_ui.rs:1343`](../../ui/dr-ui/src/develop_ui.rs#L1343), [`ui/dr-ui/src/labels.rs:285`](../../ui/dr-ui/src/labels.rs#L285), [`ui/dr-ui/ui/adjust.slint:646`](../../ui/dr-ui/ui/adjust.slint#L646), [`ui/dr-ui/ui/adjust.slint:688`](../../ui/dr-ui/ui/adjust.slint#L688), [`ui/dr-ui/ui/adjust.slint:831`](../../ui/dr-ui/ui/adjust.slint#L831), [`ui/dr-ui/ui/app.slint:2718`](../../ui/dr-ui/ui/app.slint#L2718), [`ui/dr-ui/ui/app.slint:727`](../../ui/dr-ui/ui/app.slint#L727), [`ui/dr-ui/ui/app.slint:750`](../../ui/dr-ui/ui/app.slint#L750) | -| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:1050`](../../core/dr-gpu/src/adjust.rs#L1050), [`core/dr-gpu/src/adjust.rs:2886`](../../core/dr-gpu/src/adjust.rs#L2886), [`core/dr-gpu/src/adjust.rs:74`](../../core/dr-gpu/src/adjust.rs#L74), [`core/dr-gpu/src/adjust.rs:917`](../../core/dr-gpu/src/adjust.rs#L917), [`core/dr-gpu/tests/tone_curve.rs:1`](../../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:491`](../../core/dr-pipeline/src/detail.rs#L491), [`core/dr-pipeline/src/detail.rs:592`](../../core/dr-pipeline/src/detail.rs#L592), [`core/dr-pipeline/src/framing.rs:1111`](../../core/dr-pipeline/src/framing.rs#L1111), [`core/dr-pipeline/src/framing.rs:251`](../../core/dr-pipeline/src/framing.rs#L251), [`core/dr-pipeline/src/framing.rs:321`](../../core/dr-pipeline/src/framing.rs#L321), [`core/dr-pipeline/src/framing.rs:481`](../../core/dr-pipeline/src/framing.rs#L481), [`core/dr-pipeline/src/framing.rs:717`](../../core/dr-pipeline/src/framing.rs#L717), [`core/dr-pipeline/src/graph.rs:1016`](../../core/dr-pipeline/src/graph.rs#L1016), [`core/dr-pipeline/src/graph.rs:1411`](../../core/dr-pipeline/src/graph.rs#L1411), [`core/dr-pipeline/src/graph.rs:1442`](../../core/dr-pipeline/src/graph.rs#L1442), [`core/dr-pipeline/src/graph.rs:1465`](../../core/dr-pipeline/src/graph.rs#L1465), [`core/dr-pipeline/src/graph.rs:1503`](../../core/dr-pipeline/src/graph.rs#L1503), [`core/dr-pipeline/src/graph.rs:1534`](../../core/dr-pipeline/src/graph.rs#L1534), [`core/dr-pipeline/src/graph.rs:232`](../../core/dr-pipeline/src/graph.rs#L232), [`core/dr-pipeline/src/graph.rs:364`](../../core/dr-pipeline/src/graph.rs#L364), [`core/dr-pipeline/src/graph.rs:402`](../../core/dr-pipeline/src/graph.rs#L402), [`core/dr-pipeline/src/graph.rs:408`](../../core/dr-pipeline/src/graph.rs#L408), [`core/dr-pipeline/src/graph.rs:924`](../../core/dr-pipeline/src/graph.rs#L924), [`core/dr-pipeline/src/lens.rs:93`](../../core/dr-pipeline/src/lens.rs#L93), [`core/dr-pipeline/src/mask.rs:205`](../../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:306`](../../core/dr-pipeline/src/neutral.rs#L306), [`core/dr-pipeline/src/neutral.rs:322`](../../core/dr-pipeline/src/neutral.rs#L322), [`core/dr-pipeline/src/neutral.rs:338`](../../core/dr-pipeline/src/neutral.rs#L338), [`core/dr-pipeline/src/neutral.rs:360`](../../core/dr-pipeline/src/neutral.rs#L360), [`core/dr-pipeline/src/neutral.rs:81`](../../core/dr-pipeline/src/neutral.rs#L81), [`core/dr-pipeline/src/operation.rs:321`](../../core/dr-pipeline/src/operation.rs#L321), [`core/dr-pipeline/src/operation.rs:364`](../../core/dr-pipeline/src/operation.rs#L364), [`core/dr-pipeline/src/operation.rs:701`](../../core/dr-pipeline/src/operation.rs#L701), [`core/dr-pipeline/src/operation.rs:774`](../../core/dr-pipeline/src/operation.rs#L774), [`core/dr-pipeline/src/operation.rs:956`](../../core/dr-pipeline/src/operation.rs#L956), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:669`](../../core/dr-pipeline/src/ops/curve.rs#L669), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/preset.rs:927`](../../core/dr-pipeline/src/preset.rs#L927), [`core/dr-pipeline/src/sidecar.rs:1433`](../../core/dr-pipeline/src/sidecar.rs#L1433), [`core/dr-pipeline/src/sidecar.rs:206`](../../core/dr-pipeline/src/sidecar.rs#L206), [`core/dr-pipeline/src/sidecar.rs:2275`](../../core/dr-pipeline/src/sidecar.rs#L2275), [`core/dr-pipeline/src/sidecar.rs:2355`](../../core/dr-pipeline/src/sidecar.rs#L2355), [`core/dr-pipeline/tests/tone_curve.rs:1`](../../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:937`](../../core/dr-segment/src/refine.rs#L937), [`ui/dr-ui/src/develop/curves.rs:163`](../../ui/dr-ui/src/develop/curves.rs#L163), [`ui/dr-ui/src/develop/framing.rs:10`](../../ui/dr-ui/src/develop/framing.rs#L10), [`ui/dr-ui/src/develop/framing.rs:298`](../../ui/dr-ui/src/develop/framing.rs#L298), [`ui/dr-ui/src/develop/framing.rs:328`](../../ui/dr-ui/src/develop/framing.rs#L328), [`ui/dr-ui/src/develop/framing.rs:394`](../../ui/dr-ui/src/develop/framing.rs#L394), [`ui/dr-ui/src/develop/framing.rs:408`](../../ui/dr-ui/src/develop/framing.rs#L408), [`ui/dr-ui/src/develop/framing.rs:690`](../../ui/dr-ui/src/develop/framing.rs#L690), [`ui/dr-ui/src/develop/framing.rs:71`](../../ui/dr-ui/src/develop/framing.rs#L71), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1340`](../../ui/dr-ui/src/develop/mask_ops.rs#L1340), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/mask_ops.rs:969`](../../ui/dr-ui/src/develop/mask_ops.rs#L969), [`ui/dr-ui/src/develop/masks.rs:263`](../../ui/dr-ui/src/develop/masks.rs#L263), [`ui/dr-ui/src/develop/masks.rs:361`](../../ui/dr-ui/src/develop/masks.rs#L361), [`ui/dr-ui/src/develop/masks.rs:743`](../../ui/dr-ui/src/develop/masks.rs#L743), [`ui/dr-ui/src/develop/masks.rs:773`](../../ui/dr-ui/src/develop/masks.rs#L773), [`ui/dr-ui/src/develop/render.rs:1383`](../../ui/dr-ui/src/develop/render.rs#L1383), [`ui/dr-ui/src/develop/rows.rs:106`](../../ui/dr-ui/src/develop/rows.rs#L106), [`ui/dr-ui/src/develop/rows.rs:195`](../../ui/dr-ui/src/develop/rows.rs#L195), [`ui/dr-ui/src/develop/rows.rs:231`](../../ui/dr-ui/src/develop/rows.rs#L231), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/segmentation.rs:139`](../../ui/dr-ui/src/develop/segmentation.rs#L139), [`ui/dr-ui/src/develop/segmentation.rs:302`](../../ui/dr-ui/src/develop/segmentation.rs#L302), [`ui/dr-ui/src/develop/segmentation.rs:339`](../../ui/dr-ui/src/develop/segmentation.rs#L339), [`ui/dr-ui/src/develop/segmentation.rs:572`](../../ui/dr-ui/src/develop/segmentation.rs#L572), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:604`](../../ui/dr-ui/src/develop/segmentation.rs#L604), [`ui/dr-ui/src/develop/segmentation.rs:626`](../../ui/dr-ui/src/develop/segmentation.rs#L626), [`ui/dr-ui/src/develop/segmentation.rs:77`](../../ui/dr-ui/src/develop/segmentation.rs#L77), [`ui/dr-ui/src/develop/segmentation.rs:806`](../../ui/dr-ui/src/develop/segmentation.rs#L806), [`ui/dr-ui/src/develop/session.rs:175`](../../ui/dr-ui/src/develop/session.rs#L175), [`ui/dr-ui/src/develop/session.rs:268`](../../ui/dr-ui/src/develop/session.rs#L268), [`ui/dr-ui/src/develop/session.rs:297`](../../ui/dr-ui/src/develop/session.rs#L297), [`ui/dr-ui/src/develop/session.rs:488`](../../ui/dr-ui/src/develop/session.rs#L488), [`ui/dr-ui/src/develop/session.rs:548`](../../ui/dr-ui/src/develop/session.rs#L548), [`ui/dr-ui/src/develop/session.rs:620`](../../ui/dr-ui/src/develop/session.rs#L620), [`ui/dr-ui/src/develop/session.rs:775`](../../ui/dr-ui/src/develop/session.rs#L775), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop/white_balance.rs:193`](../../ui/dr-ui/src/develop/white_balance.rs#L193), [`ui/dr-ui/src/develop/white_balance.rs:276`](../../ui/dr-ui/src/develop/white_balance.rs#L276), [`ui/dr-ui/src/develop/white_balance.rs:338`](../../ui/dr-ui/src/develop/white_balance.rs#L338), [`ui/dr-ui/src/develop_ui.rs:1123`](../../ui/dr-ui/src/develop_ui.rs#L1123), [`ui/dr-ui/src/develop_ui.rs:117`](../../ui/dr-ui/src/develop_ui.rs#L117), [`ui/dr-ui/src/develop_ui.rs:1220`](../../ui/dr-ui/src/develop_ui.rs#L1220), [`ui/dr-ui/src/develop_ui.rs:1274`](../../ui/dr-ui/src/develop_ui.rs#L1274), [`ui/dr-ui/src/develop_ui.rs:521`](../../ui/dr-ui/src/develop_ui.rs#L521), [`ui/dr-ui/src/develop_ui.rs:741`](../../ui/dr-ui/src/develop_ui.rs#L741), [`ui/dr-ui/src/labels.rs:35`](../../ui/dr-ui/src/labels.rs#L35), [`ui/dr-ui/src/lib.rs:2192`](../../ui/dr-ui/src/lib.rs#L2192), [`ui/dr-ui/src/lib.rs:458`](../../ui/dr-ui/src/lib.rs#L458), [`ui/dr-ui/src/lib.rs:488`](../../ui/dr-ui/src/lib.rs#L488), [`ui/dr-ui/src/lib.rs:596`](../../ui/dr-ui/src/lib.rs#L596), [`ui/dr-ui/src/lib.rs:620`](../../ui/dr-ui/src/lib.rs#L620), [`ui/dr-ui/src/library/sidecar.rs:66`](../../ui/dr-ui/src/library/sidecar.rs#L66), [`ui/dr-ui/src/masks_ui.rs:1608`](../../ui/dr-ui/src/masks_ui.rs#L1608), [`ui/dr-ui/src/masks_ui.rs:1722`](../../ui/dr-ui/src/masks_ui.rs#L1722), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/masks_ui.rs:44`](../../ui/dr-ui/src/masks_ui.rs#L44), [`ui/dr-ui/src/presets.rs:414`](../../ui/dr-ui/src/presets.rs#L414), [`ui/dr-ui/src/segmentation.rs:117`](../../ui/dr-ui/src/segmentation.rs#L117), [`ui/dr-ui/src/segmentation.rs:353`](../../ui/dr-ui/src/segmentation.rs#L353), [`ui/dr-ui/src/segmentation.rs:369`](../../ui/dr-ui/src/segmentation.rs#L369), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499), [`ui/dr-ui/src/segmentation.rs:527`](../../ui/dr-ui/src/segmentation.rs#L527), [`ui/dr-ui/ui/adjust.slint:1050`](../../ui/dr-ui/ui/adjust.slint#L1050), [`ui/dr-ui/ui/adjust.slint:127`](../../ui/dr-ui/ui/adjust.slint#L127), [`ui/dr-ui/ui/adjust.slint:1658`](../../ui/dr-ui/ui/adjust.slint#L1658), [`ui/dr-ui/ui/adjust.slint:173`](../../ui/dr-ui/ui/adjust.slint#L173), [`ui/dr-ui/ui/adjust.slint:47`](../../ui/dr-ui/ui/adjust.slint#L47), [`ui/dr-ui/ui/adjust.slint:626`](../../ui/dr-ui/ui/adjust.slint#L626), [`ui/dr-ui/ui/adjust.slint:662`](../../ui/dr-ui/ui/adjust.slint#L662), [`ui/dr-ui/ui/adjust.slint:681`](../../ui/dr-ui/ui/adjust.slint#L681), [`ui/dr-ui/ui/adjust.slint:874`](../../ui/dr-ui/ui/adjust.slint#L874), [`ui/dr-ui/ui/adjust.slint:973`](../../ui/dr-ui/ui/adjust.slint#L973), [`ui/dr-ui/ui/app.slint:2294`](../../ui/dr-ui/ui/app.slint#L2294), [`ui/dr-ui/ui/app.slint:2356`](../../ui/dr-ui/ui/app.slint#L2356), [`ui/dr-ui/ui/app.slint:242`](../../ui/dr-ui/ui/app.slint#L242), [`ui/dr-ui/ui/develop.slint:375`](../../ui/dr-ui/ui/develop.slint#L375), [`ui/dr-ui/ui/masks.slint:1246`](../../ui/dr-ui/ui/masks.slint#L1246), [`ui/dr-ui/ui/masks.slint:779`](../../ui/dr-ui/ui/masks.slint#L779), [`ui/dr-ui/ui/masks.slint:838`](../../ui/dr-ui/ui/masks.slint#L838) | -| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:212`](../../core/dr-pipeline/src/descriptor.rs#L212), [`core/dr-pipeline/src/descriptor.rs:252`](../../core/dr-pipeline/src/descriptor.rs#L252), [`core/dr-pipeline/src/descriptor.rs:276`](../../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/descriptor.rs:331`](../../core/dr-pipeline/src/descriptor.rs#L331), [`core/dr-pipeline/src/framing.rs:568`](../../core/dr-pipeline/src/framing.rs#L568), [`core/dr-pipeline/src/graph.rs:25`](../../core/dr-pipeline/src/graph.rs#L25), [`core/dr-pipeline/src/graph.rs:451`](../../core/dr-pipeline/src/graph.rs#L451), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:592`](../../core/dr-pipeline/src/graph.rs#L592), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1746`](../../core/dr-pipeline/src/mask.rs#L1746), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:378`](../../core/dr-pipeline/src/neutral.rs#L378), [`core/dr-pipeline/src/operation.rs:232`](../../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:399`](../../core/dr-pipeline/src/operation.rs#L399), [`core/dr-pipeline/src/ops/curve.rs:319`](../../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop/curves.rs:36`](../../ui/dr-ui/src/develop/curves.rs#L36), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/rows.rs:877`](../../ui/dr-ui/src/develop/rows.rs#L877), [`ui/dr-ui/src/lib.rs:945`](../../ui/dr-ui/src/lib.rs#L945), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../../ui/dr-ui/tests/ui_names_no_operation.rs#L1), [`ui/dr-ui/ui/app.slint:2748`](../../ui/dr-ui/ui/app.slint#L2748) | -| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:276`](../../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/framing.rs:568`](../../core/dr-pipeline/src/framing.rs#L568), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/operation.rs:399`](../../core/dr-pipeline/src/operation.rs#L399), [`ui/dr-ui/ui/app.slint:3027`](../../ui/dr-ui/ui/app.slint#L3027) | +| FR-DEV-19c | [`core/dr-gpu/src/mask.rs:727`](../../core/dr-gpu/src/mask.rs#L727), [`core/dr-gpu/tests/local_adjustments.rs:1000`](../../core/dr-gpu/tests/local_adjustments.rs#L1000), [`core/dr-gpu/tests/local_adjustments.rs:1035`](../../core/dr-gpu/tests/local_adjustments.rs#L1035), [`core/dr-gpu/tests/local_adjustments.rs:1080`](../../core/dr-gpu/tests/local_adjustments.rs#L1080), [`core/dr-gpu/tests/local_adjustments.rs:943`](../../core/dr-gpu/tests/local_adjustments.rs#L943), [`core/dr-pipeline/src/graph.rs:957`](../../core/dr-pipeline/src/graph.rs#L957), [`core/dr-pipeline/src/mask.rs:1843`](../../core/dr-pipeline/src/mask.rs#L1843), [`core/dr-pipeline/src/mask.rs:1869`](../../core/dr-pipeline/src/mask.rs#L1869), [`core/dr-pipeline/src/mask.rs:1884`](../../core/dr-pipeline/src/mask.rs#L1884), [`core/dr-pipeline/src/mask.rs:2006`](../../core/dr-pipeline/src/mask.rs#L2006), [`core/dr-pipeline/src/mask.rs:2065`](../../core/dr-pipeline/src/mask.rs#L2065), [`core/dr-pipeline/src/mask.rs:2309`](../../core/dr-pipeline/src/mask.rs#L2309), [`core/dr-pipeline/src/mask.rs:2621`](../../core/dr-pipeline/src/mask.rs#L2621), [`core/dr-pipeline/src/operation.rs:1103`](../../core/dr-pipeline/src/operation.rs#L1103), [`core/dr-pipeline/src/operation.rs:2140`](../../core/dr-pipeline/src/operation.rs#L2140), [`core/dr-pipeline/src/operation.rs:738`](../../core/dr-pipeline/src/operation.rs#L738), [`ui/dr-ui/src/develop/mask_ops.rs:1199`](../../ui/dr-ui/src/develop/mask_ops.rs#L1199), [`ui/dr-ui/src/develop/mask_ops.rs:1235`](../../ui/dr-ui/src/develop/mask_ops.rs#L1235), [`ui/dr-ui/src/develop/mask_ops.rs:318`](../../ui/dr-ui/src/develop/mask_ops.rs#L318), [`ui/dr-ui/src/develop/mask_ops.rs:58`](../../ui/dr-ui/src/develop/mask_ops.rs#L58), [`ui/dr-ui/src/develop/masks.rs:12`](../../ui/dr-ui/src/develop/masks.rs#L12), [`ui/dr-ui/src/develop/masks.rs:176`](../../ui/dr-ui/src/develop/masks.rs#L176), [`ui/dr-ui/src/develop/masks.rs:21`](../../ui/dr-ui/src/develop/masks.rs#L21), [`ui/dr-ui/src/develop/masks.rs:43`](../../ui/dr-ui/src/develop/masks.rs#L43), [`ui/dr-ui/src/develop/render.rs:355`](../../ui/dr-ui/src/develop/render.rs#L355), [`ui/dr-ui/src/develop/session.rs:240`](../../ui/dr-ui/src/develop/session.rs#L240), [`ui/dr-ui/src/develop/session.rs:249`](../../ui/dr-ui/src/develop/session.rs#L249), [`ui/dr-ui/src/masks_ui.rs:1024`](../../ui/dr-ui/src/masks_ui.rs#L1024), [`ui/dr-ui/src/masks_ui.rs:1448`](../../ui/dr-ui/src/masks_ui.rs#L1448), [`ui/dr-ui/src/masks_ui.rs:152`](../../ui/dr-ui/src/masks_ui.rs#L152), [`ui/dr-ui/src/masks_ui.rs:1849`](../../ui/dr-ui/src/masks_ui.rs#L1849), [`ui/dr-ui/src/masks_ui.rs:291`](../../ui/dr-ui/src/masks_ui.rs#L291), [`ui/dr-ui/src/masks_ui.rs:317`](../../ui/dr-ui/src/masks_ui.rs#L317), [`ui/dr-ui/src/masks_ui.rs:677`](../../ui/dr-ui/src/masks_ui.rs#L677), [`ui/dr-ui/src/masks_ui.rs:996`](../../ui/dr-ui/src/masks_ui.rs#L996), [`ui/dr-ui/ui/icons.slint:340`](../../ui/dr-ui/ui/icons.slint#L340), [`ui/dr-ui/ui/masks.slint:1121`](../../ui/dr-ui/ui/masks.slint#L1121), [`ui/dr-ui/ui/masks.slint:184`](../../ui/dr-ui/ui/masks.slint#L184), [`ui/dr-ui/ui/masks.slint:294`](../../ui/dr-ui/ui/masks.slint#L294), [`ui/dr-ui/ui/masks.slint:543`](../../ui/dr-ui/ui/masks.slint#L543), [`ui/dr-ui/ui/masks.slint:70`](../../ui/dr-ui/ui/masks.slint#L70), [`ui/dr-ui/ui/masks.slint:808`](../../ui/dr-ui/ui/masks.slint#L808), [`ui/dr-ui/ui/masks.slint:876`](../../ui/dr-ui/ui/masks.slint#L876), [`ui/dr-ui/ui/masks.slint:968`](../../ui/dr-ui/ui/masks.slint#L968) | +| FR-DEV-2 | [`core/dr-gpu/tests/scene_referred.rs:144`](../../core/dr-gpu/tests/scene_referred.rs#L144), [`core/dr-gpu/tests/scene_referred.rs:1`](../../core/dr-gpu/tests/scene_referred.rs#L1), [`core/dr-gpu/tests/view_transform.rs:153`](../../core/dr-gpu/tests/view_transform.rs#L153), [`core/dr-gpu/tests/view_transform.rs:1`](../../core/dr-gpu/tests/view_transform.rs#L1), [`core/dr-gpu/tests/view_transform.rs:89`](../../core/dr-gpu/tests/view_transform.rs#L89), [`core/dr-pipeline/src/declared/decl.rs:279`](../../core/dr-pipeline/src/declared/decl.rs#L279), [`core/dr-pipeline/src/operation.rs:2459`](../../core/dr-pipeline/src/operation.rs#L2459), [`core/dr-pipeline/src/operation.rs:2700`](../../core/dr-pipeline/src/operation.rs#L2700), [`core/dr-pipeline/src/operation.rs:369`](../../core/dr-pipeline/src/operation.rs#L369), [`core/dr-pipeline/src/operation.rs:443`](../../core/dr-pipeline/src/operation.rs#L443), [`core/dr-pipeline/src/operation.rs:463`](../../core/dr-pipeline/src/operation.rs#L463), [`core/dr-pipeline/src/operation.rs:505`](../../core/dr-pipeline/src/operation.rs#L505), [`core/dr-pipeline/src/ops/curve.rs:491`](../../core/dr-pipeline/src/ops/curve.rs#L491), [`core/dr-pipeline/src/view.rs:1`](../../core/dr-pipeline/src/view.rs#L1), [`core/dr-pipeline/src/view.rs:211`](../../core/dr-pipeline/src/view.rs#L211) | +| FR-DEV-20 | [`core/dr-gpu/src/adjust.rs:2336`](../../core/dr-gpu/src/adjust.rs#L2336), [`core/dr-pipeline/src/framing.rs:1377`](../../core/dr-pipeline/src/framing.rs#L1377), [`core/dr-pipeline/src/framing.rs:170`](../../core/dr-pipeline/src/framing.rs#L170), [`core/dr-pipeline/src/framing.rs:401`](../../core/dr-pipeline/src/framing.rs#L401), [`core/dr-pipeline/src/framing.rs:495`](../../core/dr-pipeline/src/framing.rs#L495), [`core/dr-pipeline/src/framing.rs:652`](../../core/dr-pipeline/src/framing.rs#L652), [`core/dr-pipeline/src/framing.rs:663`](../../core/dr-pipeline/src/framing.rs#L663), [`core/dr-pipeline/src/framing.rs:88`](../../core/dr-pipeline/src/framing.rs#L88), [`core/dr-pipeline/src/framing.rs:92`](../../core/dr-pipeline/src/framing.rs#L92), [`core/dr-pipeline/src/framing.rs:938`](../../core/dr-pipeline/src/framing.rs#L938), [`core/dr-pipeline/src/framing.rs:994`](../../core/dr-pipeline/src/framing.rs#L994), [`core/dr-pipeline/src/preset.rs:1001`](../../core/dr-pipeline/src/preset.rs#L1001), [`core/dr-pipeline/src/sidecar.rs:2197`](../../core/dr-pipeline/src/sidecar.rs#L2197), [`ui/dr-ui/src/develop/framing.rs:1185`](../../ui/dr-ui/src/develop/framing.rs#L1185), [`ui/dr-ui/src/develop/framing.rs:418`](../../ui/dr-ui/src/develop/framing.rs#L418), [`ui/dr-ui/src/develop/framing.rs:474`](../../ui/dr-ui/src/develop/framing.rs#L474), [`ui/dr-ui/src/develop/framing.rs:480`](../../ui/dr-ui/src/develop/framing.rs#L480), [`ui/dr-ui/src/develop/framing.rs:489`](../../ui/dr-ui/src/develop/framing.rs#L489), [`ui/dr-ui/src/develop_ui.rs:1310`](../../ui/dr-ui/src/develop_ui.rs#L1310), [`ui/dr-ui/src/develop_ui.rs:1343`](../../ui/dr-ui/src/develop_ui.rs#L1343), [`ui/dr-ui/src/labels.rs:285`](../../ui/dr-ui/src/labels.rs#L285), [`ui/dr-ui/ui/adjust.slint:646`](../../ui/dr-ui/ui/adjust.slint#L646), [`ui/dr-ui/ui/adjust.slint:688`](../../ui/dr-ui/ui/adjust.slint#L688), [`ui/dr-ui/ui/adjust.slint:831`](../../ui/dr-ui/ui/adjust.slint#L831), [`ui/dr-ui/ui/app.slint:2718`](../../ui/dr-ui/ui/app.slint#L2718), [`ui/dr-ui/ui/app.slint:727`](../../ui/dr-ui/ui/app.slint#L727), [`ui/dr-ui/ui/app.slint:750`](../../ui/dr-ui/ui/app.slint#L750) | +| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/adjust.rs:2956`](../../core/dr-gpu/src/adjust.rs#L2956), [`core/dr-gpu/src/adjust.rs:82`](../../core/dr-gpu/src/adjust.rs#L82), [`core/dr-gpu/src/adjust.rs:969`](../../core/dr-gpu/src/adjust.rs#L969), [`core/dr-gpu/tests/tone_curve.rs:1`](../../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:491`](../../core/dr-pipeline/src/detail.rs#L491), [`core/dr-pipeline/src/detail.rs:592`](../../core/dr-pipeline/src/detail.rs#L592), [`core/dr-pipeline/src/framing.rs:1111`](../../core/dr-pipeline/src/framing.rs#L1111), [`core/dr-pipeline/src/framing.rs:251`](../../core/dr-pipeline/src/framing.rs#L251), [`core/dr-pipeline/src/framing.rs:321`](../../core/dr-pipeline/src/framing.rs#L321), [`core/dr-pipeline/src/framing.rs:481`](../../core/dr-pipeline/src/framing.rs#L481), [`core/dr-pipeline/src/framing.rs:717`](../../core/dr-pipeline/src/framing.rs#L717), [`core/dr-pipeline/src/graph.rs:1016`](../../core/dr-pipeline/src/graph.rs#L1016), [`core/dr-pipeline/src/graph.rs:1414`](../../core/dr-pipeline/src/graph.rs#L1414), [`core/dr-pipeline/src/graph.rs:1445`](../../core/dr-pipeline/src/graph.rs#L1445), [`core/dr-pipeline/src/graph.rs:1468`](../../core/dr-pipeline/src/graph.rs#L1468), [`core/dr-pipeline/src/graph.rs:1506`](../../core/dr-pipeline/src/graph.rs#L1506), [`core/dr-pipeline/src/graph.rs:1537`](../../core/dr-pipeline/src/graph.rs#L1537), [`core/dr-pipeline/src/graph.rs:232`](../../core/dr-pipeline/src/graph.rs#L232), [`core/dr-pipeline/src/graph.rs:364`](../../core/dr-pipeline/src/graph.rs#L364), [`core/dr-pipeline/src/graph.rs:402`](../../core/dr-pipeline/src/graph.rs#L402), [`core/dr-pipeline/src/graph.rs:408`](../../core/dr-pipeline/src/graph.rs#L408), [`core/dr-pipeline/src/graph.rs:924`](../../core/dr-pipeline/src/graph.rs#L924), [`core/dr-pipeline/src/lens.rs:93`](../../core/dr-pipeline/src/lens.rs#L93), [`core/dr-pipeline/src/mask.rs:205`](../../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:306`](../../core/dr-pipeline/src/neutral.rs#L306), [`core/dr-pipeline/src/neutral.rs:322`](../../core/dr-pipeline/src/neutral.rs#L322), [`core/dr-pipeline/src/neutral.rs:338`](../../core/dr-pipeline/src/neutral.rs#L338), [`core/dr-pipeline/src/neutral.rs:360`](../../core/dr-pipeline/src/neutral.rs#L360), [`core/dr-pipeline/src/neutral.rs:81`](../../core/dr-pipeline/src/neutral.rs#L81), [`core/dr-pipeline/src/operation.rs:334`](../../core/dr-pipeline/src/operation.rs#L334), [`core/dr-pipeline/src/operation.rs:377`](../../core/dr-pipeline/src/operation.rs#L377), [`core/dr-pipeline/src/operation.rs:714`](../../core/dr-pipeline/src/operation.rs#L714), [`core/dr-pipeline/src/operation.rs:787`](../../core/dr-pipeline/src/operation.rs#L787), [`core/dr-pipeline/src/operation.rs:969`](../../core/dr-pipeline/src/operation.rs#L969), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:669`](../../core/dr-pipeline/src/ops/curve.rs#L669), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/preset.rs:927`](../../core/dr-pipeline/src/preset.rs#L927), [`core/dr-pipeline/src/sidecar.rs:1433`](../../core/dr-pipeline/src/sidecar.rs#L1433), [`core/dr-pipeline/src/sidecar.rs:206`](../../core/dr-pipeline/src/sidecar.rs#L206), [`core/dr-pipeline/src/sidecar.rs:2275`](../../core/dr-pipeline/src/sidecar.rs#L2275), [`core/dr-pipeline/src/sidecar.rs:2355`](../../core/dr-pipeline/src/sidecar.rs#L2355), [`core/dr-pipeline/tests/tone_curve.rs:1`](../../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:937`](../../core/dr-segment/src/refine.rs#L937), [`ui/dr-ui/src/develop/curves.rs:163`](../../ui/dr-ui/src/develop/curves.rs#L163), [`ui/dr-ui/src/develop/framing.rs:10`](../../ui/dr-ui/src/develop/framing.rs#L10), [`ui/dr-ui/src/develop/framing.rs:298`](../../ui/dr-ui/src/develop/framing.rs#L298), [`ui/dr-ui/src/develop/framing.rs:328`](../../ui/dr-ui/src/develop/framing.rs#L328), [`ui/dr-ui/src/develop/framing.rs:394`](../../ui/dr-ui/src/develop/framing.rs#L394), [`ui/dr-ui/src/develop/framing.rs:408`](../../ui/dr-ui/src/develop/framing.rs#L408), [`ui/dr-ui/src/develop/framing.rs:690`](../../ui/dr-ui/src/develop/framing.rs#L690), [`ui/dr-ui/src/develop/framing.rs:71`](../../ui/dr-ui/src/develop/framing.rs#L71), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1340`](../../ui/dr-ui/src/develop/mask_ops.rs#L1340), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/mask_ops.rs:969`](../../ui/dr-ui/src/develop/mask_ops.rs#L969), [`ui/dr-ui/src/develop/masks.rs:263`](../../ui/dr-ui/src/develop/masks.rs#L263), [`ui/dr-ui/src/develop/masks.rs:361`](../../ui/dr-ui/src/develop/masks.rs#L361), [`ui/dr-ui/src/develop/masks.rs:743`](../../ui/dr-ui/src/develop/masks.rs#L743), [`ui/dr-ui/src/develop/masks.rs:773`](../../ui/dr-ui/src/develop/masks.rs#L773), [`ui/dr-ui/src/develop/render.rs:1383`](../../ui/dr-ui/src/develop/render.rs#L1383), [`ui/dr-ui/src/develop/rows.rs:106`](../../ui/dr-ui/src/develop/rows.rs#L106), [`ui/dr-ui/src/develop/rows.rs:195`](../../ui/dr-ui/src/develop/rows.rs#L195), [`ui/dr-ui/src/develop/rows.rs:231`](../../ui/dr-ui/src/develop/rows.rs#L231), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/segmentation.rs:139`](../../ui/dr-ui/src/develop/segmentation.rs#L139), [`ui/dr-ui/src/develop/segmentation.rs:302`](../../ui/dr-ui/src/develop/segmentation.rs#L302), [`ui/dr-ui/src/develop/segmentation.rs:339`](../../ui/dr-ui/src/develop/segmentation.rs#L339), [`ui/dr-ui/src/develop/segmentation.rs:572`](../../ui/dr-ui/src/develop/segmentation.rs#L572), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:604`](../../ui/dr-ui/src/develop/segmentation.rs#L604), [`ui/dr-ui/src/develop/segmentation.rs:626`](../../ui/dr-ui/src/develop/segmentation.rs#L626), [`ui/dr-ui/src/develop/segmentation.rs:77`](../../ui/dr-ui/src/develop/segmentation.rs#L77), [`ui/dr-ui/src/develop/segmentation.rs:806`](../../ui/dr-ui/src/develop/segmentation.rs#L806), [`ui/dr-ui/src/develop/session.rs:175`](../../ui/dr-ui/src/develop/session.rs#L175), [`ui/dr-ui/src/develop/session.rs:268`](../../ui/dr-ui/src/develop/session.rs#L268), [`ui/dr-ui/src/develop/session.rs:297`](../../ui/dr-ui/src/develop/session.rs#L297), [`ui/dr-ui/src/develop/session.rs:488`](../../ui/dr-ui/src/develop/session.rs#L488), [`ui/dr-ui/src/develop/session.rs:548`](../../ui/dr-ui/src/develop/session.rs#L548), [`ui/dr-ui/src/develop/session.rs:620`](../../ui/dr-ui/src/develop/session.rs#L620), [`ui/dr-ui/src/develop/session.rs:775`](../../ui/dr-ui/src/develop/session.rs#L775), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop/white_balance.rs:193`](../../ui/dr-ui/src/develop/white_balance.rs#L193), [`ui/dr-ui/src/develop/white_balance.rs:276`](../../ui/dr-ui/src/develop/white_balance.rs#L276), [`ui/dr-ui/src/develop/white_balance.rs:338`](../../ui/dr-ui/src/develop/white_balance.rs#L338), [`ui/dr-ui/src/develop_ui.rs:1123`](../../ui/dr-ui/src/develop_ui.rs#L1123), [`ui/dr-ui/src/develop_ui.rs:117`](../../ui/dr-ui/src/develop_ui.rs#L117), [`ui/dr-ui/src/develop_ui.rs:1220`](../../ui/dr-ui/src/develop_ui.rs#L1220), [`ui/dr-ui/src/develop_ui.rs:1274`](../../ui/dr-ui/src/develop_ui.rs#L1274), [`ui/dr-ui/src/develop_ui.rs:521`](../../ui/dr-ui/src/develop_ui.rs#L521), [`ui/dr-ui/src/develop_ui.rs:741`](../../ui/dr-ui/src/develop_ui.rs#L741), [`ui/dr-ui/src/labels.rs:35`](../../ui/dr-ui/src/labels.rs#L35), [`ui/dr-ui/src/lib.rs:2192`](../../ui/dr-ui/src/lib.rs#L2192), [`ui/dr-ui/src/lib.rs:458`](../../ui/dr-ui/src/lib.rs#L458), [`ui/dr-ui/src/lib.rs:488`](../../ui/dr-ui/src/lib.rs#L488), [`ui/dr-ui/src/lib.rs:596`](../../ui/dr-ui/src/lib.rs#L596), [`ui/dr-ui/src/lib.rs:620`](../../ui/dr-ui/src/lib.rs#L620), [`ui/dr-ui/src/library/sidecar.rs:66`](../../ui/dr-ui/src/library/sidecar.rs#L66), [`ui/dr-ui/src/masks_ui.rs:1608`](../../ui/dr-ui/src/masks_ui.rs#L1608), [`ui/dr-ui/src/masks_ui.rs:1722`](../../ui/dr-ui/src/masks_ui.rs#L1722), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/masks_ui.rs:44`](../../ui/dr-ui/src/masks_ui.rs#L44), [`ui/dr-ui/src/presets.rs:414`](../../ui/dr-ui/src/presets.rs#L414), [`ui/dr-ui/src/segmentation.rs:117`](../../ui/dr-ui/src/segmentation.rs#L117), [`ui/dr-ui/src/segmentation.rs:353`](../../ui/dr-ui/src/segmentation.rs#L353), [`ui/dr-ui/src/segmentation.rs:369`](../../ui/dr-ui/src/segmentation.rs#L369), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499), [`ui/dr-ui/src/segmentation.rs:527`](../../ui/dr-ui/src/segmentation.rs#L527), [`ui/dr-ui/ui/adjust.slint:1050`](../../ui/dr-ui/ui/adjust.slint#L1050), [`ui/dr-ui/ui/adjust.slint:127`](../../ui/dr-ui/ui/adjust.slint#L127), [`ui/dr-ui/ui/adjust.slint:1658`](../../ui/dr-ui/ui/adjust.slint#L1658), [`ui/dr-ui/ui/adjust.slint:173`](../../ui/dr-ui/ui/adjust.slint#L173), [`ui/dr-ui/ui/adjust.slint:47`](../../ui/dr-ui/ui/adjust.slint#L47), [`ui/dr-ui/ui/adjust.slint:626`](../../ui/dr-ui/ui/adjust.slint#L626), [`ui/dr-ui/ui/adjust.slint:662`](../../ui/dr-ui/ui/adjust.slint#L662), [`ui/dr-ui/ui/adjust.slint:681`](../../ui/dr-ui/ui/adjust.slint#L681), [`ui/dr-ui/ui/adjust.slint:874`](../../ui/dr-ui/ui/adjust.slint#L874), [`ui/dr-ui/ui/adjust.slint:973`](../../ui/dr-ui/ui/adjust.slint#L973), [`ui/dr-ui/ui/app.slint:2294`](../../ui/dr-ui/ui/app.slint#L2294), [`ui/dr-ui/ui/app.slint:2356`](../../ui/dr-ui/ui/app.slint#L2356), [`ui/dr-ui/ui/app.slint:242`](../../ui/dr-ui/ui/app.slint#L242), [`ui/dr-ui/ui/develop.slint:375`](../../ui/dr-ui/ui/develop.slint#L375), [`ui/dr-ui/ui/masks.slint:1246`](../../ui/dr-ui/ui/masks.slint#L1246), [`ui/dr-ui/ui/masks.slint:779`](../../ui/dr-ui/ui/masks.slint#L779), [`ui/dr-ui/ui/masks.slint:838`](../../ui/dr-ui/ui/masks.slint#L838) | +| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:212`](../../core/dr-pipeline/src/descriptor.rs#L212), [`core/dr-pipeline/src/descriptor.rs:252`](../../core/dr-pipeline/src/descriptor.rs#L252), [`core/dr-pipeline/src/descriptor.rs:276`](../../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/descriptor.rs:331`](../../core/dr-pipeline/src/descriptor.rs#L331), [`core/dr-pipeline/src/framing.rs:568`](../../core/dr-pipeline/src/framing.rs#L568), [`core/dr-pipeline/src/graph.rs:25`](../../core/dr-pipeline/src/graph.rs#L25), [`core/dr-pipeline/src/graph.rs:451`](../../core/dr-pipeline/src/graph.rs#L451), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:592`](../../core/dr-pipeline/src/graph.rs#L592), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1746`](../../core/dr-pipeline/src/mask.rs#L1746), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:378`](../../core/dr-pipeline/src/neutral.rs#L378), [`core/dr-pipeline/src/operation.rs:232`](../../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:412`](../../core/dr-pipeline/src/operation.rs#L412), [`core/dr-pipeline/src/ops/curve.rs:319`](../../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop/curves.rs:36`](../../ui/dr-ui/src/develop/curves.rs#L36), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/rows.rs:877`](../../ui/dr-ui/src/develop/rows.rs#L877), [`ui/dr-ui/src/lib.rs:945`](../../ui/dr-ui/src/lib.rs#L945), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../../ui/dr-ui/tests/ui_names_no_operation.rs#L1), [`ui/dr-ui/ui/app.slint:2748`](../../ui/dr-ui/ui/app.slint#L2748) | +| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:276`](../../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/framing.rs:568`](../../core/dr-pipeline/src/framing.rs#L568), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/operation.rs:412`](../../core/dr-pipeline/src/operation.rs#L412), [`ui/dr-ui/ui/app.slint:3027`](../../ui/dr-ui/ui/app.slint#L3027) | | FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:451`](../../core/dr-pipeline/src/graph.rs#L451), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/mask.rs:1746`](../../core/dr-pipeline/src/mask.rs#L1746), [`core/dr-pipeline/src/preset.rs:927`](../../core/dr-pipeline/src/preset.rs#L927), [`ui/dr-ui/src/develop/rows.rs:928`](../../ui/dr-ui/src/develop/rows.rs#L928) | -| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:104`](../../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1050`](../../core/dr-gpu/src/adjust.rs#L1050), [`core/dr-gpu/src/adjust.rs:1363`](../../core/dr-gpu/src/adjust.rs#L1363), [`core/dr-gpu/src/adjust.rs:1457`](../../core/dr-gpu/src/adjust.rs#L1457), [`core/dr-gpu/src/adjust.rs:74`](../../core/dr-gpu/src/adjust.rs#L74), [`core/dr-gpu/tests/capture_sharpen.rs:433`](../../core/dr-gpu/tests/capture_sharpen.rs#L433), [`core/dr-gpu/tests/detail_stage.rs:241`](../../core/dr-gpu/tests/detail_stage.rs#L241), [`core/dr-gpu/tests/local_contrast.rs:557`](../../core/dr-gpu/tests/local_contrast.rs#L557), [`core/dr-gpu/tests/noise_reduction.rs:555`](../../core/dr-gpu/tests/noise_reduction.rs#L555), [`core/dr-pipeline/src/framing.rs:481`](../../core/dr-pipeline/src/framing.rs#L481), [`core/dr-pipeline/src/graph.rs:1044`](../../core/dr-pipeline/src/graph.rs#L1044), [`core/dr-pipeline/src/operation.rs:32`](../../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:492`](../../core/dr-pipeline/src/operation.rs#L492), [`core/dr-pipeline/src/operation.rs:53`](../../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../../core/dr-pipeline/src/operation.rs#L71) | -| FR-DEV-3e | [`core/dr-decode/src/dcp.rs:126`](../../core/dr-decode/src/dcp.rs#L126), [`core/dr-decode/src/dcp.rs:157`](../../core/dr-decode/src/dcp.rs#L157), [`core/dr-decode/src/dcp.rs:176`](../../core/dr-decode/src/dcp.rs#L176), [`core/dr-decode/src/dcp.rs:199`](../../core/dr-decode/src/dcp.rs#L199), [`core/dr-decode/src/dcp.rs:1`](../../core/dr-decode/src/dcp.rs#L1), [`core/dr-decode/src/dcp.rs:230`](../../core/dr-decode/src/dcp.rs#L230), [`core/dr-decode/src/dcp.rs:403`](../../core/dr-decode/src/dcp.rs#L403), [`core/dr-decode/src/dcp.rs:454`](../../core/dr-decode/src/dcp.rs#L454), [`core/dr-decode/src/dcp.rs:465`](../../core/dr-decode/src/dcp.rs#L465), [`core/dr-decode/src/dcp.rs:498`](../../core/dr-decode/src/dcp.rs#L498), [`core/dr-decode/src/dcp.rs:513`](../../core/dr-decode/src/dcp.rs#L513), [`core/dr-decode/src/dcp.rs:523`](../../core/dr-decode/src/dcp.rs#L523), [`core/dr-decode/src/dcp.rs:74`](../../core/dr-decode/src/dcp.rs#L74), [`core/dr-decode/src/lib.rs:126`](../../core/dr-decode/src/lib.rs#L126), [`core/dr-decode/src/lib.rs:141`](../../core/dr-decode/src/lib.rs#L141), [`core/dr-decode/src/lib.rs:584`](../../core/dr-decode/src/lib.rs#L584), [`core/dr-decode/src/lib.rs:780`](../../core/dr-decode/src/lib.rs#L780), [`core/dr-decode/src/lib.rs:820`](../../core/dr-decode/src/lib.rs#L820), [`core/dr-decode/src/profile.rs:104`](../../core/dr-decode/src/profile.rs#L104), [`core/dr-decode/src/profile.rs:153`](../../core/dr-decode/src/profile.rs#L153), [`core/dr-decode/src/profile.rs:1`](../../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:237`](../../core/dr-decode/src/profile.rs#L237), [`core/dr-decode/src/profile.rs:288`](../../core/dr-decode/src/profile.rs#L288), [`core/dr-decode/src/profile.rs:345`](../../core/dr-decode/src/profile.rs#L345), [`core/dr-decode/src/profile.rs:475`](../../core/dr-decode/src/profile.rs#L475), [`core/dr-decode/src/profile.rs:509`](../../core/dr-decode/src/profile.rs#L509), [`core/dr-decode/src/profile.rs:680`](../../core/dr-decode/src/profile.rs#L680), [`core/dr-pipeline/src/declared/decl.rs:279`](../../core/dr-pipeline/src/declared/decl.rs#L279), [`core/dr-pipeline/src/operation.rs:2441`](../../core/dr-pipeline/src/operation.rs#L2441), [`core/dr-pipeline/src/operation.rs:2465`](../../core/dr-pipeline/src/operation.rs#L2465), [`core/dr-pipeline/src/operation.rs:336`](../../core/dr-pipeline/src/operation.rs#L336), [`core/dr-pipeline/src/operation.rs:356`](../../core/dr-pipeline/src/operation.rs#L356), [`core/dr-pipeline/src/operation.rs:430`](../../core/dr-pipeline/src/operation.rs#L430), [`core/dr-pipeline/src/operation.rs:450`](../../core/dr-pipeline/src/operation.rs#L450), [`core/dr-pipeline/src/view.rs:227`](../../core/dr-pipeline/src/view.rs#L227), [`core/dr-types/src/hue_sat.rs:1`](../../core/dr-types/src/hue_sat.rs#L1) | -| FR-DEV-3f | [`core/dr-film/src/bake.rs:161`](../../core/dr-film/src/bake.rs#L161), [`core/dr-film/src/bake.rs:384`](../../core/dr-film/src/bake.rs#L384), [`core/dr-film/src/bake.rs:52`](../../core/dr-film/src/bake.rs#L52), [`core/dr-film/src/bake.rs:662`](../../core/dr-film/src/bake.rs#L662), [`core/dr-film/src/bake.rs:689`](../../core/dr-film/src/bake.rs#L689), [`core/dr-film/src/bake.rs:710`](../../core/dr-film/src/bake.rs#L710), [`core/dr-film/src/bake.rs:747`](../../core/dr-film/src/bake.rs#L747), [`core/dr-film/src/bake.rs:95`](../../core/dr-film/src/bake.rs#L95), [`core/dr-film/src/boolean_grain.rs:1`](../../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:144`](../../core/dr-gpu/src/adjust.rs#L144), [`core/dr-gpu/src/adjust.rs:414`](../../core/dr-gpu/src/adjust.rs#L414), [`core/dr-gpu/src/adjust.rs:593`](../../core/dr-gpu/src/adjust.rs#L593), [`core/dr-gpu/src/adjust.rs:67`](../../core/dr-gpu/src/adjust.rs#L67), [`core/dr-gpu/src/adjust.rs:724`](../../core/dr-gpu/src/adjust.rs#L724), [`core/dr-gpu/tests/film_sim.rs:1`](../../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-gpu/tests/film_sim.rs:214`](../../core/dr-gpu/tests/film_sim.rs#L214), [`core/dr-gpu/tests/film_sim.rs:348`](../../core/dr-gpu/tests/film_sim.rs#L348), [`core/dr-gpu/tests/film_sim.rs:387`](../../core/dr-gpu/tests/film_sim.rs#L387), [`core/dr-gpu/tests/film_sim.rs:416`](../../core/dr-gpu/tests/film_sim.rs#L416), [`core/dr-gpu/tests/film_sim.rs:456`](../../core/dr-gpu/tests/film_sim.rs#L456), [`core/dr-pipeline/src/graph.rs:110`](../../core/dr-pipeline/src/graph.rs#L110), [`core/dr-pipeline/src/graph.rs:175`](../../core/dr-pipeline/src/graph.rs#L175), [`core/dr-pipeline/src/graph.rs:624`](../../core/dr-pipeline/src/graph.rs#L624), [`core/dr-pipeline/src/mask.rs:2452`](../../core/dr-pipeline/src/mask.rs#L2452), [`core/dr-pipeline/src/mask.rs:2485`](../../core/dr-pipeline/src/mask.rs#L2485), [`core/dr-pipeline/src/operation.rs:1073`](../../core/dr-pipeline/src/operation.rs#L1073), [`core/dr-pipeline/src/operation.rs:1418`](../../core/dr-pipeline/src/operation.rs#L1418), [`core/dr-pipeline/src/operation.rs:1652`](../../core/dr-pipeline/src/operation.rs#L1652), [`core/dr-pipeline/src/operation.rs:1680`](../../core/dr-pipeline/src/operation.rs#L1680), [`core/dr-pipeline/src/operation.rs:1732`](../../core/dr-pipeline/src/operation.rs#L1732), [`core/dr-pipeline/src/operation.rs:2359`](../../core/dr-pipeline/src/operation.rs#L2359), [`core/dr-pipeline/src/operation.rs:296`](../../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:321`](../../core/dr-pipeline/src/operation.rs#L321), [`core/dr-pipeline/src/operation.rs:336`](../../core/dr-pipeline/src/operation.rs#L336), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:134`](../../core/dr-pipeline/src/ops/film_sim.rs#L134), [`core/dr-pipeline/src/ops/film_sim.rs:186`](../../core/dr-pipeline/src/ops/film_sim.rs#L186), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:233`](../../core/dr-pipeline/src/ops/film_sim.rs#L233), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/film_sim.rs:329`](../../core/dr-pipeline/src/ops/film_sim.rs#L329), [`core/dr-pipeline/src/ops/film_sim.rs:438`](../../core/dr-pipeline/src/ops/film_sim.rs#L438), [`core/dr-pipeline/src/ops/film_sim.rs:48`](../../core/dr-pipeline/src/ops/film_sim.rs#L48), [`core/dr-pipeline/src/ops/film_sim.rs:736`](../../core/dr-pipeline/src/ops/film_sim.rs#L736), [`core/dr-pipeline/src/preset.rs:1293`](../../core/dr-pipeline/src/preset.rs#L1293), [`core/dr-pipeline/src/preset.rs:1303`](../../core/dr-pipeline/src/preset.rs#L1303), [`core/dr-pipeline/src/preset.rs:1312`](../../core/dr-pipeline/src/preset.rs#L1312), [`core/dr-pipeline/src/preset.rs:1328`](../../core/dr-pipeline/src/preset.rs#L1328), [`core/dr-pipeline/src/preset.rs:1340`](../../core/dr-pipeline/src/preset.rs#L1340), [`core/dr-pipeline/src/preset.rs:1356`](../../core/dr-pipeline/src/preset.rs#L1356), [`core/dr-pipeline/src/preset.rs:1529`](../../core/dr-pipeline/src/preset.rs#L1529), [`core/dr-pipeline/src/preset.rs:1544`](../../core/dr-pipeline/src/preset.rs#L1544), [`core/dr-pipeline/src/preset.rs:248`](../../core/dr-pipeline/src/preset.rs#L248), [`core/dr-pipeline/src/preset.rs:689`](../../core/dr-pipeline/src/preset.rs#L689), [`core/dr-pipeline/src/preset.rs:778`](../../core/dr-pipeline/src/preset.rs#L778), [`core/dr-pipeline/src/sidecar.rs:1077`](../../core/dr-pipeline/src/sidecar.rs#L1077), [`core/dr-pipeline/src/sidecar.rs:133`](../../core/dr-pipeline/src/sidecar.rs#L133), [`core/dr-pipeline/src/sidecar.rs:217`](../../core/dr-pipeline/src/sidecar.rs#L217), [`core/dr-pipeline/src/sidecar.rs:2724`](../../core/dr-pipeline/src/sidecar.rs#L2724), [`core/dr-pipeline/src/sidecar.rs:2800`](../../core/dr-pipeline/src/sidecar.rs#L2800), [`core/dr-pipeline/src/sidecar.rs:595`](../../core/dr-pipeline/src/sidecar.rs#L595), [`core/dr-pipeline/src/sidecar.rs:898`](../../core/dr-pipeline/src/sidecar.rs#L898), [`core/dr-pipeline/src/state.rs:100`](../../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop/render.rs:1046`](../../ui/dr-ui/src/develop/render.rs#L1046), [`ui/dr-ui/src/develop/render.rs:1072`](../../ui/dr-ui/src/develop/render.rs#L1072), [`ui/dr-ui/src/develop/render.rs:1395`](../../ui/dr-ui/src/develop/render.rs#L1395), [`ui/dr-ui/src/develop/render.rs:1435`](../../ui/dr-ui/src/develop/render.rs#L1435), [`ui/dr-ui/src/develop/render.rs:1470`](../../ui/dr-ui/src/develop/render.rs#L1470), [`ui/dr-ui/src/develop/render.rs:823`](../../ui/dr-ui/src/develop/render.rs#L823), [`ui/dr-ui/src/develop/render.rs:840`](../../ui/dr-ui/src/develop/render.rs#L840), [`ui/dr-ui/src/develop/render.rs:852`](../../ui/dr-ui/src/develop/render.rs#L852), [`ui/dr-ui/src/develop/render.rs:890`](../../ui/dr-ui/src/develop/render.rs#L890), [`ui/dr-ui/src/develop/render.rs:927`](../../ui/dr-ui/src/develop/render.rs#L927), [`ui/dr-ui/src/develop/render.rs:938`](../../ui/dr-ui/src/develop/render.rs#L938), [`ui/dr-ui/src/develop/render.rs:995`](../../ui/dr-ui/src/develop/render.rs#L995), [`ui/dr-ui/src/develop/session.rs:642`](../../ui/dr-ui/src/develop/session.rs#L642), [`ui/dr-ui/src/develop/session.rs:662`](../../ui/dr-ui/src/develop/session.rs#L662), [`ui/dr-ui/src/develop/tabs.rs:80`](../../ui/dr-ui/src/develop/tabs.rs#L80), [`ui/dr-ui/src/develop_ui.rs:454`](../../ui/dr-ui/src/develop_ui.rs#L454), [`ui/dr-ui/src/lib.rs:871`](../../ui/dr-ui/src/lib.rs#L871), [`ui/dr-ui/src/lib.rs:936`](../../ui/dr-ui/src/lib.rs#L936), [`ui/dr-ui/src/library/sidecar.rs:325`](../../ui/dr-ui/src/library/sidecar.rs#L325), [`ui/dr-ui/src/library/sidecar.rs:50`](../../ui/dr-ui/src/library/sidecar.rs#L50), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:602`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L602), [`ui/dr-ui/src/presets.rs:1892`](../../ui/dr-ui/src/presets.rs#L1892), [`ui/dr-ui/src/presets.rs:422`](../../ui/dr-ui/src/presets.rs#L422), [`ui/dr-ui/tests/film_list_reaches_every_stock.rs:1`](../../ui/dr-ui/tests/film_list_reaches_every_stock.rs#L1), [`ui/dr-ui/ui/adjust.slint:1071`](../../ui/dr-ui/ui/adjust.slint#L1071), [`ui/dr-ui/ui/adjust.slint:1081`](../../ui/dr-ui/ui/adjust.slint#L1081), [`ui/dr-ui/ui/adjust.slint:1298`](../../ui/dr-ui/ui/adjust.slint#L1298) | +| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/adjust.rs:112`](../../core/dr-gpu/src/adjust.rs#L112), [`core/dr-gpu/src/adjust.rs:1429`](../../core/dr-gpu/src/adjust.rs#L1429), [`core/dr-gpu/src/adjust.rs:1523`](../../core/dr-gpu/src/adjust.rs#L1523), [`core/dr-gpu/src/adjust.rs:82`](../../core/dr-gpu/src/adjust.rs#L82), [`core/dr-gpu/tests/capture_sharpen.rs:433`](../../core/dr-gpu/tests/capture_sharpen.rs#L433), [`core/dr-gpu/tests/detail_stage.rs:241`](../../core/dr-gpu/tests/detail_stage.rs#L241), [`core/dr-gpu/tests/local_contrast.rs:557`](../../core/dr-gpu/tests/local_contrast.rs#L557), [`core/dr-gpu/tests/noise_reduction.rs:555`](../../core/dr-gpu/tests/noise_reduction.rs#L555), [`core/dr-pipeline/src/framing.rs:481`](../../core/dr-pipeline/src/framing.rs#L481), [`core/dr-pipeline/src/graph.rs:1044`](../../core/dr-pipeline/src/graph.rs#L1044), [`core/dr-pipeline/src/operation.rs:32`](../../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:505`](../../core/dr-pipeline/src/operation.rs#L505), [`core/dr-pipeline/src/operation.rs:53`](../../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../../core/dr-pipeline/src/operation.rs#L71) | +| FR-DEV-3e | [`core/dr-decode/src/dcp.rs:126`](../../core/dr-decode/src/dcp.rs#L126), [`core/dr-decode/src/dcp.rs:157`](../../core/dr-decode/src/dcp.rs#L157), [`core/dr-decode/src/dcp.rs:176`](../../core/dr-decode/src/dcp.rs#L176), [`core/dr-decode/src/dcp.rs:199`](../../core/dr-decode/src/dcp.rs#L199), [`core/dr-decode/src/dcp.rs:1`](../../core/dr-decode/src/dcp.rs#L1), [`core/dr-decode/src/dcp.rs:230`](../../core/dr-decode/src/dcp.rs#L230), [`core/dr-decode/src/dcp.rs:403`](../../core/dr-decode/src/dcp.rs#L403), [`core/dr-decode/src/dcp.rs:454`](../../core/dr-decode/src/dcp.rs#L454), [`core/dr-decode/src/dcp.rs:465`](../../core/dr-decode/src/dcp.rs#L465), [`core/dr-decode/src/dcp.rs:498`](../../core/dr-decode/src/dcp.rs#L498), [`core/dr-decode/src/dcp.rs:513`](../../core/dr-decode/src/dcp.rs#L513), [`core/dr-decode/src/dcp.rs:523`](../../core/dr-decode/src/dcp.rs#L523), [`core/dr-decode/src/dcp.rs:74`](../../core/dr-decode/src/dcp.rs#L74), [`core/dr-decode/src/lib.rs:126`](../../core/dr-decode/src/lib.rs#L126), [`core/dr-decode/src/lib.rs:141`](../../core/dr-decode/src/lib.rs#L141), [`core/dr-decode/src/lib.rs:584`](../../core/dr-decode/src/lib.rs#L584), [`core/dr-decode/src/lib.rs:780`](../../core/dr-decode/src/lib.rs#L780), [`core/dr-decode/src/lib.rs:820`](../../core/dr-decode/src/lib.rs#L820), [`core/dr-decode/src/profile.rs:104`](../../core/dr-decode/src/profile.rs#L104), [`core/dr-decode/src/profile.rs:153`](../../core/dr-decode/src/profile.rs#L153), [`core/dr-decode/src/profile.rs:1`](../../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:237`](../../core/dr-decode/src/profile.rs#L237), [`core/dr-decode/src/profile.rs:288`](../../core/dr-decode/src/profile.rs#L288), [`core/dr-decode/src/profile.rs:345`](../../core/dr-decode/src/profile.rs#L345), [`core/dr-decode/src/profile.rs:475`](../../core/dr-decode/src/profile.rs#L475), [`core/dr-decode/src/profile.rs:509`](../../core/dr-decode/src/profile.rs#L509), [`core/dr-decode/src/profile.rs:680`](../../core/dr-decode/src/profile.rs#L680), [`core/dr-gpu/src/adjust.rs:523`](../../core/dr-gpu/src/adjust.rs#L523), [`core/dr-gpu/src/adjust.rs:536`](../../core/dr-gpu/src/adjust.rs#L536), [`core/dr-gpu/src/adjust.rs:74`](../../core/dr-gpu/src/adjust.rs#L74), [`core/dr-gpu/src/demosaic.rs:110`](../../core/dr-gpu/src/demosaic.rs#L110), [`core/dr-gpu/src/demosaic.rs:215`](../../core/dr-gpu/src/demosaic.rs#L215), [`core/dr-gpu/tests/camera_profile.rs:1`](../../core/dr-gpu/tests/camera_profile.rs#L1), [`core/dr-pipeline/src/declared/decl.rs:279`](../../core/dr-pipeline/src/declared/decl.rs#L279), [`core/dr-pipeline/src/operation.rs:2459`](../../core/dr-pipeline/src/operation.rs#L2459), [`core/dr-pipeline/src/operation.rs:2483`](../../core/dr-pipeline/src/operation.rs#L2483), [`core/dr-pipeline/src/operation.rs:273`](../../core/dr-pipeline/src/operation.rs#L273), [`core/dr-pipeline/src/operation.rs:349`](../../core/dr-pipeline/src/operation.rs#L349), [`core/dr-pipeline/src/operation.rs:369`](../../core/dr-pipeline/src/operation.rs#L369), [`core/dr-pipeline/src/operation.rs:443`](../../core/dr-pipeline/src/operation.rs#L443), [`core/dr-pipeline/src/operation.rs:463`](../../core/dr-pipeline/src/operation.rs#L463), [`core/dr-pipeline/src/ops/camera_profile.rs:1`](../../core/dr-pipeline/src/ops/camera_profile.rs#L1), [`core/dr-pipeline/src/ops/camera_profile.rs:355`](../../core/dr-pipeline/src/ops/camera_profile.rs#L355), [`core/dr-pipeline/src/ops/camera_profile.rs:381`](../../core/dr-pipeline/src/ops/camera_profile.rs#L381), [`core/dr-pipeline/src/view.rs:227`](../../core/dr-pipeline/src/view.rs#L227), [`core/dr-types/src/hue_sat.rs:1`](../../core/dr-types/src/hue_sat.rs#L1) | +| FR-DEV-3f | [`core/dr-film/src/bake.rs:161`](../../core/dr-film/src/bake.rs#L161), [`core/dr-film/src/bake.rs:384`](../../core/dr-film/src/bake.rs#L384), [`core/dr-film/src/bake.rs:52`](../../core/dr-film/src/bake.rs#L52), [`core/dr-film/src/bake.rs:662`](../../core/dr-film/src/bake.rs#L662), [`core/dr-film/src/bake.rs:689`](../../core/dr-film/src/bake.rs#L689), [`core/dr-film/src/bake.rs:710`](../../core/dr-film/src/bake.rs#L710), [`core/dr-film/src/bake.rs:747`](../../core/dr-film/src/bake.rs#L747), [`core/dr-film/src/bake.rs:95`](../../core/dr-film/src/bake.rs#L95), [`core/dr-film/src/boolean_grain.rs:1`](../../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:152`](../../core/dr-gpu/src/adjust.rs#L152), [`core/dr-gpu/src/adjust.rs:422`](../../core/dr-gpu/src/adjust.rs#L422), [`core/dr-gpu/src/adjust.rs:632`](../../core/dr-gpu/src/adjust.rs#L632), [`core/dr-gpu/src/adjust.rs:67`](../../core/dr-gpu/src/adjust.rs#L67), [`core/dr-gpu/src/adjust.rs:765`](../../core/dr-gpu/src/adjust.rs#L765), [`core/dr-gpu/tests/film_sim.rs:1`](../../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-gpu/tests/film_sim.rs:214`](../../core/dr-gpu/tests/film_sim.rs#L214), [`core/dr-gpu/tests/film_sim.rs:348`](../../core/dr-gpu/tests/film_sim.rs#L348), [`core/dr-gpu/tests/film_sim.rs:387`](../../core/dr-gpu/tests/film_sim.rs#L387), [`core/dr-gpu/tests/film_sim.rs:416`](../../core/dr-gpu/tests/film_sim.rs#L416), [`core/dr-gpu/tests/film_sim.rs:456`](../../core/dr-gpu/tests/film_sim.rs#L456), [`core/dr-pipeline/src/graph.rs:110`](../../core/dr-pipeline/src/graph.rs#L110), [`core/dr-pipeline/src/graph.rs:175`](../../core/dr-pipeline/src/graph.rs#L175), [`core/dr-pipeline/src/graph.rs:624`](../../core/dr-pipeline/src/graph.rs#L624), [`core/dr-pipeline/src/mask.rs:2452`](../../core/dr-pipeline/src/mask.rs#L2452), [`core/dr-pipeline/src/mask.rs:2485`](../../core/dr-pipeline/src/mask.rs#L2485), [`core/dr-pipeline/src/operation.rs:1086`](../../core/dr-pipeline/src/operation.rs#L1086), [`core/dr-pipeline/src/operation.rs:1436`](../../core/dr-pipeline/src/operation.rs#L1436), [`core/dr-pipeline/src/operation.rs:1670`](../../core/dr-pipeline/src/operation.rs#L1670), [`core/dr-pipeline/src/operation.rs:1698`](../../core/dr-pipeline/src/operation.rs#L1698), [`core/dr-pipeline/src/operation.rs:1750`](../../core/dr-pipeline/src/operation.rs#L1750), [`core/dr-pipeline/src/operation.rs:2377`](../../core/dr-pipeline/src/operation.rs#L2377), [`core/dr-pipeline/src/operation.rs:309`](../../core/dr-pipeline/src/operation.rs#L309), [`core/dr-pipeline/src/operation.rs:323`](../../core/dr-pipeline/src/operation.rs#L323), [`core/dr-pipeline/src/operation.rs:334`](../../core/dr-pipeline/src/operation.rs#L334), [`core/dr-pipeline/src/operation.rs:349`](../../core/dr-pipeline/src/operation.rs#L349), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:134`](../../core/dr-pipeline/src/ops/film_sim.rs#L134), [`core/dr-pipeline/src/ops/film_sim.rs:186`](../../core/dr-pipeline/src/ops/film_sim.rs#L186), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:233`](../../core/dr-pipeline/src/ops/film_sim.rs#L233), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/film_sim.rs:329`](../../core/dr-pipeline/src/ops/film_sim.rs#L329), [`core/dr-pipeline/src/ops/film_sim.rs:438`](../../core/dr-pipeline/src/ops/film_sim.rs#L438), [`core/dr-pipeline/src/ops/film_sim.rs:48`](../../core/dr-pipeline/src/ops/film_sim.rs#L48), [`core/dr-pipeline/src/ops/film_sim.rs:736`](../../core/dr-pipeline/src/ops/film_sim.rs#L736), [`core/dr-pipeline/src/preset.rs:1293`](../../core/dr-pipeline/src/preset.rs#L1293), [`core/dr-pipeline/src/preset.rs:1303`](../../core/dr-pipeline/src/preset.rs#L1303), [`core/dr-pipeline/src/preset.rs:1312`](../../core/dr-pipeline/src/preset.rs#L1312), [`core/dr-pipeline/src/preset.rs:1328`](../../core/dr-pipeline/src/preset.rs#L1328), [`core/dr-pipeline/src/preset.rs:1340`](../../core/dr-pipeline/src/preset.rs#L1340), [`core/dr-pipeline/src/preset.rs:1356`](../../core/dr-pipeline/src/preset.rs#L1356), [`core/dr-pipeline/src/preset.rs:1529`](../../core/dr-pipeline/src/preset.rs#L1529), [`core/dr-pipeline/src/preset.rs:1544`](../../core/dr-pipeline/src/preset.rs#L1544), [`core/dr-pipeline/src/preset.rs:248`](../../core/dr-pipeline/src/preset.rs#L248), [`core/dr-pipeline/src/preset.rs:689`](../../core/dr-pipeline/src/preset.rs#L689), [`core/dr-pipeline/src/preset.rs:778`](../../core/dr-pipeline/src/preset.rs#L778), [`core/dr-pipeline/src/sidecar.rs:1077`](../../core/dr-pipeline/src/sidecar.rs#L1077), [`core/dr-pipeline/src/sidecar.rs:133`](../../core/dr-pipeline/src/sidecar.rs#L133), [`core/dr-pipeline/src/sidecar.rs:217`](../../core/dr-pipeline/src/sidecar.rs#L217), [`core/dr-pipeline/src/sidecar.rs:2724`](../../core/dr-pipeline/src/sidecar.rs#L2724), [`core/dr-pipeline/src/sidecar.rs:2800`](../../core/dr-pipeline/src/sidecar.rs#L2800), [`core/dr-pipeline/src/sidecar.rs:595`](../../core/dr-pipeline/src/sidecar.rs#L595), [`core/dr-pipeline/src/sidecar.rs:898`](../../core/dr-pipeline/src/sidecar.rs#L898), [`core/dr-pipeline/src/state.rs:100`](../../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop/render.rs:1046`](../../ui/dr-ui/src/develop/render.rs#L1046), [`ui/dr-ui/src/develop/render.rs:1072`](../../ui/dr-ui/src/develop/render.rs#L1072), [`ui/dr-ui/src/develop/render.rs:1395`](../../ui/dr-ui/src/develop/render.rs#L1395), [`ui/dr-ui/src/develop/render.rs:1435`](../../ui/dr-ui/src/develop/render.rs#L1435), [`ui/dr-ui/src/develop/render.rs:1470`](../../ui/dr-ui/src/develop/render.rs#L1470), [`ui/dr-ui/src/develop/render.rs:823`](../../ui/dr-ui/src/develop/render.rs#L823), [`ui/dr-ui/src/develop/render.rs:840`](../../ui/dr-ui/src/develop/render.rs#L840), [`ui/dr-ui/src/develop/render.rs:852`](../../ui/dr-ui/src/develop/render.rs#L852), [`ui/dr-ui/src/develop/render.rs:890`](../../ui/dr-ui/src/develop/render.rs#L890), [`ui/dr-ui/src/develop/render.rs:927`](../../ui/dr-ui/src/develop/render.rs#L927), [`ui/dr-ui/src/develop/render.rs:938`](../../ui/dr-ui/src/develop/render.rs#L938), [`ui/dr-ui/src/develop/render.rs:995`](../../ui/dr-ui/src/develop/render.rs#L995), [`ui/dr-ui/src/develop/session.rs:642`](../../ui/dr-ui/src/develop/session.rs#L642), [`ui/dr-ui/src/develop/session.rs:662`](../../ui/dr-ui/src/develop/session.rs#L662), [`ui/dr-ui/src/develop/tabs.rs:80`](../../ui/dr-ui/src/develop/tabs.rs#L80), [`ui/dr-ui/src/develop_ui.rs:454`](../../ui/dr-ui/src/develop_ui.rs#L454), [`ui/dr-ui/src/lib.rs:871`](../../ui/dr-ui/src/lib.rs#L871), [`ui/dr-ui/src/lib.rs:936`](../../ui/dr-ui/src/lib.rs#L936), [`ui/dr-ui/src/library/sidecar.rs:325`](../../ui/dr-ui/src/library/sidecar.rs#L325), [`ui/dr-ui/src/library/sidecar.rs:50`](../../ui/dr-ui/src/library/sidecar.rs#L50), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:602`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L602), [`ui/dr-ui/src/presets.rs:1892`](../../ui/dr-ui/src/presets.rs#L1892), [`ui/dr-ui/src/presets.rs:422`](../../ui/dr-ui/src/presets.rs#L422), [`ui/dr-ui/tests/film_list_reaches_every_stock.rs:1`](../../ui/dr-ui/tests/film_list_reaches_every_stock.rs#L1), [`ui/dr-ui/ui/adjust.slint:1071`](../../ui/dr-ui/ui/adjust.slint#L1071), [`ui/dr-ui/ui/adjust.slint:1081`](../../ui/dr-ui/ui/adjust.slint#L1081), [`ui/dr-ui/ui/adjust.slint:1298`](../../ui/dr-ui/ui/adjust.slint#L1298) | | FR-DEV-3h | [`core/dr-decode/src/lib.rs:445`](../../core/dr-decode/src/lib.rs#L445), [`core/dr-decode/src/preview.rs:29`](../../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1492`](../../core/dr-pipeline/src/framing.rs#L1492), [`core/dr-pipeline/src/framing.rs:499`](../../core/dr-pipeline/src/framing.rs#L499), [`core/dr-pipeline/src/framing.rs:717`](../../core/dr-pipeline/src/framing.rs#L717), [`core/dr-types/src/lib.rs:341`](../../core/dr-types/src/lib.rs#L341), [`core/dr-types/src/lib.rs:449`](../../core/dr-types/src/lib.rs#L449), [`core/dr-types/src/lib.rs:461`](../../core/dr-types/src/lib.rs#L461), [`core/dr-types/src/lib.rs:477`](../../core/dr-types/src/lib.rs#L477), [`ui/dr-ui/src/develop/masks.rs:280`](../../ui/dr-ui/src/develop/masks.rs#L280), [`ui/dr-ui/src/develop/segmentation.rs:114`](../../ui/dr-ui/src/develop/segmentation.rs#L114), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499) | | FR-DEV-3i | [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-segment/src/lib.rs:1`](../../core/dr-segment/src/lib.rs#L1), [`ui/dr-ui/src/segmentation.rs:1`](../../ui/dr-ui/src/segmentation.rs#L1) | -| FR-DEV-3j | [`core/dr-gpu/src/adjust.rs:1239`](../../core/dr-gpu/src/adjust.rs#L1239), [`core/dr-gpu/src/adjust.rs:1473`](../../core/dr-gpu/src/adjust.rs#L1473), [`core/dr-gpu/src/adjust.rs:3322`](../../core/dr-gpu/src/adjust.rs#L3322), [`core/dr-gpu/tests/scene_referred.rs:144`](../../core/dr-gpu/tests/scene_referred.rs#L144), [`core/dr-gpu/tests/scene_referred.rs:1`](../../core/dr-gpu/tests/scene_referred.rs#L1), [`core/dr-gpu/tests/view_transform.rs:115`](../../core/dr-gpu/tests/view_transform.rs#L115), [`core/dr-gpu/tests/view_transform.rs:153`](../../core/dr-gpu/tests/view_transform.rs#L153), [`core/dr-gpu/tests/view_transform.rs:1`](../../core/dr-gpu/tests/view_transform.rs#L1), [`core/dr-gpu/tests/view_transform.rs:66`](../../core/dr-gpu/tests/view_transform.rs#L66), [`core/dr-gpu/tests/view_transform.rs:89`](../../core/dr-gpu/tests/view_transform.rs#L89), [`core/dr-pipeline/src/operation.rs:1396`](../../core/dr-pipeline/src/operation.rs#L1396), [`core/dr-pipeline/src/operation.rs:2359`](../../core/dr-pipeline/src/operation.rs#L2359), [`core/dr-pipeline/src/operation.rs:2475`](../../core/dr-pipeline/src/operation.rs#L2475), [`core/dr-pipeline/src/operation.rs:2492`](../../core/dr-pipeline/src/operation.rs#L2492), [`core/dr-pipeline/src/operation.rs:2682`](../../core/dr-pipeline/src/operation.rs#L2682), [`core/dr-pipeline/src/operation.rs:2720`](../../core/dr-pipeline/src/operation.rs#L2720), [`core/dr-pipeline/src/operation.rs:567`](../../core/dr-pipeline/src/operation.rs#L567), [`core/dr-pipeline/src/operation.rs:867`](../../core/dr-pipeline/src/operation.rs#L867), [`core/dr-pipeline/src/operation.rs:917`](../../core/dr-pipeline/src/operation.rs#L917), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/view_transform.rs:168`](../../core/dr-pipeline/src/ops/view_transform.rs#L168), [`core/dr-pipeline/src/ops/view_transform.rs:1`](../../core/dr-pipeline/src/ops/view_transform.rs#L1), [`core/dr-pipeline/src/view.rs:184`](../../core/dr-pipeline/src/view.rs#L184), [`core/dr-pipeline/src/view.rs:197`](../../core/dr-pipeline/src/view.rs#L197), [`core/dr-pipeline/src/view.rs:1`](../../core/dr-pipeline/src/view.rs#L1), [`core/dr-pipeline/src/view.rs:211`](../../core/dr-pipeline/src/view.rs#L211), [`core/dr-pipeline/src/view.rs:227`](../../core/dr-pipeline/src/view.rs#L227), [`core/dr-pipeline/src/view.rs:241`](../../core/dr-pipeline/src/view.rs#L241), [`core/dr-pipeline/src/view.rs:252`](../../core/dr-pipeline/src/view.rs#L252) | -| FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:1050`](../../core/dr-gpu/src/adjust.rs#L1050), [`core/dr-gpu/src/lib.rs:368`](../../core/dr-gpu/src/lib.rs#L368), [`ui/dr-ui/ui/crop.slint:1`](../../ui/dr-ui/ui/crop.slint#L1) | -| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:1503`](../../core/dr-pipeline/src/graph.rs#L1503), [`core/dr-pipeline/src/graph.rs:645`](../../core/dr-pipeline/src/graph.rs#L645), [`core/dr-pipeline/src/graph.rs:700`](../../core/dr-pipeline/src/graph.rs#L700), [`core/dr-pipeline/src/history.rs:102`](../../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/sidecar.rs:1067`](../../core/dr-pipeline/src/sidecar.rs#L1067), [`core/dr-pipeline/src/sidecar.rs:147`](../../core/dr-pipeline/src/sidecar.rs#L147), [`core/dr-pipeline/src/sidecar.rs:2515`](../../core/dr-pipeline/src/sidecar.rs#L2515), [`core/dr-pipeline/src/sidecar.rs:2551`](../../core/dr-pipeline/src/sidecar.rs#L2551), [`core/dr-pipeline/src/sidecar.rs:2563`](../../core/dr-pipeline/src/sidecar.rs#L2563), [`core/dr-pipeline/src/sidecar.rs:318`](../../core/dr-pipeline/src/sidecar.rs#L318), [`core/dr-pipeline/src/sidecar.rs:713`](../../core/dr-pipeline/src/sidecar.rs#L713), [`core/dr-pipeline/src/sidecar.rs:729`](../../core/dr-pipeline/src/sidecar.rs#L729), [`core/dr-pipeline/src/sidecar.rs:876`](../../core/dr-pipeline/src/sidecar.rs#L876), [`core/dr-pipeline/src/state.rs:1`](../../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop/framing.rs:945`](../../ui/dr-ui/src/develop/framing.rs#L945), [`ui/dr-ui/src/develop/history.rs:11`](../../ui/dr-ui/src/develop/history.rs#L11), [`ui/dr-ui/src/develop/history.rs:152`](../../ui/dr-ui/src/develop/history.rs#L152), [`ui/dr-ui/src/develop/history.rs:165`](../../ui/dr-ui/src/develop/history.rs#L165), [`ui/dr-ui/src/develop/history.rs:178`](../../ui/dr-ui/src/develop/history.rs#L178), [`ui/dr-ui/src/develop/history.rs:190`](../../ui/dr-ui/src/develop/history.rs#L190), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:242`](../../ui/dr-ui/src/develop/history.rs#L242), [`ui/dr-ui/src/develop/history.rs:261`](../../ui/dr-ui/src/develop/history.rs#L261), [`ui/dr-ui/src/develop/history.rs:277`](../../ui/dr-ui/src/develop/history.rs#L277), [`ui/dr-ui/src/develop/history.rs:299`](../../ui/dr-ui/src/develop/history.rs#L299), [`ui/dr-ui/src/develop/history.rs:29`](../../ui/dr-ui/src/develop/history.rs#L29), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/history.rs:68`](../../ui/dr-ui/src/develop/history.rs#L68), [`ui/dr-ui/src/develop/history.rs:82`](../../ui/dr-ui/src/develop/history.rs#L82), [`ui/dr-ui/src/develop/history.rs:93`](../../ui/dr-ui/src/develop/history.rs#L93), [`ui/dr-ui/src/develop/render.rs:1072`](../../ui/dr-ui/src/develop/render.rs#L1072), [`ui/dr-ui/src/develop/render.rs:1108`](../../ui/dr-ui/src/develop/render.rs#L1108), [`ui/dr-ui/src/develop/render.rs:852`](../../ui/dr-ui/src/develop/render.rs#L852), [`ui/dr-ui/src/develop/session.rs:80`](../../ui/dr-ui/src/develop/session.rs#L80), [`ui/dr-ui/src/develop/session.rs:89`](../../ui/dr-ui/src/develop/session.rs#L89), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop_ui.rs:772`](../../ui/dr-ui/src/develop_ui.rs#L772), [`ui/dr-ui/src/develop_ui.rs:792`](../../ui/dr-ui/src/develop_ui.rs#L792), [`ui/dr-ui/src/labels.rs:12`](../../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:292`](../../ui/dr-ui/src/labels.rs#L292), [`ui/dr-ui/src/labels.rs:31`](../../ui/dr-ui/src/labels.rs#L31), [`ui/dr-ui/src/lib.rs:2109`](../../ui/dr-ui/src/lib.rs#L2109), [`ui/dr-ui/src/lib.rs:2114`](../../ui/dr-ui/src/lib.rs#L2114), [`ui/dr-ui/src/lib.rs:2146`](../../ui/dr-ui/src/lib.rs#L2146), [`ui/dr-ui/src/lib.rs:2155`](../../ui/dr-ui/src/lib.rs#L2155), [`ui/dr-ui/src/lib.rs:2172`](../../ui/dr-ui/src/lib.rs#L2172), [`ui/dr-ui/src/library/sidecar.rs:351`](../../ui/dr-ui/src/library/sidecar.rs#L351), [`ui/dr-ui/src/library/sidecar.rs:61`](../../ui/dr-ui/src/library/sidecar.rs#L61), [`ui/dr-ui/src/presets.rs:2076`](../../ui/dr-ui/src/presets.rs#L2076), [`ui/dr-ui/src/presets.rs:373`](../../ui/dr-ui/src/presets.rs#L373), [`ui/dr-ui/src/presets.rs:437`](../../ui/dr-ui/src/presets.rs#L437), [`ui/dr-ui/src/presets.rs:557`](../../ui/dr-ui/src/presets.rs#L557), [`ui/dr-ui/ui/history.slint:192`](../../ui/dr-ui/ui/history.slint#L192), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:219`](../../ui/dr-ui/ui/history.slint#L219), [`ui/dr-ui/ui/history.slint:304`](../../ui/dr-ui/ui/history.slint#L304), [`ui/dr-ui/ui/history.slint:43`](../../ui/dr-ui/ui/history.slint#L43), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53) | +| FR-DEV-3j | [`core/dr-gpu/src/adjust.rs:1301`](../../core/dr-gpu/src/adjust.rs#L1301), [`core/dr-gpu/src/adjust.rs:1539`](../../core/dr-gpu/src/adjust.rs#L1539), [`core/dr-gpu/src/adjust.rs:3392`](../../core/dr-gpu/src/adjust.rs#L3392), [`core/dr-gpu/tests/scene_referred.rs:144`](../../core/dr-gpu/tests/scene_referred.rs#L144), [`core/dr-gpu/tests/scene_referred.rs:1`](../../core/dr-gpu/tests/scene_referred.rs#L1), [`core/dr-gpu/tests/view_transform.rs:115`](../../core/dr-gpu/tests/view_transform.rs#L115), [`core/dr-gpu/tests/view_transform.rs:153`](../../core/dr-gpu/tests/view_transform.rs#L153), [`core/dr-gpu/tests/view_transform.rs:1`](../../core/dr-gpu/tests/view_transform.rs#L1), [`core/dr-gpu/tests/view_transform.rs:66`](../../core/dr-gpu/tests/view_transform.rs#L66), [`core/dr-gpu/tests/view_transform.rs:89`](../../core/dr-gpu/tests/view_transform.rs#L89), [`core/dr-pipeline/src/operation.rs:1414`](../../core/dr-pipeline/src/operation.rs#L1414), [`core/dr-pipeline/src/operation.rs:2377`](../../core/dr-pipeline/src/operation.rs#L2377), [`core/dr-pipeline/src/operation.rs:2493`](../../core/dr-pipeline/src/operation.rs#L2493), [`core/dr-pipeline/src/operation.rs:2510`](../../core/dr-pipeline/src/operation.rs#L2510), [`core/dr-pipeline/src/operation.rs:2700`](../../core/dr-pipeline/src/operation.rs#L2700), [`core/dr-pipeline/src/operation.rs:2738`](../../core/dr-pipeline/src/operation.rs#L2738), [`core/dr-pipeline/src/operation.rs:580`](../../core/dr-pipeline/src/operation.rs#L580), [`core/dr-pipeline/src/operation.rs:880`](../../core/dr-pipeline/src/operation.rs#L880), [`core/dr-pipeline/src/operation.rs:930`](../../core/dr-pipeline/src/operation.rs#L930), [`core/dr-pipeline/src/ops/film_sim.rs:315`](../../core/dr-pipeline/src/ops/film_sim.rs#L315), [`core/dr-pipeline/src/ops/view_transform.rs:168`](../../core/dr-pipeline/src/ops/view_transform.rs#L168), [`core/dr-pipeline/src/ops/view_transform.rs:1`](../../core/dr-pipeline/src/ops/view_transform.rs#L1), [`core/dr-pipeline/src/view.rs:184`](../../core/dr-pipeline/src/view.rs#L184), [`core/dr-pipeline/src/view.rs:197`](../../core/dr-pipeline/src/view.rs#L197), [`core/dr-pipeline/src/view.rs:1`](../../core/dr-pipeline/src/view.rs#L1), [`core/dr-pipeline/src/view.rs:211`](../../core/dr-pipeline/src/view.rs#L211), [`core/dr-pipeline/src/view.rs:227`](../../core/dr-pipeline/src/view.rs#L227), [`core/dr-pipeline/src/view.rs:241`](../../core/dr-pipeline/src/view.rs#L241), [`core/dr-pipeline/src/view.rs:252`](../../core/dr-pipeline/src/view.rs#L252) | +| FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/lib.rs:368`](../../core/dr-gpu/src/lib.rs#L368), [`ui/dr-ui/ui/crop.slint:1`](../../ui/dr-ui/ui/crop.slint#L1) | +| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:1506`](../../core/dr-pipeline/src/graph.rs#L1506), [`core/dr-pipeline/src/graph.rs:645`](../../core/dr-pipeline/src/graph.rs#L645), [`core/dr-pipeline/src/graph.rs:700`](../../core/dr-pipeline/src/graph.rs#L700), [`core/dr-pipeline/src/history.rs:102`](../../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/sidecar.rs:1067`](../../core/dr-pipeline/src/sidecar.rs#L1067), [`core/dr-pipeline/src/sidecar.rs:147`](../../core/dr-pipeline/src/sidecar.rs#L147), [`core/dr-pipeline/src/sidecar.rs:2515`](../../core/dr-pipeline/src/sidecar.rs#L2515), [`core/dr-pipeline/src/sidecar.rs:2551`](../../core/dr-pipeline/src/sidecar.rs#L2551), [`core/dr-pipeline/src/sidecar.rs:2563`](../../core/dr-pipeline/src/sidecar.rs#L2563), [`core/dr-pipeline/src/sidecar.rs:318`](../../core/dr-pipeline/src/sidecar.rs#L318), [`core/dr-pipeline/src/sidecar.rs:713`](../../core/dr-pipeline/src/sidecar.rs#L713), [`core/dr-pipeline/src/sidecar.rs:729`](../../core/dr-pipeline/src/sidecar.rs#L729), [`core/dr-pipeline/src/sidecar.rs:876`](../../core/dr-pipeline/src/sidecar.rs#L876), [`core/dr-pipeline/src/state.rs:1`](../../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop/framing.rs:945`](../../ui/dr-ui/src/develop/framing.rs#L945), [`ui/dr-ui/src/develop/history.rs:11`](../../ui/dr-ui/src/develop/history.rs#L11), [`ui/dr-ui/src/develop/history.rs:152`](../../ui/dr-ui/src/develop/history.rs#L152), [`ui/dr-ui/src/develop/history.rs:165`](../../ui/dr-ui/src/develop/history.rs#L165), [`ui/dr-ui/src/develop/history.rs:178`](../../ui/dr-ui/src/develop/history.rs#L178), [`ui/dr-ui/src/develop/history.rs:190`](../../ui/dr-ui/src/develop/history.rs#L190), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:242`](../../ui/dr-ui/src/develop/history.rs#L242), [`ui/dr-ui/src/develop/history.rs:261`](../../ui/dr-ui/src/develop/history.rs#L261), [`ui/dr-ui/src/develop/history.rs:277`](../../ui/dr-ui/src/develop/history.rs#L277), [`ui/dr-ui/src/develop/history.rs:299`](../../ui/dr-ui/src/develop/history.rs#L299), [`ui/dr-ui/src/develop/history.rs:29`](../../ui/dr-ui/src/develop/history.rs#L29), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/history.rs:68`](../../ui/dr-ui/src/develop/history.rs#L68), [`ui/dr-ui/src/develop/history.rs:82`](../../ui/dr-ui/src/develop/history.rs#L82), [`ui/dr-ui/src/develop/history.rs:93`](../../ui/dr-ui/src/develop/history.rs#L93), [`ui/dr-ui/src/develop/render.rs:1072`](../../ui/dr-ui/src/develop/render.rs#L1072), [`ui/dr-ui/src/develop/render.rs:1108`](../../ui/dr-ui/src/develop/render.rs#L1108), [`ui/dr-ui/src/develop/render.rs:852`](../../ui/dr-ui/src/develop/render.rs#L852), [`ui/dr-ui/src/develop/session.rs:80`](../../ui/dr-ui/src/develop/session.rs#L80), [`ui/dr-ui/src/develop/session.rs:89`](../../ui/dr-ui/src/develop/session.rs#L89), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop_ui.rs:772`](../../ui/dr-ui/src/develop_ui.rs#L772), [`ui/dr-ui/src/develop_ui.rs:792`](../../ui/dr-ui/src/develop_ui.rs#L792), [`ui/dr-ui/src/labels.rs:12`](../../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:292`](../../ui/dr-ui/src/labels.rs#L292), [`ui/dr-ui/src/labels.rs:31`](../../ui/dr-ui/src/labels.rs#L31), [`ui/dr-ui/src/lib.rs:2109`](../../ui/dr-ui/src/lib.rs#L2109), [`ui/dr-ui/src/lib.rs:2114`](../../ui/dr-ui/src/lib.rs#L2114), [`ui/dr-ui/src/lib.rs:2146`](../../ui/dr-ui/src/lib.rs#L2146), [`ui/dr-ui/src/lib.rs:2155`](../../ui/dr-ui/src/lib.rs#L2155), [`ui/dr-ui/src/lib.rs:2172`](../../ui/dr-ui/src/lib.rs#L2172), [`ui/dr-ui/src/library/sidecar.rs:351`](../../ui/dr-ui/src/library/sidecar.rs#L351), [`ui/dr-ui/src/library/sidecar.rs:61`](../../ui/dr-ui/src/library/sidecar.rs#L61), [`ui/dr-ui/src/presets.rs:2076`](../../ui/dr-ui/src/presets.rs#L2076), [`ui/dr-ui/src/presets.rs:373`](../../ui/dr-ui/src/presets.rs#L373), [`ui/dr-ui/src/presets.rs:437`](../../ui/dr-ui/src/presets.rs#L437), [`ui/dr-ui/src/presets.rs:557`](../../ui/dr-ui/src/presets.rs#L557), [`ui/dr-ui/ui/history.slint:192`](../../ui/dr-ui/ui/history.slint#L192), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:219`](../../ui/dr-ui/ui/history.slint#L219), [`ui/dr-ui/ui/history.slint:304`](../../ui/dr-ui/ui/history.slint#L304), [`ui/dr-ui/ui/history.slint:43`](../../ui/dr-ui/ui/history.slint#L43), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53) | | FR-DEV-6 | [`core/dr-pipeline/src/bundled.rs:1`](../../core/dr-pipeline/src/bundled.rs#L1), [`core/dr-pipeline/src/preset.rs:1293`](../../core/dr-pipeline/src/preset.rs#L1293), [`core/dr-pipeline/src/preset.rs:1303`](../../core/dr-pipeline/src/preset.rs#L1303), [`core/dr-pipeline/src/preset.rs:1312`](../../core/dr-pipeline/src/preset.rs#L1312), [`core/dr-pipeline/src/preset.rs:1328`](../../core/dr-pipeline/src/preset.rs#L1328), [`core/dr-pipeline/src/preset.rs:1340`](../../core/dr-pipeline/src/preset.rs#L1340), [`core/dr-pipeline/src/preset.rs:1356`](../../core/dr-pipeline/src/preset.rs#L1356), [`core/dr-pipeline/src/preset.rs:1382`](../../core/dr-pipeline/src/preset.rs#L1382), [`core/dr-pipeline/src/preset.rs:1404`](../../core/dr-pipeline/src/preset.rs#L1404), [`core/dr-pipeline/src/preset.rs:1418`](../../core/dr-pipeline/src/preset.rs#L1418), [`core/dr-pipeline/src/preset.rs:1436`](../../core/dr-pipeline/src/preset.rs#L1436), [`core/dr-pipeline/src/preset.rs:1529`](../../core/dr-pipeline/src/preset.rs#L1529), [`core/dr-pipeline/src/preset.rs:1544`](../../core/dr-pipeline/src/preset.rs#L1544), [`core/dr-pipeline/src/preset.rs:1`](../../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:501`](../../core/dr-pipeline/src/preset.rs#L501), [`core/dr-pipeline/src/preset.rs:534`](../../core/dr-pipeline/src/preset.rs#L534), [`core/dr-preset-xmp/src/lib.rs:1`](../../core/dr-preset-xmp/src/lib.rs#L1), [`core/dr-preset-xmp/src/lib.rs:492`](../../core/dr-preset-xmp/src/lib.rs#L492), [`core/dr-types/src/settings.rs:443`](../../core/dr-types/src/settings.rs#L443), [`ui/dr-ui/src/develop/session.rs:614`](../../ui/dr-ui/src/develop/session.rs#L614), [`ui/dr-ui/src/develop/session.rs:635`](../../ui/dr-ui/src/develop/session.rs#L635), [`ui/dr-ui/src/develop_ui.rs:167`](../../ui/dr-ui/src/develop_ui.rs#L167), [`ui/dr-ui/src/develop_ui.rs:196`](../../ui/dr-ui/src/develop_ui.rs#L196), [`ui/dr-ui/src/lib.rs:1276`](../../ui/dr-ui/src/lib.rs#L1276), [`ui/dr-ui/src/library/sidecar.rs:12`](../../ui/dr-ui/src/library/sidecar.rs#L12), [`ui/dr-ui/src/library/sidecar.rs:40`](../../ui/dr-ui/src/library/sidecar.rs#L40), [`ui/dr-ui/src/library/thumbnails_fetch.rs:414`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L414), [`ui/dr-ui/src/library_ui/controller.rs:699`](../../ui/dr-ui/src/library_ui/controller.rs#L699), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:495`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L495), [`ui/dr-ui/src/library_ui/window.rs:823`](../../ui/dr-ui/src/library_ui/window.rs#L823), [`ui/dr-ui/src/preset_store.rs:1`](../../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/presets.rs:1892`](../../ui/dr-ui/src/presets.rs#L1892), [`ui/dr-ui/src/presets.rs:1`](../../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/presets.rs:707`](../../ui/dr-ui/src/presets.rs#L707), [`ui/dr-ui/src/presets.rs:746`](../../ui/dr-ui/src/presets.rs#L746), [`ui/dr-ui/src/presets.rs:996`](../../ui/dr-ui/src/presets.rs#L996), [`ui/dr-ui/ui/adjust.slint:937`](../../ui/dr-ui/ui/adjust.slint#L937), [`ui/dr-ui/ui/adjust.slint:962`](../../ui/dr-ui/ui/adjust.slint#L962), [`ui/dr-ui/ui/app.slint:1094`](../../ui/dr-ui/ui/app.slint#L1094), [`ui/dr-ui/ui/app.slint:1518`](../../ui/dr-ui/ui/app.slint#L1518), [`ui/dr-ui/ui/app.slint:1802`](../../ui/dr-ui/ui/app.slint#L1802), [`ui/dr-ui/ui/app.slint:2550`](../../ui/dr-ui/ui/app.slint#L2550), [`ui/dr-ui/ui/app.slint:3483`](../../ui/dr-ui/ui/app.slint#L3483), [`ui/dr-ui/ui/app.slint:3529`](../../ui/dr-ui/ui/app.slint#L3529), [`ui/dr-ui/ui/app.slint:527`](../../ui/dr-ui/ui/app.slint#L527), [`ui/dr-ui/ui/app.slint:538`](../../ui/dr-ui/ui/app.slint#L538), [`ui/dr-ui/ui/app.slint:698`](../../ui/dr-ui/ui/app.slint#L698), [`ui/dr-ui/ui/develop.slint:257`](../../ui/dr-ui/ui/develop.slint#L257), [`ui/dr-ui/ui/icons.slint:390`](../../ui/dr-ui/ui/icons.slint#L390), [`ui/dr-ui/ui/library.slint:2026`](../../ui/dr-ui/ui/library.slint#L2026), [`ui/dr-ui/ui/library.slint:2032`](../../ui/dr-ui/ui/library.slint#L2032), [`ui/dr-ui/ui/library.slint:3229`](../../ui/dr-ui/ui/library.slint#L3229), [`ui/dr-ui/ui/library.slint:5167`](../../ui/dr-ui/ui/library.slint#L5167), [`ui/dr-ui/ui/library.slint:5185`](../../ui/dr-ui/ui/library.slint#L5185), [`ui/dr-ui/ui/presets.slint:114`](../../ui/dr-ui/ui/presets.slint#L114), [`ui/dr-ui/ui/presets.slint:155`](../../ui/dr-ui/ui/presets.slint#L155), [`ui/dr-ui/ui/presets.slint:203`](../../ui/dr-ui/ui/presets.slint#L203), [`ui/dr-ui/ui/presets.slint:211`](../../ui/dr-ui/ui/presets.slint#L211), [`ui/dr-ui/ui/presets.slint:21`](../../ui/dr-ui/ui/presets.slint#L21), [`ui/dr-ui/ui/presets.slint:33`](../../ui/dr-ui/ui/presets.slint#L33), [`ui/dr-ui/ui/presets.slint:394`](../../ui/dr-ui/ui/presets.slint#L394), [`ui/dr-ui/ui/presets.slint:432`](../../ui/dr-ui/ui/presets.slint#L432), [`ui/dr-ui/ui/presets.slint:467`](../../ui/dr-ui/ui/presets.slint#L467), [`ui/dr-ui/ui/presets.slint:62`](../../ui/dr-ui/ui/presets.slint#L62), [`ui/dr-ui/ui/presets.slint:7`](../../ui/dr-ui/ui/presets.slint#L7), [`ui/dr-ui/ui/settings.slint:126`](../../ui/dr-ui/ui/settings.slint#L126), [`ui/dr-ui/ui/settings.slint:690`](../../ui/dr-ui/ui/settings.slint#L690), [`ui/dr-ui/ui/toolrail.slint:123`](../../ui/dr-ui/ui/toolrail.slint#L123), [`ui/dr-ui/ui/toolrail.slint:453`](../../ui/dr-ui/ui/toolrail.slint#L453) | | FR-DEV-7 | [`core/dr-pipeline/src/history.rs:214`](../../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:499`](../../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../../core/dr-pipeline/src/history.rs#L526), [`ui/dr-ui/src/develop/history.rs:107`](../../ui/dr-ui/src/develop/history.rs#L107), [`ui/dr-ui/src/develop/history.rs:124`](../../ui/dr-ui/src/develop/history.rs#L124), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/render.rs:1108`](../../ui/dr-ui/src/develop/render.rs#L1108), [`ui/dr-ui/src/develop/render.rs:583`](../../ui/dr-ui/src/develop/render.rs#L583), [`ui/dr-ui/src/develop/render.rs:624`](../../ui/dr-ui/src/develop/render.rs#L624), [`ui/dr-ui/src/develop/session.rs:105`](../../ui/dr-ui/src/develop/session.rs#L105), [`ui/dr-ui/src/develop_ui.rs:713`](../../ui/dr-ui/src/develop_ui.rs#L713), [`ui/dr-ui/src/develop_ui.rs:772`](../../ui/dr-ui/src/develop_ui.rs#L772), [`ui/dr-ui/src/develop_ui.rs:844`](../../ui/dr-ui/src/develop_ui.rs#L844), [`ui/dr-ui/src/lib.rs:2155`](../../ui/dr-ui/src/lib.rs#L2155), [`ui/dr-ui/src/lib.rs:2241`](../../ui/dr-ui/src/lib.rs#L2241), [`ui/dr-ui/src/lib.rs:2255`](../../ui/dr-ui/src/lib.rs#L2255), [`ui/dr-ui/src/lib.rs:450`](../../ui/dr-ui/src/lib.rs#L450), [`ui/dr-ui/ui/app.slint:224`](../../ui/dr-ui/ui/app.slint#L224), [`ui/dr-ui/ui/app.slint:2417`](../../ui/dr-ui/ui/app.slint#L2417), [`ui/dr-ui/ui/app.slint:2463`](../../ui/dr-ui/ui/app.slint#L2463), [`ui/dr-ui/ui/app.slint:3027`](../../ui/dr-ui/ui/app.slint#L3027), [`ui/dr-ui/ui/history.slint:103`](../../ui/dr-ui/ui/history.slint#L103), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:227`](../../ui/dr-ui/ui/history.slint#L227), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53), [`ui/dr-ui/ui/widgets.slint:72`](../../ui/dr-ui/ui/widgets.slint#L72) | -| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:397`](../../core/dr-gpu/src/detail.rs#L397), [`core/dr-gpu/src/detail.rs:609`](../../core/dr-gpu/src/detail.rs#L609), [`core/dr-gpu/tests/detail_instances.rs:1`](../../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:449`](../../core/dr-pipeline/src/detail.rs#L449), [`core/dr-pipeline/src/detail.rs:491`](../../core/dr-pipeline/src/detail.rs#L491), [`core/dr-pipeline/src/detail.rs:526`](../../core/dr-pipeline/src/detail.rs#L526), [`core/dr-pipeline/src/detail.rs:620`](../../core/dr-pipeline/src/detail.rs#L620), [`core/dr-pipeline/src/graph.rs:1145`](../../core/dr-pipeline/src/graph.rs#L1145), [`core/dr-pipeline/src/graph.rs:122`](../../core/dr-pipeline/src/graph.rs#L122), [`core/dr-pipeline/src/graph.rs:254`](../../core/dr-pipeline/src/graph.rs#L254), [`core/dr-pipeline/src/operation.rs:364`](../../core/dr-pipeline/src/operation.rs#L364), [`core/dr-pipeline/src/operation.rs:856`](../../core/dr-pipeline/src/operation.rs#L856), [`core/dr-pipeline/src/sidecar.rs:1104`](../../core/dr-pipeline/src/sidecar.rs#L1104), [`core/dr-pipeline/src/sidecar.rs:1158`](../../core/dr-pipeline/src/sidecar.rs#L1158), [`core/dr-pipeline/src/sidecar.rs:1188`](../../core/dr-pipeline/src/sidecar.rs#L1188), [`core/dr-pipeline/src/sidecar.rs:233`](../../core/dr-pipeline/src/sidecar.rs#L233), [`core/dr-pipeline/src/sidecar.rs:410`](../../core/dr-pipeline/src/sidecar.rs#L410), [`core/dr-pipeline/src/sidecar.rs:910`](../../core/dr-pipeline/src/sidecar.rs#L910), [`core/dr-pipeline/src/spot.rs:115`](../../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop/repairs.rs:114`](../../ui/dr-ui/src/develop/repairs.rs#L114), [`ui/dr-ui/src/develop/repairs.rs:11`](../../ui/dr-ui/src/develop/repairs.rs#L11), [`ui/dr-ui/src/develop/repairs.rs:197`](../../ui/dr-ui/src/develop/repairs.rs#L197), [`ui/dr-ui/src/develop/repairs.rs:211`](../../ui/dr-ui/src/develop/repairs.rs#L211), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/develop/session.rs:229`](../../ui/dr-ui/src/develop/session.rs#L229), [`ui/dr-ui/src/develop_ui.rs:1001`](../../ui/dr-ui/src/develop_ui.rs#L1001), [`ui/dr-ui/src/labels.rs:80`](../../ui/dr-ui/src/labels.rs#L80), [`ui/dr-ui/src/lib.rs:2199`](../../ui/dr-ui/src/lib.rs#L2199), [`ui/dr-ui/src/lib.rs:493`](../../ui/dr-ui/src/lib.rs#L493), [`ui/dr-ui/src/spots_ui.rs:19`](../../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/app.slint:2270`](../../ui/dr-ui/ui/app.slint#L2270), [`ui/dr-ui/ui/app.slint:2513`](../../ui/dr-ui/ui/app.slint#L2513), [`ui/dr-ui/ui/app.slint:3376`](../../ui/dr-ui/ui/app.slint#L3376), [`ui/dr-ui/ui/icons.slint:378`](../../ui/dr-ui/ui/icons.slint#L378), [`ui/dr-ui/ui/session.slint:102`](../../ui/dr-ui/ui/session.slint#L102), [`ui/dr-ui/ui/session.slint:52`](../../ui/dr-ui/ui/session.slint#L52), [`ui/dr-ui/ui/spots.slint:191`](../../ui/dr-ui/ui/spots.slint#L191), [`ui/dr-ui/ui/spots.slint:49`](../../ui/dr-ui/ui/spots.slint#L49), [`ui/dr-ui/ui/spots.slint:6`](../../ui/dr-ui/ui/spots.slint#L6), [`ui/dr-ui/ui/spots.slint:91`](../../ui/dr-ui/ui/spots.slint#L91) | -| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:1050`](../../core/dr-gpu/src/adjust.rs#L1050), [`core/dr-gpu/src/adjust.rs:2809`](../../core/dr-gpu/src/adjust.rs#L2809), [`core/dr-gpu/src/adjust.rs:2886`](../../core/dr-gpu/src/adjust.rs#L2886), [`core/dr-gpu/src/adjust.rs:2971`](../../core/dr-gpu/src/adjust.rs#L2971), [`core/dr-gpu/src/adjust.rs:44`](../../core/dr-gpu/src/adjust.rs#L44), [`core/dr-gpu/src/lib.rs:174`](../../core/dr-gpu/src/lib.rs#L174), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-gpu/src/lib.rs:72`](../../core/dr-gpu/src/lib.rs#L72), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`core/dr-gpu/tests/capture_sharpen.rs:199`](../../core/dr-gpu/tests/capture_sharpen.rs#L199), [`core/dr-gpu/tests/detail_stage.rs:327`](../../core/dr-gpu/tests/detail_stage.rs#L327), [`core/dr-gpu/tests/local_contrast.rs:263`](../../core/dr-gpu/tests/local_contrast.rs#L263), [`core/dr-gpu/tests/noise_reduction.rs:377`](../../core/dr-gpu/tests/noise_reduction.rs#L377), [`core/dr-pipeline/src/detail.rs:142`](../../core/dr-pipeline/src/detail.rs#L142), [`core/dr-pipeline/src/detail.rs:231`](../../core/dr-pipeline/src/detail.rs#L231), [`core/dr-pipeline/src/detail.rs:592`](../../core/dr-pipeline/src/detail.rs#L592), [`core/dr-pipeline/src/detail.rs:980`](../../core/dr-pipeline/src/detail.rs#L980), [`core/dr-pipeline/src/graph.rs:1016`](../../core/dr-pipeline/src/graph.rs#L1016), [`core/dr-pipeline/src/graph.rs:986`](../../core/dr-pipeline/src/graph.rs#L986), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:628`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L628), [`core/dr-pipeline/src/ops/dehaze.rs:1`](../../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:564`](../../core/dr-pipeline/src/ops/dehaze.rs#L564), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:970`](../../core/dr-pipeline/src/ops/local_contrast.rs#L970), [`core/dr-pipeline/src/ops/noise_reduction.rs:694`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L694), [`core/dr-pipeline/src/spot.rs:673`](../../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop/framing.rs:640`](../../ui/dr-ui/src/develop/framing.rs#L640), [`ui/dr-ui/src/develop/mod.rs:55`](../../ui/dr-ui/src/develop/mod.rs#L55), [`ui/dr-ui/src/develop/render.rs:1165`](../../ui/dr-ui/src/develop/render.rs#L1165), [`ui/dr-ui/src/develop/render.rs:1199`](../../ui/dr-ui/src/develop/render.rs#L1199), [`ui/dr-ui/src/develop/render.rs:1337`](../../ui/dr-ui/src/develop/render.rs#L1337), [`ui/dr-ui/src/develop/render.rs:312`](../../ui/dr-ui/src/develop/render.rs#L312), [`ui/dr-ui/src/develop/render.rs:97`](../../ui/dr-ui/src/develop/render.rs#L97), [`ui/dr-ui/src/lib.rs:1092`](../../ui/dr-ui/src/lib.rs#L1092), [`ui/dr-ui/src/lib.rs:118`](../../ui/dr-ui/src/lib.rs#L118) | -| FR-DSP-2 | [`core/dr-gpu/src/adjust.rs:1353`](../../core/dr-gpu/src/adjust.rs#L1353), [`core/dr-gpu/src/demosaic.rs:117`](../../core/dr-gpu/src/demosaic.rs#L117), [`core/dr-gpu/src/demosaic.rs:164`](../../core/dr-gpu/src/demosaic.rs#L164), [`core/dr-gpu/src/demosaic.rs:350`](../../core/dr-gpu/src/demosaic.rs#L350), [`core/dr-gpu/tests/source_window.rs:1`](../../core/dr-gpu/tests/source_window.rs#L1), [`core/dr-pipeline/src/detail.rs:231`](../../core/dr-pipeline/src/detail.rs#L231), [`core/dr-pipeline/src/detail.rs:571`](../../core/dr-pipeline/src/detail.rs#L571), [`core/dr-pipeline/src/detail.rs:980`](../../core/dr-pipeline/src/detail.rs#L980), [`core/dr-pipeline/src/graph.rs:302`](../../core/dr-pipeline/src/graph.rs#L302), [`core/dr-pipeline/src/graph.rs:86`](../../core/dr-pipeline/src/graph.rs#L86), [`core/dr-pipeline/src/operation.rs:1776`](../../core/dr-pipeline/src/operation.rs#L1776), [`core/dr-pipeline/src/operation.rs:2504`](../../core/dr-pipeline/src/operation.rs#L2504), [`core/dr-pipeline/src/operation.rs:602`](../../core/dr-pipeline/src/operation.rs#L602), [`core/dr-pipeline/src/tiles.rs:1`](../../core/dr-pipeline/src/tiles.rs#L1), [`ui/dr-ui/src/develop/render.rs:1885`](../../ui/dr-ui/src/develop/render.rs#L1885), [`ui/dr-ui/src/develop/render.rs:1964`](../../ui/dr-ui/src/develop/render.rs#L1964), [`ui/dr-ui/src/develop/render.rs:216`](../../ui/dr-ui/src/develop/render.rs#L216), [`ui/dr-ui/src/develop/render.rs:23`](../../ui/dr-ui/src/develop/render.rs#L23), [`ui/dr-ui/src/develop/render.rs:763`](../../ui/dr-ui/src/develop/render.rs#L763), [`ui/dr-ui/src/develop/session.rs:115`](../../ui/dr-ui/src/develop/session.rs#L115), [`ui/dr-ui/src/develop/session.rs:328`](../../ui/dr-ui/src/develop/session.rs#L328), [`ui/dr-ui/src/develop/session.rs:355`](../../ui/dr-ui/src/develop/session.rs#L355) | +| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:397`](../../core/dr-gpu/src/detail.rs#L397), [`core/dr-gpu/src/detail.rs:609`](../../core/dr-gpu/src/detail.rs#L609), [`core/dr-gpu/tests/detail_instances.rs:1`](../../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:449`](../../core/dr-pipeline/src/detail.rs#L449), [`core/dr-pipeline/src/detail.rs:491`](../../core/dr-pipeline/src/detail.rs#L491), [`core/dr-pipeline/src/detail.rs:526`](../../core/dr-pipeline/src/detail.rs#L526), [`core/dr-pipeline/src/detail.rs:620`](../../core/dr-pipeline/src/detail.rs#L620), [`core/dr-pipeline/src/graph.rs:1145`](../../core/dr-pipeline/src/graph.rs#L1145), [`core/dr-pipeline/src/graph.rs:122`](../../core/dr-pipeline/src/graph.rs#L122), [`core/dr-pipeline/src/graph.rs:254`](../../core/dr-pipeline/src/graph.rs#L254), [`core/dr-pipeline/src/operation.rs:377`](../../core/dr-pipeline/src/operation.rs#L377), [`core/dr-pipeline/src/operation.rs:869`](../../core/dr-pipeline/src/operation.rs#L869), [`core/dr-pipeline/src/sidecar.rs:1104`](../../core/dr-pipeline/src/sidecar.rs#L1104), [`core/dr-pipeline/src/sidecar.rs:1158`](../../core/dr-pipeline/src/sidecar.rs#L1158), [`core/dr-pipeline/src/sidecar.rs:1188`](../../core/dr-pipeline/src/sidecar.rs#L1188), [`core/dr-pipeline/src/sidecar.rs:233`](../../core/dr-pipeline/src/sidecar.rs#L233), [`core/dr-pipeline/src/sidecar.rs:410`](../../core/dr-pipeline/src/sidecar.rs#L410), [`core/dr-pipeline/src/sidecar.rs:910`](../../core/dr-pipeline/src/sidecar.rs#L910), [`core/dr-pipeline/src/spot.rs:115`](../../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop/repairs.rs:114`](../../ui/dr-ui/src/develop/repairs.rs#L114), [`ui/dr-ui/src/develop/repairs.rs:11`](../../ui/dr-ui/src/develop/repairs.rs#L11), [`ui/dr-ui/src/develop/repairs.rs:197`](../../ui/dr-ui/src/develop/repairs.rs#L197), [`ui/dr-ui/src/develop/repairs.rs:211`](../../ui/dr-ui/src/develop/repairs.rs#L211), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/develop/session.rs:229`](../../ui/dr-ui/src/develop/session.rs#L229), [`ui/dr-ui/src/develop_ui.rs:1001`](../../ui/dr-ui/src/develop_ui.rs#L1001), [`ui/dr-ui/src/labels.rs:80`](../../ui/dr-ui/src/labels.rs#L80), [`ui/dr-ui/src/lib.rs:2199`](../../ui/dr-ui/src/lib.rs#L2199), [`ui/dr-ui/src/lib.rs:493`](../../ui/dr-ui/src/lib.rs#L493), [`ui/dr-ui/src/spots_ui.rs:19`](../../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/app.slint:2270`](../../ui/dr-ui/ui/app.slint#L2270), [`ui/dr-ui/ui/app.slint:2513`](../../ui/dr-ui/ui/app.slint#L2513), [`ui/dr-ui/ui/app.slint:3376`](../../ui/dr-ui/ui/app.slint#L3376), [`ui/dr-ui/ui/icons.slint:378`](../../ui/dr-ui/ui/icons.slint#L378), [`ui/dr-ui/ui/session.slint:102`](../../ui/dr-ui/ui/session.slint#L102), [`ui/dr-ui/ui/session.slint:52`](../../ui/dr-ui/ui/session.slint#L52), [`ui/dr-ui/ui/spots.slint:191`](../../ui/dr-ui/ui/spots.slint#L191), [`ui/dr-ui/ui/spots.slint:49`](../../ui/dr-ui/ui/spots.slint#L49), [`ui/dr-ui/ui/spots.slint:6`](../../ui/dr-ui/ui/spots.slint#L6), [`ui/dr-ui/ui/spots.slint:91`](../../ui/dr-ui/ui/spots.slint#L91) | +| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/adjust.rs:2879`](../../core/dr-gpu/src/adjust.rs#L2879), [`core/dr-gpu/src/adjust.rs:2956`](../../core/dr-gpu/src/adjust.rs#L2956), [`core/dr-gpu/src/adjust.rs:3041`](../../core/dr-gpu/src/adjust.rs#L3041), [`core/dr-gpu/src/adjust.rs:44`](../../core/dr-gpu/src/adjust.rs#L44), [`core/dr-gpu/src/lib.rs:174`](../../core/dr-gpu/src/lib.rs#L174), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-gpu/src/lib.rs:72`](../../core/dr-gpu/src/lib.rs#L72), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`core/dr-gpu/tests/capture_sharpen.rs:199`](../../core/dr-gpu/tests/capture_sharpen.rs#L199), [`core/dr-gpu/tests/detail_stage.rs:327`](../../core/dr-gpu/tests/detail_stage.rs#L327), [`core/dr-gpu/tests/local_contrast.rs:263`](../../core/dr-gpu/tests/local_contrast.rs#L263), [`core/dr-gpu/tests/noise_reduction.rs:377`](../../core/dr-gpu/tests/noise_reduction.rs#L377), [`core/dr-pipeline/src/detail.rs:142`](../../core/dr-pipeline/src/detail.rs#L142), [`core/dr-pipeline/src/detail.rs:231`](../../core/dr-pipeline/src/detail.rs#L231), [`core/dr-pipeline/src/detail.rs:592`](../../core/dr-pipeline/src/detail.rs#L592), [`core/dr-pipeline/src/detail.rs:980`](../../core/dr-pipeline/src/detail.rs#L980), [`core/dr-pipeline/src/graph.rs:1016`](../../core/dr-pipeline/src/graph.rs#L1016), [`core/dr-pipeline/src/graph.rs:986`](../../core/dr-pipeline/src/graph.rs#L986), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:628`](../../core/dr-pipeline/src/ops/capture_sharpen.rs#L628), [`core/dr-pipeline/src/ops/dehaze.rs:1`](../../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:564`](../../core/dr-pipeline/src/ops/dehaze.rs#L564), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:970`](../../core/dr-pipeline/src/ops/local_contrast.rs#L970), [`core/dr-pipeline/src/ops/noise_reduction.rs:694`](../../core/dr-pipeline/src/ops/noise_reduction.rs#L694), [`core/dr-pipeline/src/spot.rs:673`](../../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop/framing.rs:640`](../../ui/dr-ui/src/develop/framing.rs#L640), [`ui/dr-ui/src/develop/mod.rs:55`](../../ui/dr-ui/src/develop/mod.rs#L55), [`ui/dr-ui/src/develop/render.rs:1165`](../../ui/dr-ui/src/develop/render.rs#L1165), [`ui/dr-ui/src/develop/render.rs:1199`](../../ui/dr-ui/src/develop/render.rs#L1199), [`ui/dr-ui/src/develop/render.rs:1337`](../../ui/dr-ui/src/develop/render.rs#L1337), [`ui/dr-ui/src/develop/render.rs:312`](../../ui/dr-ui/src/develop/render.rs#L312), [`ui/dr-ui/src/develop/render.rs:97`](../../ui/dr-ui/src/develop/render.rs#L97), [`ui/dr-ui/src/lib.rs:1092`](../../ui/dr-ui/src/lib.rs#L1092), [`ui/dr-ui/src/lib.rs:118`](../../ui/dr-ui/src/lib.rs#L118) | +| FR-DSP-2 | [`core/dr-gpu/src/adjust.rs:1419`](../../core/dr-gpu/src/adjust.rs#L1419), [`core/dr-gpu/src/demosaic.rs:122`](../../core/dr-gpu/src/demosaic.rs#L122), [`core/dr-gpu/src/demosaic.rs:169`](../../core/dr-gpu/src/demosaic.rs#L169), [`core/dr-gpu/src/demosaic.rs:362`](../../core/dr-gpu/src/demosaic.rs#L362), [`core/dr-gpu/tests/source_window.rs:1`](../../core/dr-gpu/tests/source_window.rs#L1), [`core/dr-pipeline/src/detail.rs:231`](../../core/dr-pipeline/src/detail.rs#L231), [`core/dr-pipeline/src/detail.rs:571`](../../core/dr-pipeline/src/detail.rs#L571), [`core/dr-pipeline/src/detail.rs:980`](../../core/dr-pipeline/src/detail.rs#L980), [`core/dr-pipeline/src/graph.rs:302`](../../core/dr-pipeline/src/graph.rs#L302), [`core/dr-pipeline/src/graph.rs:86`](../../core/dr-pipeline/src/graph.rs#L86), [`core/dr-pipeline/src/operation.rs:1794`](../../core/dr-pipeline/src/operation.rs#L1794), [`core/dr-pipeline/src/operation.rs:2522`](../../core/dr-pipeline/src/operation.rs#L2522), [`core/dr-pipeline/src/operation.rs:615`](../../core/dr-pipeline/src/operation.rs#L615), [`core/dr-pipeline/src/tiles.rs:1`](../../core/dr-pipeline/src/tiles.rs#L1), [`ui/dr-ui/src/develop/render.rs:1885`](../../ui/dr-ui/src/develop/render.rs#L1885), [`ui/dr-ui/src/develop/render.rs:1964`](../../ui/dr-ui/src/develop/render.rs#L1964), [`ui/dr-ui/src/develop/render.rs:216`](../../ui/dr-ui/src/develop/render.rs#L216), [`ui/dr-ui/src/develop/render.rs:23`](../../ui/dr-ui/src/develop/render.rs#L23), [`ui/dr-ui/src/develop/render.rs:763`](../../ui/dr-ui/src/develop/render.rs#L763), [`ui/dr-ui/src/develop/session.rs:115`](../../ui/dr-ui/src/develop/session.rs#L115), [`ui/dr-ui/src/develop/session.rs:328`](../../ui/dr-ui/src/develop/session.rs#L328), [`ui/dr-ui/src/develop/session.rs:355`](../../ui/dr-ui/src/develop/session.rs#L355) | | FR-DSP-3 | [`core/dr-gpu/tests/frame_budget.rs:101`](../../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/local_contrast.rs:328`](../../core/dr-gpu/tests/local_contrast.rs#L328), [`core/dr-pipeline/src/ops/local_contrast.rs:447`](../../core/dr-pipeline/src/ops/local_contrast.rs#L447) | | FR-DSP-4 | [`ui/dr-ui/src/lib.rs:2264`](../../ui/dr-ui/src/lib.rs#L2264), [`ui/dr-ui/src/lib.rs:2450`](../../ui/dr-ui/src/lib.rs#L2450), [`ui/dr-ui/src/refine.rs:1`](../../ui/dr-ui/src/refine.rs#L1), [`ui/dr-ui/ui/app.slint:112`](../../ui/dr-ui/ui/app.slint#L112), [`ui/dr-ui/ui/app.slint:1863`](../../ui/dr-ui/ui/app.slint#L1863), [`ui/dr-ui/ui/histogram.slint:182`](../../ui/dr-ui/ui/histogram.slint#L182), [`ui/dr-ui/ui/histogram.slint:250`](../../ui/dr-ui/ui/histogram.slint#L250) | | FR-DSP-5 | [`core/dr-gpu/tests/frame_budget.rs:101`](../../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/zoom_resolution.rs:135`](../../core/dr-gpu/tests/zoom_resolution.rs#L135), [`core/dr-gpu/tests/zoom_resolution.rs:166`](../../core/dr-gpu/tests/zoom_resolution.rs#L166), [`core/dr-gpu/tests/zoom_resolution.rs:1`](../../core/dr-gpu/tests/zoom_resolution.rs#L1), [`core/dr-gpu/tests/zoom_resolution.rs:216`](../../core/dr-gpu/tests/zoom_resolution.rs#L216) | -| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:663`](../../core/dr-pipeline/src/operation.rs#L663), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop/render.rs:1744`](../../ui/dr-ui/src/develop/render.rs#L1744), [`ui/dr-ui/src/develop/render.rs:347`](../../ui/dr-ui/src/develop/render.rs#L347), [`ui/dr-ui/src/lib.rs:2131`](../../ui/dr-ui/src/lib.rs#L2131), [`ui/dr-ui/src/lib.rs:3002`](../../ui/dr-ui/src/lib.rs#L3002) | +| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:676`](../../core/dr-pipeline/src/operation.rs#L676), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop/render.rs:1744`](../../ui/dr-ui/src/develop/render.rs#L1744), [`ui/dr-ui/src/develop/render.rs:347`](../../ui/dr-ui/src/develop/render.rs#L347), [`ui/dr-ui/src/lib.rs:2131`](../../ui/dr-ui/src/lib.rs#L2131), [`ui/dr-ui/src/lib.rs:3002`](../../ui/dr-ui/src/lib.rs#L3002) | | FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop/render.rs:1534`](../../ui/dr-ui/src/develop/render.rs#L1534), [`ui/dr-ui/src/develop/render.rs:1566`](../../ui/dr-ui/src/develop/render.rs#L1566), [`ui/dr-ui/src/develop/render.rs:375`](../../ui/dr-ui/src/develop/render.rs#L375), [`ui/dr-ui/src/develop/session.rs:129`](../../ui/dr-ui/src/develop/session.rs#L129), [`ui/dr-ui/src/histogram.rs:1`](../../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:2303`](../../ui/dr-ui/src/lib.rs#L2303), [`ui/dr-ui/src/lib.rs:470`](../../ui/dr-ui/src/lib.rs#L470), [`ui/dr-ui/ui/histogram.slint:191`](../../ui/dr-ui/ui/histogram.slint#L191), [`ui/dr-ui/ui/histogram.slint:1`](../../ui/dr-ui/ui/histogram.slint#L1) | | FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop/render.rs:1298`](../../ui/dr-ui/src/develop/render.rs#L1298), [`ui/dr-ui/src/develop/render.rs:1744`](../../ui/dr-ui/src/develop/render.rs#L1744), [`ui/dr-ui/src/develop/render.rs:1790`](../../ui/dr-ui/src/develop/render.rs#L1790), [`ui/dr-ui/src/develop/render.rs:1809`](../../ui/dr-ui/src/develop/render.rs#L1809), [`ui/dr-ui/src/develop/render.rs:288`](../../ui/dr-ui/src/develop/render.rs#L288), [`ui/dr-ui/src/develop/render.rs:347`](../../ui/dr-ui/src/develop/render.rs#L347), [`ui/dr-ui/src/develop/render.rs:65`](../../ui/dr-ui/src/develop/render.rs#L65), [`ui/dr-ui/src/develop/session.rs:282`](../../ui/dr-ui/src/develop/session.rs#L282), [`ui/dr-ui/src/display_ui.rs:192`](../../ui/dr-ui/src/display_ui.rs#L192), [`ui/dr-ui/src/display_ui.rs:1`](../../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:325`](../../ui/dr-ui/src/display_ui.rs#L325), [`ui/dr-ui/src/display_ui.rs:346`](../../ui/dr-ui/src/display_ui.rs#L346), [`ui/dr-ui/src/display_ui.rs:379`](../../ui/dr-ui/src/display_ui.rs#L379), [`ui/dr-ui/src/lib.rs:1298`](../../ui/dr-ui/src/lib.rs#L1298), [`ui/dr-ui/src/lib.rs:2131`](../../ui/dr-ui/src/lib.rs#L2131), [`ui/dr-ui/src/lib.rs:2979`](../../ui/dr-ui/src/lib.rs#L2979), [`ui/dr-ui/src/lib.rs:3002`](../../ui/dr-ui/src/lib.rs#L3002), [`ui/dr-ui/ui/app.slint:130`](../../ui/dr-ui/ui/app.slint#L130), [`ui/dr-ui/ui/app.slint:1849`](../../ui/dr-ui/ui/app.slint#L1849), [`ui/dr-ui/ui/settings.slint:176`](../../ui/dr-ui/ui/settings.slint#L176), [`ui/dr-ui/ui/settings.slint:864`](../../ui/dr-ui/ui/settings.slint#L864) | | FR-EXP-1 | [`core/dr-export/src/encode.rs:1`](../../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-10 | [`core/dr-catalog/src/albums.rs:1`](../../core/dr-catalog/src/albums.rs#L1), [`core/dr-types/src/settings.rs:731`](../../core/dr-types/src/settings.rs#L731), [`ui/dr-ui/src/albums_ui.rs:1`](../../ui/dr-ui/src/albums_ui.rs#L1), [`ui/dr-ui/src/collections_ui/controller.rs:129`](../../ui/dr-ui/src/collections_ui/controller.rs#L129), [`ui/dr-ui/src/collections_ui/controller.rs:432`](../../ui/dr-ui/src/collections_ui/controller.rs#L432), [`ui/dr-ui/src/develop_ui.rs:273`](../../ui/dr-ui/src/develop_ui.rs#L273), [`ui/dr-ui/src/export.rs:100`](../../ui/dr-ui/src/export.rs#L100), [`ui/dr-ui/src/export.rs:240`](../../ui/dr-ui/src/export.rs#L240), [`ui/dr-ui/src/export.rs:679`](../../ui/dr-ui/src/export.rs#L679), [`ui/dr-ui/src/export.rs:949`](../../ui/dr-ui/src/export.rs#L949), [`ui/dr-ui/src/lib.rs:1641`](../../ui/dr-ui/src/lib.rs#L1641), [`ui/dr-ui/src/library_ui/controller.rs:224`](../../ui/dr-ui/src/library_ui/controller.rs#L224), [`ui/dr-ui/src/library_ui/controller.rs:956`](../../ui/dr-ui/src/library_ui/controller.rs#L956), [`ui/dr-ui/src/library_ui/controller.rs:996`](../../ui/dr-ui/src/library_ui/controller.rs#L996), [`ui/dr-ui/src/library_ui/window.rs:388`](../../ui/dr-ui/src/library_ui/window.rs#L388), [`ui/dr-ui/src/saf.rs:1`](../../ui/dr-ui/src/saf.rs#L1), [`ui/dr-ui/ui/albums.slint:1`](../../ui/dr-ui/ui/albums.slint#L1), [`ui/dr-ui/ui/app.slint:3610`](../../ui/dr-ui/ui/app.slint#L3610), [`ui/dr-ui/ui/collections.slint:789`](../../ui/dr-ui/ui/collections.slint#L789), [`ui/dr-ui/ui/export.slint:204`](../../ui/dr-ui/ui/export.slint#L204) | -| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:157`](../../core/dr-export/src/lib.rs#L157), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:57`](../../core/dr-export/src/lib.rs#L57), [`core/dr-gpu/src/adjust.rs:3244`](../../core/dr-gpu/src/adjust.rs#L3244), [`core/dr-pipeline/src/graph.rs:899`](../../core/dr-pipeline/src/graph.rs#L899), [`core/dr-pipeline/src/operation.rs:663`](../../core/dr-pipeline/src/operation.rs#L663), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:976`](../../core/dr-types/src/settings.rs#L976), [`ui/dr-ui/src/develop/render.rs:1809`](../../ui/dr-ui/src/develop/render.rs#L1809), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | +| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:157`](../../core/dr-export/src/lib.rs#L157), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:57`](../../core/dr-export/src/lib.rs#L57), [`core/dr-gpu/src/adjust.rs:3314`](../../core/dr-gpu/src/adjust.rs#L3314), [`core/dr-pipeline/src/graph.rs:899`](../../core/dr-pipeline/src/graph.rs#L899), [`core/dr-pipeline/src/operation.rs:676`](../../core/dr-pipeline/src/operation.rs#L676), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:976`](../../core/dr-types/src/settings.rs#L976), [`ui/dr-ui/src/develop/render.rs:1809`](../../ui/dr-ui/src/develop/render.rs#L1809), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-3 | [`core/dr-export/src/lib.rs:186`](../../core/dr-export/src/lib.rs#L186), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:136`](../../core/dr-export/src/size.rs#L136), [`core/dr-export/src/size.rs:1`](../../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../../core/dr-export/src/size.rs#L25), [`core/dr-export/src/size.rs:84`](../../core/dr-export/src/size.rs#L84), [`core/dr-types/src/settings.rs:1021`](../../core/dr-types/src/settings.rs#L1021), [`core/dr-types/src/settings.rs:1029`](../../core/dr-types/src/settings.rs#L1029), [`core/dr-types/src/settings.rs:1045`](../../core/dr-types/src/settings.rs#L1045), [`core/dr-types/src/settings.rs:1114`](../../core/dr-types/src/settings.rs#L1114), [`core/dr-types/src/settings.rs:1142`](../../core/dr-types/src/settings.rs#L1142), [`core/dr-types/src/settings.rs:1153`](../../core/dr-types/src/settings.rs#L1153), [`core/dr-types/src/settings.rs:1159`](../../core/dr-types/src/settings.rs#L1159), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:256`](../../ui/dr-ui/src/settings_ui.rs#L256), [`ui/dr-ui/src/settings_ui.rs:269`](../../ui/dr-ui/src/settings_ui.rs#L269), [`ui/dr-ui/src/settings_ui.rs:288`](../../ui/dr-ui/src/settings_ui.rs#L288), [`ui/dr-ui/src/settings_ui.rs:701`](../../ui/dr-ui/src/settings_ui.rs#L701), [`ui/dr-ui/ui/export.slint:138`](../../ui/dr-ui/ui/export.slint#L138), [`ui/dr-ui/ui/export.slint:148`](../../ui/dr-ui/ui/export.slint#L148) | | FR-EXP-4 | [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/sharpen.rs:1`](../../core/dr-export/src/sharpen.rs#L1), [`core/dr-export/src/size.rs:1`](../../core/dr-export/src/size.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-5 | [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1) | | FR-EXP-6 | [`core/dr-catalog/src/albums.rs:1`](../../core/dr-catalog/src/albums.rs#L1), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/name.rs:1`](../../core/dr-export/src/name.rs#L1), [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/albums_ui.rs:1`](../../ui/dr-ui/src/albums_ui.rs#L1), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/export.rs:621`](../../ui/dr-ui/src/export.rs#L621), [`ui/dr-ui/src/export.rs:959`](../../ui/dr-ui/src/export.rs#L959), [`ui/dr-ui/src/lib.rs:654`](../../ui/dr-ui/src/lib.rs#L654), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/ui/albums.slint:1`](../../ui/dr-ui/ui/albums.slint#L1) | | FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/develop_ui.rs:377`](../../ui/dr-ui/src/develop_ui.rs#L377), [`ui/dr-ui/src/export.rs:1513`](../../ui/dr-ui/src/export.rs#L1513), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:295`](../../ui/dr-ui/src/lib.rs#L295), [`ui/dr-ui/src/lib.rs:654`](../../ui/dr-ui/src/lib.rs#L654), [`ui/dr-ui/src/lib.rs:700`](../../ui/dr-ui/src/lib.rs#L700), [`ui/dr-ui/src/lib.rs:730`](../../ui/dr-ui/src/lib.rs#L730), [`ui/dr-ui/src/library_ui/controller.rs:1121`](../../ui/dr-ui/src/library_ui/controller.rs#L1121), [`ui/dr-ui/src/library_ui/controller.rs:1133`](../../ui/dr-ui/src/library_ui/controller.rs#L1133), [`ui/dr-ui/src/library_ui/controller.rs:1145`](../../ui/dr-ui/src/library_ui/controller.rs#L1145), [`ui/dr-ui/src/library_ui/controller.rs:790`](../../ui/dr-ui/src/library_ui/controller.rs#L790), [`ui/dr-ui/src/library_ui/controller.rs:890`](../../ui/dr-ui/src/library_ui/controller.rs#L890), [`ui/dr-ui/src/library_ui/controller.rs:947`](../../ui/dr-ui/src/library_ui/controller.rs#L947), [`ui/dr-ui/src/library_ui/sync.rs:101`](../../ui/dr-ui/src/library_ui/sync.rs#L101), [`ui/dr-ui/src/settings_ui.rs:394`](../../ui/dr-ui/src/settings_ui.rs#L394), [`ui/dr-ui/ui/app.slint:1094`](../../ui/dr-ui/ui/app.slint#L1094), [`ui/dr-ui/ui/app.slint:1528`](../../ui/dr-ui/ui/app.slint#L1528), [`ui/dr-ui/ui/app.slint:2606`](../../ui/dr-ui/ui/app.slint#L2606), [`ui/dr-ui/ui/app.slint:3510`](../../ui/dr-ui/ui/app.slint#L3510), [`ui/dr-ui/ui/app.slint:691`](../../ui/dr-ui/ui/app.slint#L691), [`ui/dr-ui/ui/app.slint:708`](../../ui/dr-ui/ui/app.slint#L708), [`ui/dr-ui/ui/app.slint:944`](../../ui/dr-ui/ui/app.slint#L944), [`ui/dr-ui/ui/export.slint:1`](../../ui/dr-ui/ui/export.slint#L1), [`ui/dr-ui/ui/export.slint:246`](../../ui/dr-ui/ui/export.slint#L246), [`ui/dr-ui/ui/library.slint:2035`](../../ui/dr-ui/ui/library.slint#L2035), [`ui/dr-ui/ui/library.slint:2044`](../../ui/dr-ui/ui/library.slint#L2044), [`ui/dr-ui/ui/library.slint:3210`](../../ui/dr-ui/ui/library.slint#L3210), [`ui/dr-ui/ui/library.slint:5240`](../../ui/dr-ui/ui/library.slint#L5240) | | FR-EXP-8 | [`core/dr-decode/src/lib.rs:367`](../../core/dr-decode/src/lib.rs#L367), [`core/dr-decode/src/lib.rs:391`](../../core/dr-decode/src/lib.rs#L391), [`core/dr-decode/src/lib.rs:405`](../../core/dr-decode/src/lib.rs#L405), [`core/dr-decode/src/lib.rs:76`](../../core/dr-decode/src/lib.rs#L76), [`core/dr-decode/src/lib.rs:84`](../../core/dr-decode/src/lib.rs#L84), [`core/dr-decode/src/lib.rs:87`](../../core/dr-decode/src/lib.rs#L87), [`core/dr-decode/src/locate.rs:1233`](../../core/dr-decode/src/locate.rs#L1233), [`core/dr-decode/src/locate.rs:1292`](../../core/dr-decode/src/locate.rs#L1292), [`core/dr-decode/src/locate.rs:359`](../../core/dr-decode/src/locate.rs#L359), [`core/dr-decode/src/locate.rs:556`](../../core/dr-decode/src/locate.rs#L556), [`core/dr-decode/src/locate.rs:640`](../../core/dr-decode/src/locate.rs#L640), [`core/dr-decode/src/locate.rs:653`](../../core/dr-decode/src/locate.rs#L653), [`core/dr-decode/src/locate.rs:736`](../../core/dr-decode/src/locate.rs#L736), [`core/dr-export/examples/export.rs:99`](../../core/dr-export/examples/export.rs#L99), [`core/dr-export/src/encode.rs:117`](../../core/dr-export/src/encode.rs#L117), [`core/dr-export/src/encode.rs:161`](../../core/dr-export/src/encode.rs#L161), [`core/dr-export/src/encode.rs:1`](../../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/encode.rs:206`](../../core/dr-export/src/encode.rs#L206), [`core/dr-export/src/encode.rs:235`](../../core/dr-export/src/encode.rs#L235), [`core/dr-export/src/encode.rs:311`](../../core/dr-export/src/encode.rs#L311), [`core/dr-export/src/encode.rs:325`](../../core/dr-export/src/encode.rs#L325), [`core/dr-export/src/encode.rs:408`](../../core/dr-export/src/encode.rs#L408), [`core/dr-export/src/encode.rs:456`](../../core/dr-export/src/encode.rs#L456), [`core/dr-export/src/encode.rs:70`](../../core/dr-export/src/encode.rs#L70), [`core/dr-export/src/encode.rs:795`](../../core/dr-export/src/encode.rs#L795), [`core/dr-export/src/encode.rs:809`](../../core/dr-export/src/encode.rs#L809), [`core/dr-export/src/encode.rs:850`](../../core/dr-export/src/encode.rs#L850), [`core/dr-export/src/encode.rs:898`](../../core/dr-export/src/encode.rs#L898), [`core/dr-export/src/exif.rs:1`](../../core/dr-export/src/exif.rs#L1), [`core/dr-export/src/lib.rs:140`](../../core/dr-export/src/lib.rs#L140), [`core/dr-export/src/metadata.rs:1`](../../core/dr-export/src/metadata.rs#L1), [`core/dr-export/src/metadata.rs:41`](../../core/dr-export/src/metadata.rs#L41), [`core/dr-export/src/metadata.rs:74`](../../core/dr-export/src/metadata.rs#L74), [`core/dr-types/src/lib.rs:657`](../../core/dr-types/src/lib.rs#L657), [`core/dr-types/src/settings.rs:671`](../../core/dr-types/src/settings.rs#L671), [`ui/dr-ui/src/decoder_seam.rs:256`](../../ui/dr-ui/src/decoder_seam.rs#L256), [`ui/dr-ui/src/develop/session.rs:37`](../../ui/dr-ui/src/develop/session.rs#L37), [`ui/dr-ui/src/develop/session.rs:471`](../../ui/dr-ui/src/develop/session.rs#L471), [`ui/dr-ui/src/develop/session.rs:583`](../../ui/dr-ui/src/develop/session.rs#L583), [`ui/dr-ui/src/export.rs:1127`](../../ui/dr-ui/src/export.rs#L1127), [`ui/dr-ui/src/export.rs:1173`](../../ui/dr-ui/src/export.rs#L1173), [`ui/dr-ui/src/export.rs:1201`](../../ui/dr-ui/src/export.rs#L1201), [`ui/dr-ui/src/export.rs:1238`](../../ui/dr-ui/src/export.rs#L1238), [`ui/dr-ui/src/export.rs:1339`](../../ui/dr-ui/src/export.rs#L1339), [`ui/dr-ui/src/export.rs:1357`](../../ui/dr-ui/src/export.rs#L1357), [`ui/dr-ui/src/export.rs:916`](../../ui/dr-ui/src/export.rs#L916), [`ui/dr-ui/src/lib.rs:295`](../../ui/dr-ui/src/lib.rs#L295), [`ui/dr-ui/src/lib.rs:319`](../../ui/dr-ui/src/lib.rs#L319), [`ui/dr-ui/src/lib.rs:686`](../../ui/dr-ui/src/lib.rs#L686), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1) | -| FR-EXP-9 | [`core/dr-decode/src/lib.rs:547`](../../core/dr-decode/src/lib.rs#L547), [`core/dr-export/src/lib.rs:132`](../../core/dr-export/src/lib.rs#L132), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1491`](../../core/dr-gpu/src/adjust.rs#L1491), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/decoder_seam.rs:256`](../../ui/dr-ui/src/decoder_seam.rs#L256), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/render.rs:678`](../../ui/dr-ui/src/develop/render.rs#L678), [`ui/dr-ui/src/develop/render.rs:716`](../../ui/dr-ui/src/develop/render.rs#L716), [`ui/dr-ui/src/lib.rs:654`](../../ui/dr-ui/src/lib.rs#L654), [`ui/dr-ui/src/library/sweep.rs:538`](../../ui/dr-ui/src/library/sweep.rs#L538), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | +| FR-EXP-9 | [`core/dr-decode/src/lib.rs:547`](../../core/dr-decode/src/lib.rs#L547), [`core/dr-export/src/lib.rs:132`](../../core/dr-export/src/lib.rs#L132), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1557`](../../core/dr-gpu/src/adjust.rs#L1557), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/decoder_seam.rs:256`](../../ui/dr-ui/src/decoder_seam.rs#L256), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/render.rs:678`](../../ui/dr-ui/src/develop/render.rs#L678), [`ui/dr-ui/src/develop/render.rs:716`](../../ui/dr-ui/src/develop/render.rs#L716), [`ui/dr-ui/src/lib.rs:654`](../../ui/dr-ui/src/lib.rs#L654), [`ui/dr-ui/src/library/sweep.rs:538`](../../ui/dr-ui/src/library/sweep.rs#L538), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | | FR-INF-1 | [`ui/dr-ui/src/lib.rs:1478`](../../ui/dr-ui/src/lib.rs#L1478), [`ui/dr-ui/ui/settings.slint:824`](../../ui/dr-ui/ui/settings.slint#L824) | | FR-MRG-1 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1), [`ui/dr-ui/src/lib.rs:1904`](../../ui/dr-ui/src/lib.rs#L1904), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1533`](../../ui/dr-ui/ui/app.slint#L1533), [`ui/dr-ui/ui/app.slint:592`](../../ui/dr-ui/ui/app.slint#L592), [`ui/dr-ui/ui/library.slint:2049`](../../ui/dr-ui/ui/library.slint#L2049), [`ui/dr-ui/ui/library.slint:5197`](../../ui/dr-ui/ui/library.slint#L5197), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) | | FR-MRG-10 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1), [`core/dr-pano/src/seam.rs:1`](../../core/dr-pano/src/seam.rs#L1) | | FR-MRG-11 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1) | -| FR-MRG-2 | [`core/dr-gpu/src/adjust.rs:1514`](../../core/dr-gpu/src/adjust.rs#L1514), [`core/dr-gpu/src/adjust.rs:1641`](../../core/dr-gpu/src/adjust.rs#L1641), [`core/dr-gpu/src/adjust.rs:528`](../../core/dr-gpu/src/adjust.rs#L528), [`core/dr-gpu/src/adjust.rs:94`](../../core/dr-gpu/src/adjust.rs#L94), [`core/dr-pipeline/src/graph.rs:916`](../../core/dr-pipeline/src/graph.rs#L916), [`core/dr-pipeline/src/operation.rs:1150`](../../core/dr-pipeline/src/operation.rs#L1150), [`core/dr-pipeline/src/operation.rs:2529`](../../core/dr-pipeline/src/operation.rs#L2529), [`core/dr-pipeline/src/operation.rs:2569`](../../core/dr-pipeline/src/operation.rs#L2569), [`core/dr-pipeline/src/operation.rs:516`](../../core/dr-pipeline/src/operation.rs#L516), [`core/dr-pipeline/src/operation.rs:749`](../../core/dr-pipeline/src/operation.rs#L749), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1) | -| FR-MRG-3 | [`core/dr-decode/examples/linear_dng.rs:1`](../../core/dr-decode/examples/linear_dng.rs#L1), [`core/dr-decode/src/lib.rs:129`](../../core/dr-decode/src/lib.rs#L129), [`core/dr-decode/src/lib.rs:136`](../../core/dr-decode/src/lib.rs#L136), [`core/dr-decode/src/lib.rs:607`](../../core/dr-decode/src/lib.rs#L607), [`core/dr-decode/src/profile.rs:397`](../../core/dr-decode/src/profile.rs#L397), [`core/dr-export/src/dng.rs:1`](../../core/dr-export/src/dng.rs#L1), [`core/dr-gpu/src/demosaic.rs:337`](../../core/dr-gpu/src/demosaic.rs#L337), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1) | +| FR-MRG-2 | [`core/dr-gpu/src/adjust.rs:102`](../../core/dr-gpu/src/adjust.rs#L102), [`core/dr-gpu/src/adjust.rs:1580`](../../core/dr-gpu/src/adjust.rs#L1580), [`core/dr-gpu/src/adjust.rs:1711`](../../core/dr-gpu/src/adjust.rs#L1711), [`core/dr-gpu/src/adjust.rs:567`](../../core/dr-gpu/src/adjust.rs#L567), [`core/dr-pipeline/src/graph.rs:916`](../../core/dr-pipeline/src/graph.rs#L916), [`core/dr-pipeline/src/operation.rs:1163`](../../core/dr-pipeline/src/operation.rs#L1163), [`core/dr-pipeline/src/operation.rs:2547`](../../core/dr-pipeline/src/operation.rs#L2547), [`core/dr-pipeline/src/operation.rs:2587`](../../core/dr-pipeline/src/operation.rs#L2587), [`core/dr-pipeline/src/operation.rs:529`](../../core/dr-pipeline/src/operation.rs#L529), [`core/dr-pipeline/src/operation.rs:762`](../../core/dr-pipeline/src/operation.rs#L762), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1) | +| FR-MRG-3 | [`core/dr-decode/examples/linear_dng.rs:1`](../../core/dr-decode/examples/linear_dng.rs#L1), [`core/dr-decode/src/lib.rs:129`](../../core/dr-decode/src/lib.rs#L129), [`core/dr-decode/src/lib.rs:136`](../../core/dr-decode/src/lib.rs#L136), [`core/dr-decode/src/lib.rs:607`](../../core/dr-decode/src/lib.rs#L607), [`core/dr-decode/src/profile.rs:397`](../../core/dr-decode/src/profile.rs#L397), [`core/dr-export/src/dng.rs:1`](../../core/dr-export/src/dng.rs#L1), [`core/dr-gpu/src/demosaic.rs:349`](../../core/dr-gpu/src/demosaic.rs#L349), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1) | | FR-MRG-4 | [`core/dr-export/src/inscribed.rs:1`](../../core/dr-export/src/inscribed.rs#L1), [`core/dr-pano/src/fill.rs:1`](../../core/dr-pano/src/fill.rs#L1), [`core/dr-pano/src/migan.rs:1`](../../core/dr-pano/src/migan.rs#L1), [`core/dr-pano/src/projection.rs:1`](../../core/dr-pano/src/projection.rs#L1), [`ui/dr-ui/src/library/paths.rs:365`](../../ui/dr-ui/src/library/paths.rs#L365), [`ui/dr-ui/src/library/paths.rs:369`](../../ui/dr-ui/src/library/paths.rs#L369), [`ui/dr-ui/src/merge.rs:174`](../../ui/dr-ui/src/merge.rs#L174), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1), [`ui/dr-ui/ui/merge.slint:50`](../../ui/dr-ui/ui/merge.slint#L50) | | FR-MRG-5 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) | | FR-MRG-6 | [`core/dr-pipeline/src/sidecar.rs:1055`](../../core/dr-pipeline/src/sidecar.rs#L1055), [`core/dr-pipeline/src/sidecar.rs:116`](../../core/dr-pipeline/src/sidecar.rs#L116), [`core/dr-pipeline/src/sidecar.rs:126`](../../core/dr-pipeline/src/sidecar.rs#L126), [`core/dr-pipeline/src/sidecar.rs:2284`](../../core/dr-pipeline/src/sidecar.rs#L2284), [`core/dr-pipeline/src/sidecar.rs:860`](../../core/dr-pipeline/src/sidecar.rs#L860), [`core/dr-thumbs/src/lib.rs:75`](../../core/dr-thumbs/src/lib.rs#L75), [`ui/dr-ui/src/export.rs:156`](../../ui/dr-ui/src/export.rs#L156), [`ui/dr-ui/src/export.rs:370`](../../ui/dr-ui/src/export.rs#L370), [`ui/dr-ui/src/export.rs:694`](../../ui/dr-ui/src/export.rs#L694), [`ui/dr-ui/src/lib.rs:1933`](../../ui/dr-ui/src/lib.rs#L1933), [`ui/dr-ui/src/library/cells.rs:353`](../../ui/dr-ui/src/library/cells.rs#L353), [`ui/dr-ui/src/library/cells.rs:374`](../../ui/dr-ui/src/library/cells.rs#L374), [`ui/dr-ui/src/library/cells.rs:56`](../../ui/dr-ui/src/library/cells.rs#L56), [`ui/dr-ui/src/library/composite.rs:1`](../../ui/dr-ui/src/library/composite.rs#L1), [`ui/dr-ui/src/library/sweep.rs:31`](../../ui/dr-ui/src/library/sweep.rs#L31), [`ui/dr-ui/src/library_ui/controller.rs:116`](../../ui/dr-ui/src/library_ui/controller.rs#L116), [`ui/dr-ui/src/library_ui/controller.rs:126`](../../ui/dr-ui/src/library_ui/controller.rs#L126), [`ui/dr-ui/src/library_ui/grid.rs:422`](../../ui/dr-ui/src/library_ui/grid.rs#L422), [`ui/dr-ui/src/library_ui/layout.rs:1`](../../ui/dr-ui/src/library_ui/layout.rs#L1), [`ui/dr-ui/src/library_ui/layout.rs:51`](../../ui/dr-ui/src/library_ui/layout.rs#L51), [`ui/dr-ui/src/library_ui/open.rs:44`](../../ui/dr-ui/src/library_ui/open.rs#L44), [`ui/dr-ui/src/library_ui/window.rs:233`](../../ui/dr-ui/src/library_ui/window.rs#L233), [`ui/dr-ui/src/library_ui/window.rs:476`](../../ui/dr-ui/src/library_ui/window.rs#L476), [`ui/dr-ui/src/library_ui/window.rs:664`](../../ui/dr-ui/src/library_ui/window.rs#L664), [`ui/dr-ui/src/merge.rs:1015`](../../ui/dr-ui/src/merge.rs#L1015), [`ui/dr-ui/src/merge.rs:1058`](../../ui/dr-ui/src/merge.rs#L1058), [`ui/dr-ui/src/merge.rs:258`](../../ui/dr-ui/src/merge.rs#L258), [`ui/dr-ui/src/merge_thumbs.rs:1`](../../ui/dr-ui/src/merge_thumbs.rs#L1), [`ui/dr-ui/src/merge_ui.rs:52`](../../ui/dr-ui/src/merge_ui.rs#L52), [`ui/dr-ui/ui/library.slint:1486`](../../ui/dr-ui/ui/library.slint#L1486), [`ui/dr-ui/ui/library.slint:486`](../../ui/dr-ui/ui/library.slint#L486), [`ui/dr-ui/ui/library.slint:549`](../../ui/dr-ui/ui/library.slint#L549), [`ui/dr-ui/ui/library.slint:637`](../../ui/dr-ui/ui/library.slint#L637) | @@ -139,7 +139,7 @@ _None._ | FR-PLAT-AND-2 | [`core/dr-catalog/src/walk.rs:1000`](../../core/dr-catalog/src/walk.rs#L1000), [`core/dr-catalog/src/walk.rs:432`](../../core/dr-catalog/src/walk.rs#L432), [`core/dr-sync-folder/src/lib.rs:242`](../../core/dr-sync-folder/src/lib.rs#L242), [`core/dr-sync-folder/src/tests.rs:51`](../../core/dr-sync-folder/src/tests.rs#L51), [`core/dr-sync/src/error.rs:113`](../../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/error.rs:195`](../../core/dr-sync/src/error.rs#L195), [`core/dr-sync/src/scan.rs:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-sync/src/scan.rs:545`](../../core/dr-sync/src/scan.rs#L545), [`core/dr-sync/src/scan.rs:574`](../../core/dr-sync/src/scan.rs#L574), [`ui/dr-ui/src/library/scan.rs:127`](../../ui/dr-ui/src/library/scan.rs#L127), [`ui/dr-ui/src/library/scan.rs:180`](../../ui/dr-ui/src/library/scan.rs#L180), [`ui/dr-ui/src/library/scan.rs:211`](../../ui/dr-ui/src/library/scan.rs#L211), [`ui/dr-ui/src/library/scan.rs:636`](../../ui/dr-ui/src/library/scan.rs#L636), [`ui/dr-ui/src/library_ui/controller.rs:363`](../../ui/dr-ui/src/library_ui/controller.rs#L363), [`ui/dr-ui/src/library_ui/controller.rs:614`](../../ui/dr-ui/src/library_ui/controller.rs#L614), [`ui/dr-ui/src/library_ui/offline.rs:569`](../../ui/dr-ui/src/library_ui/offline.rs#L569), [`ui/dr-ui/src/library_ui/open.rs:490`](../../ui/dr-ui/src/library_ui/open.rs#L490), [`ui/dr-ui/src/library_ui/open.rs:599`](../../ui/dr-ui/src/library_ui/open.rs#L599) | | FR-PLAT-AND-3 | [`core/dr-catalog/src/jobs.rs:1`](../../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/runner.rs:1`](../../core/dr-catalog/src/runner.rs#L1), [`core/dr-catalog/tests/every_queued_kind_has_a_consumer.rs:1`](../../core/dr-catalog/tests/every_queued_kind_has_a_consumer.rs#L1) | | FR-PLAT-AND-4 | [`core/dr-catalog/src/runner.rs:1`](../../core/dr-catalog/src/runner.rs#L1) | -| FR-PLAT-AND-5 | [`apps/darkroom-android/src/lib.rs:166`](../../apps/darkroom-android/src/lib.rs#L166), [`core/dr-gpu/src/adjust.rs:1406`](../../core/dr-gpu/src/adjust.rs#L1406), [`core/dr-gpu/src/detail.rs:161`](../../core/dr-gpu/src/detail.rs#L161), [`core/dr-gpu/src/detail.rs:533`](../../core/dr-gpu/src/detail.rs#L533), [`core/dr-gpu/tests/detail_stage.rs:415`](../../core/dr-gpu/tests/detail_stage.rs#L415), [`ui/dr-ui/src/develop/render.rs:651`](../../ui/dr-ui/src/develop/render.rs#L651), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:1250`](../../ui/dr-ui/src/lib.rs#L1250), [`ui/dr-ui/src/lib.rs:1649`](../../ui/dr-ui/src/lib.rs#L1649), [`ui/dr-ui/src/memory.rs:163`](../../ui/dr-ui/src/memory.rs#L163), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | +| FR-PLAT-AND-5 | [`apps/darkroom-android/src/lib.rs:166`](../../apps/darkroom-android/src/lib.rs#L166), [`core/dr-gpu/src/adjust.rs:1472`](../../core/dr-gpu/src/adjust.rs#L1472), [`core/dr-gpu/src/detail.rs:161`](../../core/dr-gpu/src/detail.rs#L161), [`core/dr-gpu/src/detail.rs:533`](../../core/dr-gpu/src/detail.rs#L533), [`core/dr-gpu/tests/detail_stage.rs:415`](../../core/dr-gpu/tests/detail_stage.rs#L415), [`ui/dr-ui/src/develop/render.rs:651`](../../ui/dr-ui/src/develop/render.rs#L651), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:1250`](../../ui/dr-ui/src/lib.rs#L1250), [`ui/dr-ui/src/lib.rs:1649`](../../ui/dr-ui/src/lib.rs#L1649), [`ui/dr-ui/src/memory.rs:163`](../../ui/dr-ui/src/memory.rs#L163), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | | FR-PLAT-AND-6 | [`apps/darkroom-android/src/lib.rs:443`](../../apps/darkroom-android/src/lib.rs#L443) | | FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1427`](../../ui/dr-ui/src/lib.rs#L1427), [`ui/dr-ui/src/preset_store.rs:1`](../../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1) | | FR-PLAT-LIN-2 | [`platform/dr-plat/src/display.rs:1`](../../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../../platform/dr-plat/src/display/x11.rs#L1) | @@ -148,9 +148,9 @@ _None._ | FR-PLAT-WIN-3 | [`apps/darkroom-desktop/src/main.rs:19`](../../apps/darkroom-desktop/src/main.rs#L19) | | FR-RAW-1 | [`core/dr-decode/src/lib.rs:260`](../../core/dr-decode/src/lib.rs#L260), [`core/dr-types/src/lib.rs:134`](../../core/dr-types/src/lib.rs#L134), [`core/dr-types/src/lib.rs:205`](../../core/dr-types/src/lib.rs#L205) | | FR-RAW-2 | [`core/dr-decode/src/decoder.rs:1`](../../core/dr-decode/src/decoder.rs#L1), [`core/dr-decode/src/decoder.rs:26`](../../core/dr-decode/src/decoder.rs#L26), [`core/dr-decode/src/decoder.rs:59`](../../core/dr-decode/src/decoder.rs#L59), [`core/dr-decode/src/decoder.rs:95`](../../core/dr-decode/src/decoder.rs#L95), [`ui/dr-ui/src/decoder_seam.rs:184`](../../ui/dr-ui/src/decoder_seam.rs#L184), [`ui/dr-ui/src/decoder_seam.rs:1`](../../ui/dr-ui/src/decoder_seam.rs#L1), [`ui/dr-ui/src/decoder_seam.rs:215`](../../ui/dr-ui/src/decoder_seam.rs#L215), [`ui/dr-ui/src/decoder_seam.rs:256`](../../ui/dr-ui/src/decoder_seam.rs#L256), [`ui/dr-ui/src/export.rs:1238`](../../ui/dr-ui/src/export.rs#L1238), [`ui/dr-ui/src/export.rs:973`](../../ui/dr-ui/src/export.rs#L973), [`ui/dr-ui/src/import.rs:96`](../../ui/dr-ui/src/import.rs#L96), [`ui/dr-ui/src/library/sweep.rs:301`](../../ui/dr-ui/src/library/sweep.rs#L301), [`ui/dr-ui/src/library/sweep.rs:629`](../../ui/dr-ui/src/library/sweep.rs#L629), [`ui/dr-ui/src/library/thumbnails_gen.rs:101`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L101), [`ui/dr-ui/src/merge.rs:119`](../../ui/dr-ui/src/merge.rs#L119), [`ui/dr-ui/src/repairs.rs:243`](../../ui/dr-ui/src/repairs.rs#L243) | -| FR-RAW-3 | [`core/dr-decode/src/lib.rs:156`](../../core/dr-decode/src/lib.rs#L156), [`core/dr-decode/src/lib.rs:547`](../../core/dr-decode/src/lib.rs#L547), [`core/dr-decode/src/locate.rs:1435`](../../core/dr-decode/src/locate.rs#L1435), [`core/dr-gpu/src/demosaic.rs:1182`](../../core/dr-gpu/src/demosaic.rs#L1182), [`core/dr-gpu/src/demosaic.rs:749`](../../core/dr-gpu/src/demosaic.rs#L749), [`core/dr-gpu/tests/hot_pixels.rs:1`](../../core/dr-gpu/tests/hot_pixels.rs#L1) | +| FR-RAW-3 | [`core/dr-decode/src/lib.rs:156`](../../core/dr-decode/src/lib.rs#L156), [`core/dr-decode/src/lib.rs:547`](../../core/dr-decode/src/lib.rs#L547), [`core/dr-decode/src/locate.rs:1435`](../../core/dr-decode/src/locate.rs#L1435), [`core/dr-gpu/src/demosaic.rs:1196`](../../core/dr-gpu/src/demosaic.rs#L1196), [`core/dr-gpu/src/demosaic.rs:762`](../../core/dr-gpu/src/demosaic.rs#L762), [`core/dr-gpu/tests/hot_pixels.rs:1`](../../core/dr-gpu/tests/hot_pixels.rs#L1) | | FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30), [`ui/dr-ui/src/lib.rs:295`](../../ui/dr-ui/src/lib.rs#L295) | -| FR-RAW-5 | [`core/dr-decode/src/lib.rs:184`](../../core/dr-decode/src/lib.rs#L184), [`core/dr-gpu/src/demosaic.rs:1056`](../../core/dr-gpu/src/demosaic.rs#L1056), [`core/dr-gpu/src/demosaic.rs:1180`](../../core/dr-gpu/src/demosaic.rs#L1180), [`core/dr-gpu/src/demosaic.rs:34`](../../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:977`](../../core/dr-gpu/src/demosaic.rs#L977) | +| FR-RAW-5 | [`core/dr-decode/src/lib.rs:184`](../../core/dr-decode/src/lib.rs#L184), [`core/dr-gpu/src/demosaic.rs:1070`](../../core/dr-gpu/src/demosaic.rs#L1070), [`core/dr-gpu/src/demosaic.rs:1194`](../../core/dr-gpu/src/demosaic.rs#L1194), [`core/dr-gpu/src/demosaic.rs:34`](../../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:991`](../../core/dr-gpu/src/demosaic.rs#L991) | | FR-UI-1 | [`core/dr-types/src/settings.rs:1390`](../../core/dr-types/src/settings.rs#L1390), [`core/dr-types/src/settings.rs:492`](../../core/dr-types/src/settings.rs#L492), [`core/dr-types/src/settings.rs:512`](../../core/dr-types/src/settings.rs#L512), [`ui/dr-ui/src/develop_ui.rs:204`](../../ui/dr-ui/src/develop_ui.rs#L204), [`ui/dr-ui/src/lib.rs:126`](../../ui/dr-ui/src/lib.rs#L126), [`ui/dr-ui/src/lib.rs:141`](../../ui/dr-ui/src/lib.rs#L141), [`ui/dr-ui/src/lib.rs:163`](../../ui/dr-ui/src/lib.rs#L163), [`ui/dr-ui/src/lib.rs:3274`](../../ui/dr-ui/src/lib.rs#L3274), [`ui/dr-ui/src/lib.rs:3293`](../../ui/dr-ui/src/lib.rs#L3293), [`ui/dr-ui/src/lib.rs:3320`](../../ui/dr-ui/src/lib.rs#L3320), [`ui/dr-ui/src/lib.rs:3371`](../../ui/dr-ui/src/lib.rs#L3371), [`ui/dr-ui/src/lib.rs:3404`](../../ui/dr-ui/src/lib.rs#L3404), [`ui/dr-ui/src/library_ui/grid.rs:242`](../../ui/dr-ui/src/library_ui/grid.rs#L242), [`ui/dr-ui/src/masks_ui.rs:1608`](../../ui/dr-ui/src/masks_ui.rs#L1608), [`ui/dr-ui/src/settings_ui.rs:143`](../../ui/dr-ui/src/settings_ui.rs#L143), [`ui/dr-ui/ui/adjust.slint:1000`](../../ui/dr-ui/ui/adjust.slint#L1000), [`ui/dr-ui/ui/app.slint:3147`](../../ui/dr-ui/ui/app.slint#L3147), [`ui/dr-ui/ui/app.slint:670`](../../ui/dr-ui/ui/app.slint#L670), [`ui/dr-ui/ui/app.slint:815`](../../ui/dr-ui/ui/app.slint#L815), [`ui/dr-ui/ui/identity.slint:249`](../../ui/dr-ui/ui/identity.slint#L249), [`ui/dr-ui/ui/library.slint:1469`](../../ui/dr-ui/ui/library.slint#L1469), [`ui/dr-ui/ui/settings.slint:129`](../../ui/dr-ui/ui/settings.slint#L129), [`ui/dr-ui/ui/settings.slint:660`](../../ui/dr-ui/ui/settings.slint#L660), [`ui/dr-ui/ui/toolrail.slint:180`](../../ui/dr-ui/ui/toolrail.slint#L180), [`ui/dr-ui/ui/toolrail.slint:92`](../../ui/dr-ui/ui/toolrail.slint#L92), [`ui/dr-ui/ui/widgets.slint:1117`](../../ui/dr-ui/ui/widgets.slint#L1117) | | FR-UI-2 | [`ui/dr-ui/src/collections_ui/controller.rs:45`](../../ui/dr-ui/src/collections_ui/controller.rs#L45), [`ui/dr-ui/src/collections_ui/controller.rs:83`](../../ui/dr-ui/src/collections_ui/controller.rs#L83), [`ui/dr-ui/src/collections_ui/drag.rs:246`](../../ui/dr-ui/src/collections_ui/drag.rs#L246), [`ui/dr-ui/src/collections_ui/drag.rs:256`](../../ui/dr-ui/src/collections_ui/drag.rs#L256), [`ui/dr-ui/src/collections_ui/press.rs:453`](../../ui/dr-ui/src/collections_ui/press.rs#L453), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:138`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L138), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:415`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L415), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/gestures.rs:1`](../../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:126`](../../ui/dr-ui/src/lib.rs#L126), [`ui/dr-ui/src/library_ui/filter_bar.rs:351`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L351), [`ui/dr-ui/src/library_ui/grid.rs:242`](../../ui/dr-ui/src/library_ui/grid.rs#L242), [`ui/dr-ui/src/library_ui/window.rs:1149`](../../ui/dr-ui/src/library_ui/window.rs#L1149), [`ui/dr-ui/tests/scroll_cue.rs:1`](../../ui/dr-ui/tests/scroll_cue.rs#L1), [`ui/dr-ui/ui/app.slint:137`](../../ui/dr-ui/ui/app.slint#L137), [`ui/dr-ui/ui/app.slint:3545`](../../ui/dr-ui/ui/app.slint#L3545), [`ui/dr-ui/ui/app.slint:799`](../../ui/dr-ui/ui/app.slint#L799), [`ui/dr-ui/ui/collections.slint:1354`](../../ui/dr-ui/ui/collections.slint#L1354), [`ui/dr-ui/ui/controls.slint:626`](../../ui/dr-ui/ui/controls.slint#L626), [`ui/dr-ui/ui/gestures.slint:1`](../../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1356`](../../ui/dr-ui/ui/library.slint#L1356), [`ui/dr-ui/ui/library.slint:1389`](../../ui/dr-ui/ui/library.slint#L1389), [`ui/dr-ui/ui/library.slint:1717`](../../ui/dr-ui/ui/library.slint#L1717), [`ui/dr-ui/ui/library.slint:1724`](../../ui/dr-ui/ui/library.slint#L1724), [`ui/dr-ui/ui/library.slint:1825`](../../ui/dr-ui/ui/library.slint#L1825), [`ui/dr-ui/ui/library.slint:3168`](../../ui/dr-ui/ui/library.slint#L3168), [`ui/dr-ui/ui/library.slint:586`](../../ui/dr-ui/ui/library.slint#L586), [`ui/dr-ui/ui/presets.slint:114`](../../ui/dr-ui/ui/presets.slint#L114), [`ui/dr-ui/ui/settings.slint:143`](../../ui/dr-ui/ui/settings.slint#L143), [`ui/dr-ui/ui/widgets.slint:1117`](../../ui/dr-ui/ui/widgets.slint#L1117) | | FR-UI-3 | [`ui/dr-ui/src/collections_ui/controller.rs:143`](../../ui/dr-ui/src/collections_ui/controller.rs#L143), [`ui/dr-ui/src/collections_ui/controller.rs:348`](../../ui/dr-ui/src/collections_ui/controller.rs#L348), [`ui/dr-ui/src/collections_ui/controller.rs:361`](../../ui/dr-ui/src/collections_ui/controller.rs#L361), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/develop/masks.rs:361`](../../ui/dr-ui/src/develop/masks.rs#L361), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/library_ui/grid.rs:228`](../../ui/dr-ui/src/library_ui/grid.rs#L228), [`ui/dr-ui/src/masks_ui.rs:1700`](../../ui/dr-ui/src/masks_ui.rs#L1700), [`ui/dr-ui/src/masks_ui.rs:1722`](../../ui/dr-ui/src/masks_ui.rs#L1722), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/spots_ui.rs:19`](../../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/ui/app.slint:2356`](../../ui/dr-ui/ui/app.slint#L2356), [`ui/dr-ui/ui/collections.slint:1228`](../../ui/dr-ui/ui/collections.slint#L1228), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:78`](../../ui/dr-ui/ui/collections.slint#L78), [`ui/dr-ui/ui/collections.slint:978`](../../ui/dr-ui/ui/collections.slint#L978), [`ui/dr-ui/ui/masks.slint:1246`](../../ui/dr-ui/ui/masks.slint#L1246), [`ui/dr-ui/ui/widgets.slint:72`](../../ui/dr-ui/ui/widgets.slint#L72) | @@ -173,7 +173,7 @@ _None._ | NFR-P13 | [`core/dr-decode/src/preview.rs:121`](../../core/dr-decode/src/preview.rs#L121) | | NFR-P14 | [`core/dr-gpu/src/focus.rs:186`](../../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`ui/dr-ui/src/develop/render.rs:499`](../../ui/dr-ui/src/develop/render.rs#L499), [`ui/dr-ui/src/lib.rs:2348`](../../ui/dr-ui/src/lib.rs#L2348) | | NFR-P3 | [`tools/bench/src/thumbnails.rs:1`](../../tools/bench/src/thumbnails.rs#L1) | -| NFR-P5 | [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`core/dr-gpu/src/adjust.rs:168`](../../core/dr-gpu/src/adjust.rs#L168), [`core/dr-gpu/src/adjust.rs:3042`](../../core/dr-gpu/src/adjust.rs#L3042), [`core/dr-pipeline/src/detail.rs:1225`](../../core/dr-pipeline/src/detail.rs#L1225), [`core/dr-pipeline/src/detail.rs:681`](../../core/dr-pipeline/src/detail.rs#L681), [`ui/dr-ui/src/library/cells.rs:470`](../../ui/dr-ui/src/library/cells.rs#L470), [`ui/dr-ui/src/library/cells.rs:811`](../../ui/dr-ui/src/library/cells.rs#L811), [`ui/dr-ui/src/library_ui/controller.rs:58`](../../ui/dr-ui/src/library_ui/controller.rs#L58), [`ui/dr-ui/src/library_ui/timeline.rs:382`](../../ui/dr-ui/src/library_ui/timeline.rs#L382) | +| NFR-P5 | [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`core/dr-gpu/src/adjust.rs:176`](../../core/dr-gpu/src/adjust.rs#L176), [`core/dr-gpu/src/adjust.rs:3112`](../../core/dr-gpu/src/adjust.rs#L3112), [`core/dr-pipeline/src/detail.rs:1225`](../../core/dr-pipeline/src/detail.rs#L1225), [`core/dr-pipeline/src/detail.rs:681`](../../core/dr-pipeline/src/detail.rs#L681), [`ui/dr-ui/src/library/cells.rs:470`](../../ui/dr-ui/src/library/cells.rs#L470), [`ui/dr-ui/src/library/cells.rs:811`](../../ui/dr-ui/src/library/cells.rs#L811), [`ui/dr-ui/src/library_ui/controller.rs:58`](../../ui/dr-ui/src/library_ui/controller.rs#L58), [`ui/dr-ui/src/library_ui/timeline.rs:382`](../../ui/dr-ui/src/library_ui/timeline.rs#L382) | | NFR-P9 | [`core/dr-catalog/src/backfilled.rs:1`](../../core/dr-catalog/src/backfilled.rs#L1), [`core/dr-catalog/src/schema.rs:956`](../../core/dr-catalog/src/schema.rs#L956), [`core/dr-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/duplicates.rs:1`](../../ui/dr-ui/src/duplicates.rs#L1), [`ui/dr-ui/src/duplicates_ui.rs:1`](../../ui/dr-ui/src/duplicates_ui.rs#L1), [`ui/dr-ui/src/executors.rs:136`](../../ui/dr-ui/src/executors.rs#L136), [`ui/dr-ui/src/executors.rs:220`](../../ui/dr-ui/src/executors.rs#L220), [`ui/dr-ui/src/export.rs:1513`](../../ui/dr-ui/src/export.rs#L1513), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/net_runtime.rs:48`](../../ui/dr-ui/src/net_runtime.rs#L48), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1) | | NFR-PORT-1 | [`core/dr-catalog/src/walk.rs:1`](../../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:274`](../../core/dr-types/src/lib.rs#L274), [`core/dr-types/src/lib.rs:307`](../../core/dr-types/src/lib.rs#L307), [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/display.rs:1`](../../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/storage.rs:1`](../../platform/dr-plat/src/storage.rs#L1), [`platform/dr-plat/src/storage.rs:216`](../../platform/dr-plat/src/storage.rs#L216), [`platform/dr-plat/src/storage.rs:287`](../../platform/dr-plat/src/storage.rs#L287), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`platform/dr-plat/src/volumes.rs:1`](../../platform/dr-plat/src/volumes.rs#L1), [`platform/dr-plat/src/volumes.rs:62`](../../platform/dr-plat/src/volumes.rs#L62), [`ui/dr-ui/src/cards.rs:1`](../../ui/dr-ui/src/cards.rs#L1) | | NFR-PORT-2 | [`core/dr-gpu/src/lib.rs:1`](../../core/dr-gpu/src/lib.rs#L1) | @@ -186,8 +186,8 @@ _None._ | NFR-R6 | [`core/dr-catalog/src/error.rs:1`](../../core/dr-catalog/src/error.rs#L1), [`core/dr-catalog/src/lib.rs:271`](../../core/dr-catalog/src/lib.rs#L271), [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1) | | NFR-R7 | [`core/dr-gpu/src/error.rs:1`](../../core/dr-gpu/src/error.rs#L1) | | NFR-R8 | [`core/dr-gpu/src/error.rs:1`](../../core/dr-gpu/src/error.rs#L1) | -| NFR-RES-1 | [`core/dr-gpu/src/adjust.rs:1406`](../../core/dr-gpu/src/adjust.rs#L1406), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`ui/dr-ui/src/develop/render.rs:651`](../../ui/dr-ui/src/develop/render.rs#L651), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:118`](../../ui/dr-ui/src/lib.rs#L118), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | -| NFR-RES-2 | [`core/dr-gpu/src/adjust.rs:1353`](../../core/dr-gpu/src/adjust.rs#L1353), [`core/dr-gpu/src/demosaic.rs:117`](../../core/dr-gpu/src/demosaic.rs#L117), [`core/dr-gpu/src/demosaic.rs:164`](../../core/dr-gpu/src/demosaic.rs#L164), [`core/dr-gpu/src/demosaic.rs:350`](../../core/dr-gpu/src/demosaic.rs#L350), [`core/dr-gpu/tests/source_window.rs:1`](../../core/dr-gpu/tests/source_window.rs#L1), [`core/dr-pipeline/src/graph.rs:302`](../../core/dr-pipeline/src/graph.rs#L302), [`core/dr-pipeline/src/operation.rs:1776`](../../core/dr-pipeline/src/operation.rs#L1776), [`core/dr-pipeline/src/operation.rs:602`](../../core/dr-pipeline/src/operation.rs#L602), [`core/dr-pipeline/src/tiles.rs:1`](../../core/dr-pipeline/src/tiles.rs#L1), [`ui/dr-ui/src/develop/render.rs:1885`](../../ui/dr-ui/src/develop/render.rs#L1885), [`ui/dr-ui/src/develop/render.rs:1964`](../../ui/dr-ui/src/develop/render.rs#L1964), [`ui/dr-ui/src/develop/render.rs:216`](../../ui/dr-ui/src/develop/render.rs#L216), [`ui/dr-ui/src/develop/render.rs:23`](../../ui/dr-ui/src/develop/render.rs#L23), [`ui/dr-ui/src/develop/render.rs:763`](../../ui/dr-ui/src/develop/render.rs#L763), [`ui/dr-ui/src/develop/session.rs:115`](../../ui/dr-ui/src/develop/session.rs#L115), [`ui/dr-ui/src/develop/session.rs:328`](../../ui/dr-ui/src/develop/session.rs#L328), [`ui/dr-ui/src/develop/session.rs:355`](../../ui/dr-ui/src/develop/session.rs#L355), [`ui/dr-ui/src/faces.rs:463`](../../ui/dr-ui/src/faces.rs#L463), [`ui/dr-ui/src/library/sweep.rs:264`](../../ui/dr-ui/src/library/sweep.rs#L264), [`ui/dr-ui/src/repairs.rs:1155`](../../ui/dr-ui/src/repairs.rs#L1155), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1) | +| NFR-RES-1 | [`core/dr-gpu/src/adjust.rs:1472`](../../core/dr-gpu/src/adjust.rs#L1472), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`ui/dr-ui/src/develop/render.rs:651`](../../ui/dr-ui/src/develop/render.rs#L651), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:118`](../../ui/dr-ui/src/lib.rs#L118), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) | +| NFR-RES-2 | [`core/dr-gpu/src/adjust.rs:1419`](../../core/dr-gpu/src/adjust.rs#L1419), [`core/dr-gpu/src/demosaic.rs:122`](../../core/dr-gpu/src/demosaic.rs#L122), [`core/dr-gpu/src/demosaic.rs:169`](../../core/dr-gpu/src/demosaic.rs#L169), [`core/dr-gpu/src/demosaic.rs:362`](../../core/dr-gpu/src/demosaic.rs#L362), [`core/dr-gpu/tests/source_window.rs:1`](../../core/dr-gpu/tests/source_window.rs#L1), [`core/dr-pipeline/src/graph.rs:302`](../../core/dr-pipeline/src/graph.rs#L302), [`core/dr-pipeline/src/operation.rs:1794`](../../core/dr-pipeline/src/operation.rs#L1794), [`core/dr-pipeline/src/operation.rs:615`](../../core/dr-pipeline/src/operation.rs#L615), [`core/dr-pipeline/src/tiles.rs:1`](../../core/dr-pipeline/src/tiles.rs#L1), [`ui/dr-ui/src/develop/render.rs:1885`](../../ui/dr-ui/src/develop/render.rs#L1885), [`ui/dr-ui/src/develop/render.rs:1964`](../../ui/dr-ui/src/develop/render.rs#L1964), [`ui/dr-ui/src/develop/render.rs:216`](../../ui/dr-ui/src/develop/render.rs#L216), [`ui/dr-ui/src/develop/render.rs:23`](../../ui/dr-ui/src/develop/render.rs#L23), [`ui/dr-ui/src/develop/render.rs:763`](../../ui/dr-ui/src/develop/render.rs#L763), [`ui/dr-ui/src/develop/session.rs:115`](../../ui/dr-ui/src/develop/session.rs#L115), [`ui/dr-ui/src/develop/session.rs:328`](../../ui/dr-ui/src/develop/session.rs#L328), [`ui/dr-ui/src/develop/session.rs:355`](../../ui/dr-ui/src/develop/session.rs#L355), [`ui/dr-ui/src/faces.rs:463`](../../ui/dr-ui/src/faces.rs#L463), [`ui/dr-ui/src/library/sweep.rs:264`](../../ui/dr-ui/src/library/sweep.rs#L264), [`ui/dr-ui/src/repairs.rs:1155`](../../ui/dr-ui/src/repairs.rs#L1155), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1) | | NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/schema.rs:1221`](../../core/dr-catalog/src/schema.rs#L1221), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`core/dr-thumbs/src/codec.rs:1`](../../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`core/dr-thumbs/src/lib.rs:440`](../../core/dr-thumbs/src/lib.rs#L440) | | NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30) | | NFR-SEC-2 | [`core/dr-sync/src/account.rs:318`](../../core/dr-sync/src/account.rs#L318), [`platform/dr-plat/src/crash.rs:1`](../../platform/dr-plat/src/crash.rs#L1), [`platform/dr-plat/src/diagnostics.rs:1`](../../platform/dr-plat/src/diagnostics.rs#L1), [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1), [`platform/dr-plat/src/diagnostics/redact.rs:1`](../../platform/dr-plat/src/diagnostics/redact.rs#L1), [`platform/dr-plat/src/secrets.rs:82`](../../platform/dr-plat/src/secrets.rs#L82) | @@ -209,7 +209,7 @@ Defined in `requirements.md` and marked `(post-v1)` on the defining line. Not in - FR-PLG-11 - FR-PLG-12 - FR-PLG-1a -- FR-PLG-2 — tagged in [`core/dr-pipeline/src/declared/decl.rs:1`](../../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/expr.rs:152`](../../core/dr-pipeline/src/declared/expr.rs#L152), [`core/dr-pipeline/src/declared/expr.rs:1`](../../core/dr-pipeline/src/declared/expr.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:1`](../../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:82`](../../core/dr-pipeline/src/declared/mod.rs#L82), [`core/dr-pipeline/src/descriptor.rs:15`](../../core/dr-pipeline/src/descriptor.rs#L15), [`core/dr-pipeline/src/descriptor.rs:734`](../../core/dr-pipeline/src/descriptor.rs#L734), [`core/dr-pipeline/src/operation.rs:232`](../../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/tests/declared_parity.rs:1`](../../core/dr-pipeline/tests/declared_parity.rs#L1), [`core/dr-pipeline/tests/declared_parity.rs:241`](../../core/dr-pipeline/tests/declared_parity.rs#L241), [`core/dr-pipeline/tests/declared_parity.rs:306`](../../core/dr-pipeline/tests/declared_parity.rs#L306), [`core/dr-pipeline/tests/declared_parity.rs:359`](../../core/dr-pipeline/tests/declared_parity.rs#L359), [`core/dr-pipeline/tests/declared_parity.rs:420`](../../core/dr-pipeline/tests/declared_parity.rs#L420) +- FR-PLG-2 — tagged in [`core/dr-pipeline/src/declared/decl.rs:1`](../../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/expr.rs:152`](../../core/dr-pipeline/src/declared/expr.rs#L152), [`core/dr-pipeline/src/declared/expr.rs:1`](../../core/dr-pipeline/src/declared/expr.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:1`](../../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:82`](../../core/dr-pipeline/src/declared/mod.rs#L82), [`core/dr-pipeline/src/descriptor.rs:15`](../../core/dr-pipeline/src/descriptor.rs#L15), [`core/dr-pipeline/src/descriptor.rs:734`](../../core/dr-pipeline/src/descriptor.rs#L734), [`core/dr-pipeline/src/operation.rs:232`](../../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/tests/declared_parity.rs:1`](../../core/dr-pipeline/tests/declared_parity.rs#L1), [`core/dr-pipeline/tests/declared_parity.rs:241`](../../core/dr-pipeline/tests/declared_parity.rs#L241), [`core/dr-pipeline/tests/declared_parity.rs:306`](../../core/dr-pipeline/tests/declared_parity.rs#L306), [`core/dr-pipeline/tests/declared_parity.rs:359`](../../core/dr-pipeline/tests/declared_parity.rs#L359), [`core/dr-pipeline/tests/declared_parity.rs:421`](../../core/dr-pipeline/tests/declared_parity.rs#L421) - FR-PLG-2a - FR-PLG-2b - FR-PLG-2c