diff --git a/naga/src/back/hlsl/help.rs b/naga/src/back/hlsl/help.rs index 70c0a692a..8083d15e8 100644 --- a/naga/src/back/hlsl/help.rs +++ b/naga/src/back/hlsl/help.rs @@ -264,6 +264,61 @@ impl super::Writer<'_, W> { Ok(()) } + /// Helper function used by [`Self::write_wrapped_image_load_function`] and + /// [`Self::write_wrapped_image_sample_function`] to write the shared YUV + /// to RGB conversion code for external textures. Expects the preceding + /// code to declare the Y component as a `float` variable of name `y`, the + /// UV components as a `float2` variable of name `uv`, and the external + /// texture params as a variable of name `params`. The emitted code will + /// return the result. + fn write_convert_yuv_to_rgb_and_return( + &mut self, + level: crate::back::Level, + y: &str, + uv: &str, + params: &str, + ) -> BackendResult { + let l1 = level; + let l2 = l1.next(); + + // Convert from YUV to non-linear RGB in the source color space. We + // declare our matrices as row_major in HLSL, therefore we must reverse + // the order of this multiplication + writeln!( + self.out, + "{l1}float3 srcGammaRgb = mul(float4({y}, {uv}, 1.0), {params}.yuv_conversion_matrix).rgb;" + )?; + + // Apply the inverse of the source transfer function to convert to + // linear RGB in the source color space. + writeln!( + self.out, + "{l1}float3 srcLinearRgb = srcGammaRgb < {params}.src_tf.k * {params}.src_tf.b ?" + )?; + writeln!(self.out, "{l2}srcGammaRgb / {params}.src_tf.k :")?; + writeln!(self.out, "{l2}pow((srcGammaRgb + {params}.src_tf.a - 1.0) / {params}.src_tf.a, {params}.src_tf.g);")?; + + // Multiply by the gamut conversion matrix to convert to linear RGB in + // the destination color space. We declare our matrices as row_major in + // HLSL, therefore we must reverse the order of this multiplication. + writeln!( + self.out, + "{l1}float3 dstLinearRgb = mul(srcLinearRgb, {params}.gamut_conversion_matrix);" + )?; + + // Finally, apply the dest transfer function to convert to non-linear + // RGB in the destination color space, and return the result. + writeln!( + self.out, + "{l1}float3 dstGammaRgb = dstLinearRgb < {params}.dst_tf.b ?" + )?; + writeln!(self.out, "{l2}{params}.dst_tf.k * dstLinearRgb :")?; + writeln!(self.out, "{l2}{params}.dst_tf.a * pow(dstLinearRgb, 1.0 / {params}.dst_tf.g) - ({params}.dst_tf.a - 1);")?; + + writeln!(self.out, "{l1}return float4(dstGammaRgb, 1.0);")?; + Ok(()) + } + pub(super) fn write_wrapped_image_load_function( &mut self, module: &crate::Module, @@ -346,12 +401,7 @@ impl super::Writer<'_, W> { writeln!(self.out, "{l3}uv = float2(plane1.Load(uint3(plane1_coords, 0u)).x, plane2.Load(uint3(plane2_coords, 0u)).x);")?; writeln!(self.out, "{l2}}}")?; - // Convert from YUV to RGB. We declare our matrices as row_major in HLSL, - // therefore we must reverse the order of this multiplication - writeln!( - self.out, - "{l2}return mul(float4(y, uv, 1.0), params.yuv_conversion_matrix);" - )?; + self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?; writeln!(self.out, "{l1}}}")?; writeln!(self.out, "}}")?; @@ -478,12 +528,8 @@ impl super::Writer<'_, W> { writeln!(self.out, "{l3}uv = float2(plane1.SampleLevel(samp, plane1_coords, 0.0f).x, plane2.SampleLevel(samp, plane2_coords, 0.0f).x);")?; writeln!(self.out, "{l2}}}")?; - // Convert from YUV to RGB. We declare our matrices as row_major in HLSL, - // therefore we must reverse the order of this multiplication - writeln!( - self.out, - "{l2}return mul(float4(y, uv, 1.0), params.yuv_conversion_matrix);" - )?; + self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?; + writeln!(self.out, "{l1}}}")?; writeln!(self.out, "}}")?; writeln!(self.out)?; diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index dd2696c17..8982242da 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -131,6 +131,7 @@ impl Writer { .values() .any(|t| *t == ty) || Some(ty) == module.special_types.external_texture_params + || Some(ty) == module.special_types.external_texture_transfer_function } pub fn write(&mut self, module: &Module, info: &valid::ModuleInfo) -> BackendResult { diff --git a/naga/src/compact/mod.rs b/naga/src/compact/mod.rs index 7fbb5c532..d059ba21e 100644 --- a/naga/src/compact/mod.rs +++ b/naga/src/compact/mod.rs @@ -381,6 +381,7 @@ impl<'module> ModuleTracer<'module> { ref ray_vertex_return, ref predeclared_types, ref external_texture_params, + ref external_texture_transfer_function, } = *special_types; if let Some(ray_desc) = *ray_desc { @@ -398,6 +399,9 @@ impl<'module> ModuleTracer<'module> { if let Some(external_texture_params) = *external_texture_params { self.types_used.insert(external_texture_params); } + if let Some(external_texture_transfer_function) = *external_texture_transfer_function { + self.types_used.insert(external_texture_transfer_function); + } for (_, &handle) in predeclared_types { self.types_used.insert(handle); } @@ -540,6 +544,7 @@ impl ModuleMap { ref mut ray_vertex_return, ref mut predeclared_types, ref mut external_texture_params, + ref mut external_texture_transfer_function, } = *special; if let Some(ref mut ray_desc) = *ray_desc { @@ -557,6 +562,12 @@ impl ModuleMap { self.types.adjust(external_texture_params); } + if let Some(ref mut external_texture_transfer_function) = + *external_texture_transfer_function + { + self.types.adjust(external_texture_transfer_function); + } + for handle in predeclared_types.values_mut() { self.types.adjust(handle); } diff --git a/naga/src/front/type_gen.rs b/naga/src/front/type_gen.rs index d58561796..4165f051d 100644 --- a/naga/src/front/type_gen.rs +++ b/naga/src/front/type_gen.rs @@ -276,14 +276,29 @@ impl crate::Module { handle } - /// Generate [`SpecialTypes::external_texture_params`]. + /// Generate [`SpecialTypes::external_texture_params`] and + /// [`SpecialTypes::external_texture_transfer_function`]. + /// + /// Other than the WGSL backend, every backend that supports external + /// textures does so by lowering them to a set of ordinary textures and + /// some parameters saying how to sample from them. These types are used + /// for said parameters. Note that they are not used by the IR, but + /// generated purely as a convenience for the backends. /// /// [`SpecialTypes::external_texture_params`]: crate::ir::SpecialTypes::external_texture_params - pub fn generate_external_texture_params_type(&mut self) -> Handle { - if let Some(handle) = self.special_types.external_texture_params { - return handle; + /// [`SpecialTypes::external_texture_transfer_function`]: crate::ir::SpecialTypes::external_texture_transfer_function + pub fn generate_external_texture_types(&mut self) { + if self.special_types.external_texture_params.is_some() { + return; } + let ty_f32 = self.types.insert( + crate::Type { + name: None, + inner: crate::TypeInner::Scalar(crate::Scalar::F32), + }, + Span::UNDEFINED, + ); let ty_u32 = self.types.insert( crate::Type { name: None, @@ -312,6 +327,17 @@ impl crate::Module { }, Span::UNDEFINED, ); + let ty_mat3x3f = self.types.insert( + crate::Type { + name: None, + inner: crate::TypeInner::Matrix { + columns: crate::VectorSize::Tri, + rows: crate::VectorSize::Tri, + scalar: crate::Scalar::F32, + }, + }, + Span::UNDEFINED, + ); let ty_mat4x4f = self.types.insert( crate::Type { name: None, @@ -324,7 +350,44 @@ impl crate::Module { Span::UNDEFINED, ); - let handle = self.types.insert( + let transfer_fn_handle = self.types.insert( + crate::Type { + name: Some("NagaExternalTextureTransferFn".to_string()), + inner: crate::TypeInner::Struct { + members: vec![ + crate::StructMember { + name: Some("a".to_string()), + ty: ty_f32, + binding: None, + offset: 0, + }, + crate::StructMember { + name: Some("b".to_string()), + ty: ty_f32, + binding: None, + offset: 4, + }, + crate::StructMember { + name: Some("g".to_string()), + ty: ty_f32, + binding: None, + offset: 8, + }, + crate::StructMember { + name: Some("k".to_string()), + ty: ty_f32, + binding: None, + offset: 12, + }, + ], + span: 16, + }, + }, + Span::UNDEFINED, + ); + self.special_types.external_texture_transfer_function = Some(transfer_fn_handle); + + let params_handle = self.types.insert( crate::Type { name: Some("NagaExternalTextureParams".to_string()), inner: crate::TypeInner::Struct { @@ -335,39 +398,55 @@ impl crate::Module { binding: None, offset: 0, }, + crate::StructMember { + name: Some("gamut_conversion_matrix".to_string()), + ty: ty_mat3x3f, + binding: None, + offset: 64, + }, + crate::StructMember { + name: Some("src_tf".to_string()), + ty: transfer_fn_handle, + binding: None, + offset: 112, + }, + crate::StructMember { + name: Some("dst_tf".to_string()), + ty: transfer_fn_handle, + binding: None, + offset: 128, + }, crate::StructMember { name: Some("sample_transform".to_string()), ty: ty_mat3x2f, binding: None, - offset: 64, + offset: 144, }, crate::StructMember { name: Some("load_transform".to_string()), ty: ty_mat3x2f, binding: None, - offset: 88, + offset: 168, }, crate::StructMember { name: Some("size".to_string()), ty: ty_vec2u, binding: None, - offset: 112, + offset: 192, }, crate::StructMember { name: Some("num_planes".to_string()), ty: ty_u32, binding: None, - offset: 120, + offset: 200, }, ], - span: 128, + span: 208, }, }, Span::UNDEFINED, ); - - self.special_types.external_texture_params = Some(handle); - handle + self.special_types.external_texture_params = Some(params_handle); } /// Populate this module's [`SpecialTypes::predeclared_types`] type and return the handle. diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index 3b6e7806c..e90d7eab0 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -3991,14 +3991,15 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // sample from them. We don't know which backend will // consume the `Module` we're building, but in case it's not // WGSL, populate `SpecialTypes::external_texture_params` - // with the type the backend will use for the parameter + // and `SpecialTypes::external_texture_transfer_function` + // with the types the backend will use for the parameter // buffer. // - // This is *not* the type we are lowering here: that's an - // ordinary `TypeInner::Image`. But the fact we are - // lowering a `texture_external` implies the backends may - // need `SpecialTypes::external_texture_params` too. - ctx.module.generate_external_texture_params_type(); + // Neither of these are the type we are lowering here: + // that's an ordinary `TypeInner::Image`. But the fact we + // are lowering a `texture_external` implies the backends + // may need these additional types too. + ctx.module.generate_external_texture_types(); } ir::TypeInner::Image { dim, diff --git a/naga/src/ir/mod.rs b/naga/src/ir/mod.rs index 50cc89a5b..257445952 100644 --- a/naga/src/ir/mod.rs +++ b/naga/src/ir/mod.rs @@ -2369,19 +2369,42 @@ pub struct SpecialTypes { /// In WGSL, this type would be: /// /// ```ignore - /// struct NagaExternalTextureParams { // align size offset - /// yuv_conversion_matrix: mat4x4, // 16 64 0 - /// sample_transform: mat3x2, // 8 24 64 - /// load_transform: mat3x2, // 8 24 88 - /// size: vec2, // 8 8 112 - /// num_planes: u32, // 4 4 120 - /// } // whole struct: 16 128 + /// struct NagaExternalTextureParams { // align size offset + /// yuv_conversion_matrix: mat4x4, // 16 64 0 + /// gamut_conversion_matrix: mat3x3, // 16 48 64 + /// src_tf: NagaExternalTextureTransferFn, // 4 16 112 + /// dst_tf: NagaExternalTextureTransferFn, // 4 16 128 + /// sample_transform: mat3x2, // 8 24 144 + /// load_transform: mat3x2, // 8 24 168 + /// size: vec2, // 8 8 192 + /// num_planes: u32, // 4 4 200 + /// } // whole struct: 16 208 /// ``` /// - /// Call [`Module::generate_external_texture_params_type`] to populate this - /// if needed and return the handle. + /// Call [`Module::generate_external_texture_types`] to populate this if + /// needed. pub external_texture_params: Option>, + /// Struct describing a gamma encoding transfer function. Member of + /// `NagaExternalTextureParams`, describing how the backend should perform + /// color space conversion when sampling from [`ImageClass::External`] + /// textures. + /// + /// In WGSL, this type would be: + /// + /// ```ignore + /// struct NagaExternalTextureTransferFn { // align size offset + /// a: f32, // 4 4 0 + /// b: f32, // 4 4 4 + /// g: f32, // 4 4 8 + /// k: f32, // 4 4 12 + /// } // whole struct: 4 16 + /// ``` + /// + /// Call [`Module::generate_external_texture_types`] to populate this if + /// needed. + pub external_texture_transfer_function: Option>, + /// Types for predeclared wgsl types instantiated on demand. /// /// Call [`Module::generate_predeclared_type`] to populate this if diff --git a/naga/tests/out/hlsl/wgsl-texture-external.hlsl b/naga/tests/out/hlsl/wgsl-texture-external.hlsl index 517d6a724..dbf57609d 100644 --- a/naga/tests/out/hlsl/wgsl-texture-external.hlsl +++ b/naga/tests/out/hlsl/wgsl-texture-external.hlsl @@ -1,5 +1,16 @@ +struct NagaExternalTextureTransferFn { + float a; + float b; + float g; + float k; +}; + struct NagaExternalTextureParams { row_major float4x4 yuv_conversion_matrix; + row_major float3x3 gamut_conversion_matrix; + int _pad2_0; + NagaExternalTextureTransferFn src_tf; + NagaExternalTextureTransferFn dst_tf; float2 sample_transform_0; float2 sample_transform_1; float2 sample_transform_2; float2 load_transform_0; float2 load_transform_1; float2 load_transform_2; uint2 size; @@ -55,7 +66,15 @@ float4 nagaTextureSampleBaseClampToEdge( float2 plane2_coords = clamp(coords, bounds.xy + plane2_half_texel, bounds.zw - plane2_half_texel); uv = float2(plane1.SampleLevel(samp, plane1_coords, 0.0f).x, plane2.SampleLevel(samp, plane2_coords, 0.0f).x); } - return mul(float4(y, uv, 1.0), params.yuv_conversion_matrix); + float3 srcGammaRgb = mul(float4(y, uv, 1.0), params.yuv_conversion_matrix).rgb; + float3 srcLinearRgb = srcGammaRgb < params.src_tf.k * params.src_tf.b ? + srcGammaRgb / params.src_tf.k : + pow((srcGammaRgb + params.src_tf.a - 1.0) / params.src_tf.a, params.src_tf.g); + float3 dstLinearRgb = mul(srcLinearRgb, params.gamut_conversion_matrix); + float3 dstGammaRgb = dstLinearRgb < params.dst_tf.b ? + params.dst_tf.k * dstLinearRgb : + params.dst_tf.a * pow(dstLinearRgb, 1.0 / params.dst_tf.g) - (params.dst_tf.a - 1); + return float4(dstGammaRgb, 1.0); } } @@ -92,7 +111,15 @@ float4 nagaTextureLoadExternal( uint2 plane2_coords = uint2(floor(float2(plane0_coords) * float2(plane2_size) / float2(plane0_size))); uv = float2(plane1.Load(uint3(plane1_coords, 0u)).x, plane2.Load(uint3(plane2_coords, 0u)).x); } - return mul(float4(y, uv, 1.0), params.yuv_conversion_matrix); + float3 srcGammaRgb = mul(float4(y, uv, 1.0), params.yuv_conversion_matrix).rgb; + float3 srcLinearRgb = srcGammaRgb < params.src_tf.k * params.src_tf.b ? + srcGammaRgb / params.src_tf.k : + pow((srcGammaRgb + params.src_tf.a - 1.0) / params.src_tf.a, params.src_tf.g); + float3 dstLinearRgb = mul(srcLinearRgb, params.gamut_conversion_matrix); + float3 dstGammaRgb = dstLinearRgb < params.dst_tf.b ? + params.dst_tf.k * dstLinearRgb : + params.dst_tf.a * pow(dstLinearRgb, 1.0 / params.dst_tf.g) - (params.dst_tf.a - 1); + return float4(dstGammaRgb, 1.0); } } diff --git a/naga/tests/out/ir/spv-fetch_depth.compact.ron b/naga/tests/out/ir/spv-fetch_depth.compact.ron index c2b7b9b5f..1fbee2deb 100644 --- a/naga/tests/out/ir/spv-fetch_depth.compact.ron +++ b/naga/tests/out/ir/spv-fetch_depth.compact.ron @@ -68,6 +68,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/spv-fetch_depth.ron b/naga/tests/out/ir/spv-fetch_depth.ron index dd019d62a..186f78354 100644 --- a/naga/tests/out/ir/spv-fetch_depth.ron +++ b/naga/tests/out/ir/spv-fetch_depth.ron @@ -131,6 +131,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/spv-shadow.compact.ron b/naga/tests/out/ir/spv-shadow.compact.ron index 04547e651..b49cd9b55 100644 --- a/naga/tests/out/ir/spv-shadow.compact.ron +++ b/naga/tests/out/ir/spv-shadow.compact.ron @@ -156,6 +156,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/spv-shadow.ron b/naga/tests/out/ir/spv-shadow.ron index 0babda31f..e1f0f60b6 100644 --- a/naga/tests/out/ir/spv-shadow.ron +++ b/naga/tests/out/ir/spv-shadow.ron @@ -279,6 +279,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/spv-spec-constants.compact.ron b/naga/tests/out/ir/spv-spec-constants.compact.ron index a07dd0aca..3fa6ffef4 100644 --- a/naga/tests/out/ir/spv-spec-constants.compact.ron +++ b/naga/tests/out/ir/spv-spec-constants.compact.ron @@ -172,6 +172,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/spv-spec-constants.ron b/naga/tests/out/ir/spv-spec-constants.ron index 643d3c730..94c90aa78 100644 --- a/naga/tests/out/ir/spv-spec-constants.ron +++ b/naga/tests/out/ir/spv-spec-constants.ron @@ -263,6 +263,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/wgsl-access.compact.ron b/naga/tests/out/ir/wgsl-access.compact.ron index fff8d0bcf..30e88984f 100644 --- a/naga/tests/out/ir/wgsl-access.compact.ron +++ b/naga/tests/out/ir/wgsl-access.compact.ron @@ -422,6 +422,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-access.ron b/naga/tests/out/ir/wgsl-access.ron index fff8d0bcf..30e88984f 100644 --- a/naga/tests/out/ir/wgsl-access.ron +++ b/naga/tests/out/ir/wgsl-access.ron @@ -422,6 +422,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-collatz.compact.ron b/naga/tests/out/ir/wgsl-collatz.compact.ron index 30168b262..f72c652d0 100644 --- a/naga/tests/out/ir/wgsl-collatz.compact.ron +++ b/naga/tests/out/ir/wgsl-collatz.compact.ron @@ -45,6 +45,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-collatz.ron b/naga/tests/out/ir/wgsl-collatz.ron index 30168b262..f72c652d0 100644 --- a/naga/tests/out/ir/wgsl-collatz.ron +++ b/naga/tests/out/ir/wgsl-collatz.ron @@ -45,6 +45,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-const_assert.compact.ron b/naga/tests/out/ir/wgsl-const_assert.compact.ron index 4d77a5749..2816364f8 100644 --- a/naga/tests/out/ir/wgsl-const_assert.compact.ron +++ b/naga/tests/out/ir/wgsl-const_assert.compact.ron @@ -5,6 +5,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-const_assert.ron b/naga/tests/out/ir/wgsl-const_assert.ron index 4d77a5749..2816364f8 100644 --- a/naga/tests/out/ir/wgsl-const_assert.ron +++ b/naga/tests/out/ir/wgsl-const_assert.ron @@ -5,6 +5,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-diagnostic-filter.compact.ron b/naga/tests/out/ir/wgsl-diagnostic-filter.compact.ron index 10f533f10..c5746696d 100644 --- a/naga/tests/out/ir/wgsl-diagnostic-filter.compact.ron +++ b/naga/tests/out/ir/wgsl-diagnostic-filter.compact.ron @@ -5,6 +5,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-diagnostic-filter.ron b/naga/tests/out/ir/wgsl-diagnostic-filter.ron index 10f533f10..c5746696d 100644 --- a/naga/tests/out/ir/wgsl-diagnostic-filter.ron +++ b/naga/tests/out/ir/wgsl-diagnostic-filter.ron @@ -5,6 +5,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-index-by-value.compact.ron b/naga/tests/out/ir/wgsl-index-by-value.compact.ron index 31a601054..a4f84a7a6 100644 --- a/naga/tests/out/ir/wgsl-index-by-value.compact.ron +++ b/naga/tests/out/ir/wgsl-index-by-value.compact.ron @@ -82,6 +82,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-index-by-value.ron b/naga/tests/out/ir/wgsl-index-by-value.ron index 31a601054..a4f84a7a6 100644 --- a/naga/tests/out/ir/wgsl-index-by-value.ron +++ b/naga/tests/out/ir/wgsl-index-by-value.ron @@ -82,6 +82,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-local-const.compact.ron b/naga/tests/out/ir/wgsl-local-const.compact.ron index b7deb55ac..512972657 100644 --- a/naga/tests/out/ir/wgsl-local-const.compact.ron +++ b/naga/tests/out/ir/wgsl-local-const.compact.ron @@ -27,6 +27,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/wgsl-local-const.ron b/naga/tests/out/ir/wgsl-local-const.ron index b7deb55ac..512972657 100644 --- a/naga/tests/out/ir/wgsl-local-const.ron +++ b/naga/tests/out/ir/wgsl-local-const.ron @@ -27,6 +27,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/wgsl-must-use.compact.ron b/naga/tests/out/ir/wgsl-must-use.compact.ron index 4d148b906..a701a6805 100644 --- a/naga/tests/out/ir/wgsl-must-use.compact.ron +++ b/naga/tests/out/ir/wgsl-must-use.compact.ron @@ -13,6 +13,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-must-use.ron b/naga/tests/out/ir/wgsl-must-use.ron index 4d148b906..a701a6805 100644 --- a/naga/tests/out/ir/wgsl-must-use.ron +++ b/naga/tests/out/ir/wgsl-must-use.ron @@ -13,6 +13,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.compact.ron b/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.compact.ron index 1e568ebbc..640ee25ca 100644 --- a/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.compact.ron +++ b/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.compact.ron @@ -54,6 +54,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: { AtomicCompareExchangeWeakResult(( kind: Uint, diff --git a/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.ron b/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.ron index 1e568ebbc..640ee25ca 100644 --- a/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.ron +++ b/naga/tests/out/ir/wgsl-overrides-atomicCompareExchangeWeak.ron @@ -54,6 +54,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: { AtomicCompareExchangeWeakResult(( kind: Uint, diff --git a/naga/tests/out/ir/wgsl-overrides-ray-query.compact.ron b/naga/tests/out/ir/wgsl-overrides-ray-query.compact.ron index 649ba28d4..f65e8f186 100644 --- a/naga/tests/out/ir/wgsl-overrides-ray-query.compact.ron +++ b/naga/tests/out/ir/wgsl-overrides-ray-query.compact.ron @@ -86,6 +86,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-overrides-ray-query.ron b/naga/tests/out/ir/wgsl-overrides-ray-query.ron index 649ba28d4..f65e8f186 100644 --- a/naga/tests/out/ir/wgsl-overrides-ray-query.ron +++ b/naga/tests/out/ir/wgsl-overrides-ray-query.ron @@ -86,6 +86,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-overrides.compact.ron b/naga/tests/out/ir/wgsl-overrides.compact.ron index eca515610..81221ff79 100644 --- a/naga/tests/out/ir/wgsl-overrides.compact.ron +++ b/naga/tests/out/ir/wgsl-overrides.compact.ron @@ -27,6 +27,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-overrides.ron b/naga/tests/out/ir/wgsl-overrides.ron index eca515610..81221ff79 100644 --- a/naga/tests/out/ir/wgsl-overrides.ron +++ b/naga/tests/out/ir/wgsl-overrides.ron @@ -27,6 +27,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-storage-textures.compact.ron b/naga/tests/out/ir/wgsl-storage-textures.compact.ron index eb70e3bad..ec63fecac 100644 --- a/naga/tests/out/ir/wgsl-storage-textures.compact.ron +++ b/naga/tests/out/ir/wgsl-storage-textures.compact.ron @@ -72,6 +72,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-storage-textures.ron b/naga/tests/out/ir/wgsl-storage-textures.ron index eb70e3bad..ec63fecac 100644 --- a/naga/tests/out/ir/wgsl-storage-textures.ron +++ b/naga/tests/out/ir/wgsl-storage-textures.ron @@ -72,6 +72,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-template-list-trailing-comma.compact.ron b/naga/tests/out/ir/wgsl-template-list-trailing-comma.compact.ron index bfcd83f7f..a8208c09b 100644 --- a/naga/tests/out/ir/wgsl-template-list-trailing-comma.compact.ron +++ b/naga/tests/out/ir/wgsl-template-list-trailing-comma.compact.ron @@ -29,6 +29,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-template-list-trailing-comma.ron b/naga/tests/out/ir/wgsl-template-list-trailing-comma.ron index bfcd83f7f..a8208c09b 100644 --- a/naga/tests/out/ir/wgsl-template-list-trailing-comma.ron +++ b/naga/tests/out/ir/wgsl-template-list-trailing-comma.ron @@ -29,6 +29,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [], diff --git a/naga/tests/out/ir/wgsl-texture-external.compact.ron b/naga/tests/out/ir/wgsl-texture-external.compact.ron index 2bceb18a5..dbffbddcd 100644 --- a/naga/tests/out/ir/wgsl-texture-external.compact.ron +++ b/naga/tests/out/ir/wgsl-texture-external.compact.ron @@ -1,5 +1,12 @@ ( types: [ + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), ( name: None, inner: Scalar(( @@ -28,6 +35,17 @@ ), ), ), + ( + name: None, + inner: Matrix( + columns: Tri, + rows: Tri, + scalar: ( + kind: Float, + width: 4, + ), + ), + ), ( name: None, inner: Matrix( @@ -39,42 +57,92 @@ ), ), ), + ( + name: Some("NagaExternalTextureTransferFn"), + inner: Struct( + members: [ + ( + name: Some("a"), + ty: 0, + binding: None, + offset: 0, + ), + ( + name: Some("b"), + ty: 0, + binding: None, + offset: 4, + ), + ( + name: Some("g"), + ty: 0, + binding: None, + offset: 8, + ), + ( + name: Some("k"), + ty: 0, + binding: None, + offset: 12, + ), + ], + span: 16, + ), + ), ( name: Some("NagaExternalTextureParams"), inner: Struct( members: [ ( name: Some("yuv_conversion_matrix"), - ty: 3, + ty: 5, binding: None, offset: 0, ), ( - name: Some("sample_transform"), - ty: 2, + name: Some("gamut_conversion_matrix"), + ty: 4, binding: None, offset: 64, ), ( - name: Some("load_transform"), - ty: 2, - binding: None, - offset: 88, - ), - ( - name: Some("size"), - ty: 1, + name: Some("src_tf"), + ty: 6, binding: None, offset: 112, ), ( - name: Some("num_planes"), - ty: 0, + name: Some("dst_tf"), + ty: 6, binding: None, - offset: 120, + offset: 128, + ), + ( + name: Some("sample_transform"), + ty: 3, + binding: None, + offset: 144, + ), + ( + name: Some("load_transform"), + ty: 3, + binding: None, + offset: 168, + ), + ( + name: Some("size"), + ty: 2, + binding: None, + offset: 192, + ), + ( + name: Some("num_planes"), + ty: 1, + binding: None, + offset: 200, ), ], - span: 128, + span: 208, ), ), ( @@ -106,7 +174,8 @@ ray_desc: None, ray_intersection: None, ray_vertex_return: None, - external_texture_params: Some(4), + external_texture_params: Some(7), + external_texture_transfer_function: Some(6), predeclared_types: {}, ), constants: [], @@ -119,7 +188,7 @@ group: 0, binding: 0, )), - ty: 5, + ty: 8, init: None, ), ( @@ -129,7 +198,7 @@ group: 0, binding: 1, )), - ty: 6, + ty: 9, init: None, ), ], @@ -140,28 +209,28 @@ arguments: [ ( name: Some("t"), - ty: 5, + ty: 8, binding: None, ), ], result: Some(( - ty: 7, + ty: 10, binding: None, )), local_variables: [ ( name: Some("a"), - ty: 7, + ty: 10, init: None, ), ( name: Some("b"), - ty: 7, + ty: 10, init: None, ), ( name: Some("c"), - ty: 1, + ty: 2, init: None, ), ], @@ -285,7 +354,7 @@ name: Some("fragment_main"), arguments: [], result: Some(( - ty: 7, + ty: 10, binding: Some(Location( location: 0, interpolation: Some(Perspective), @@ -324,7 +393,7 @@ name: Some("vertex_main"), arguments: [], result: Some(( - ty: 7, + ty: 10, binding: Some(BuiltIn(Position( invariant: false, ))), diff --git a/naga/tests/out/ir/wgsl-texture-external.ron b/naga/tests/out/ir/wgsl-texture-external.ron index 2bceb18a5..dbffbddcd 100644 --- a/naga/tests/out/ir/wgsl-texture-external.ron +++ b/naga/tests/out/ir/wgsl-texture-external.ron @@ -1,5 +1,12 @@ ( types: [ + ( + name: None, + inner: Scalar(( + kind: Float, + width: 4, + )), + ), ( name: None, inner: Scalar(( @@ -28,6 +35,17 @@ ), ), ), + ( + name: None, + inner: Matrix( + columns: Tri, + rows: Tri, + scalar: ( + kind: Float, + width: 4, + ), + ), + ), ( name: None, inner: Matrix( @@ -39,42 +57,92 @@ ), ), ), + ( + name: Some("NagaExternalTextureTransferFn"), + inner: Struct( + members: [ + ( + name: Some("a"), + ty: 0, + binding: None, + offset: 0, + ), + ( + name: Some("b"), + ty: 0, + binding: None, + offset: 4, + ), + ( + name: Some("g"), + ty: 0, + binding: None, + offset: 8, + ), + ( + name: Some("k"), + ty: 0, + binding: None, + offset: 12, + ), + ], + span: 16, + ), + ), ( name: Some("NagaExternalTextureParams"), inner: Struct( members: [ ( name: Some("yuv_conversion_matrix"), - ty: 3, + ty: 5, binding: None, offset: 0, ), ( - name: Some("sample_transform"), - ty: 2, + name: Some("gamut_conversion_matrix"), + ty: 4, binding: None, offset: 64, ), ( - name: Some("load_transform"), - ty: 2, - binding: None, - offset: 88, - ), - ( - name: Some("size"), - ty: 1, + name: Some("src_tf"), + ty: 6, binding: None, offset: 112, ), ( - name: Some("num_planes"), - ty: 0, + name: Some("dst_tf"), + ty: 6, binding: None, - offset: 120, + offset: 128, + ), + ( + name: Some("sample_transform"), + ty: 3, + binding: None, + offset: 144, + ), + ( + name: Some("load_transform"), + ty: 3, + binding: None, + offset: 168, + ), + ( + name: Some("size"), + ty: 2, + binding: None, + offset: 192, + ), + ( + name: Some("num_planes"), + ty: 1, + binding: None, + offset: 200, ), ], - span: 128, + span: 208, ), ), ( @@ -106,7 +174,8 @@ ray_desc: None, ray_intersection: None, ray_vertex_return: None, - external_texture_params: Some(4), + external_texture_params: Some(7), + external_texture_transfer_function: Some(6), predeclared_types: {}, ), constants: [], @@ -119,7 +188,7 @@ group: 0, binding: 0, )), - ty: 5, + ty: 8, init: None, ), ( @@ -129,7 +198,7 @@ group: 0, binding: 1, )), - ty: 6, + ty: 9, init: None, ), ], @@ -140,28 +209,28 @@ arguments: [ ( name: Some("t"), - ty: 5, + ty: 8, binding: None, ), ], result: Some(( - ty: 7, + ty: 10, binding: None, )), local_variables: [ ( name: Some("a"), - ty: 7, + ty: 10, init: None, ), ( name: Some("b"), - ty: 7, + ty: 10, init: None, ), ( name: Some("c"), - ty: 1, + ty: 2, init: None, ), ], @@ -285,7 +354,7 @@ name: Some("fragment_main"), arguments: [], result: Some(( - ty: 7, + ty: 10, binding: Some(Location( location: 0, interpolation: Some(Perspective), @@ -324,7 +393,7 @@ name: Some("vertex_main"), arguments: [], result: Some(( - ty: 7, + ty: 10, binding: Some(BuiltIn(Position( invariant: false, ))), diff --git a/naga/tests/out/ir/wgsl-types_with_comments.compact.ron b/naga/tests/out/ir/wgsl-types_with_comments.compact.ron index 1139fab19..7186209f0 100644 --- a/naga/tests/out/ir/wgsl-types_with_comments.compact.ron +++ b/naga/tests/out/ir/wgsl-types_with_comments.compact.ron @@ -38,6 +38,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/naga/tests/out/ir/wgsl-types_with_comments.ron b/naga/tests/out/ir/wgsl-types_with_comments.ron index a1761c17c..480b0d233 100644 --- a/naga/tests/out/ir/wgsl-types_with_comments.ron +++ b/naga/tests/out/ir/wgsl-types_with_comments.ron @@ -63,6 +63,7 @@ ray_intersection: None, ray_vertex_return: None, external_texture_params: None, + external_texture_transfer_function: None, predeclared_types: {}, ), constants: [ diff --git a/tests/tests/wgpu-validation/api/external_texture.rs b/tests/tests/wgpu-validation/api/external_texture.rs index b3dcffb93..989fe5ac8 100644 --- a/tests/tests/wgpu-validation/api/external_texture.rs +++ b/tests/tests/wgpu-validation/api/external_texture.rs @@ -49,6 +49,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -63,6 +66,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -77,6 +83,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -95,6 +104,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -113,6 +125,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -131,6 +146,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -151,6 +169,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -169,6 +190,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -187,6 +211,9 @@ fn create_external_texture() { width: r_texture.width(), height: r_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -212,6 +239,9 @@ fn create_external_texture() { width: uint_texture.width(), height: uint_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -237,6 +267,9 @@ fn create_external_texture() { width: d3_texture.width(), height: d3_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -263,6 +296,9 @@ fn create_external_texture() { width: multisampled_texture.width(), height: multisampled_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -288,6 +324,9 @@ fn create_external_texture() { width: non_binding_texture.width(), height: non_binding_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, @@ -339,6 +378,9 @@ fn external_texture_binding() { height: texture_descriptor.size.height, format: ExternalTextureFormat::Rgba, yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }; @@ -568,6 +610,9 @@ fn destroyed_external_texture_plane() { width: plane_texture.width(), height: plane_texture.height(), yuv_conversion_matrix: [0.0; 16], + gamut_conversion_matrix: [0.0; 9], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), sample_transform: [0.0; 6], load_transform: [0.0; 6], }, diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 68a425c05..b55676ea5 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -76,8 +76,12 @@ pub(crate) struct CommandIndices { pub(crate) next_acceleration_structure_build_command_index: u64, } -/// Parameters provided to shaders via a uniform buffer, describing a -/// [`binding_model::BindingResource::ExternalTexture`] resource binding. +/// Parameters provided to shaders via a uniform buffer of the type +/// [`NagaExternalTextureParams`], describing an [`ExternalTexture`] resource +/// binding. +/// +/// [`NagaExternalTextureParams`]: naga::SpecialTypes::external_texture_params +/// [`ExternalTexture`]: binding_model::BindingResource::ExternalTexture #[repr(C)] #[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod)] pub struct ExternalTextureParams { @@ -87,6 +91,29 @@ pub struct ExternalTextureParams { /// This is ignored when `num_planes` is 1. pub yuv_conversion_matrix: [f32; 16], + /// 3x3 column-major matrix to transform linear RGB values in the source + /// color space to linear RGB values in the destination color space. In + /// combination with [`Self::src_transfer_function`] and + /// [`Self::dst_transfer_function`] this can be used to ensure that + /// [`ImageSample`] and [`ImageLoad`] operations return values in the + /// desired destination color space rather than the source color space of + /// the underlying planes. + /// + /// Includes a padding element after each column. + /// + /// [`ImageSample`]: naga::ir::Expression::ImageSample + /// [`ImageLoad`]: naga::ir::Expression::ImageLoad + pub gamut_conversion_matrix: [f32; 12], + + /// Transfer function for the source color space. The *inverse* of this + /// will be applied to decode non-linear RGB to linear RGB in the source + /// color space. + pub src_transfer_function: wgt::ExternalTextureTransferFunction, + + /// Transfer function for the destination color space. This will be applied + /// to encode linear RGB to non-linear RGB in the destination color space. + pub dst_transfer_function: wgt::ExternalTextureTransferFunction, + /// Transform to apply to [`ImageSample`] coordinates. /// /// This is a 3x2 column-major matrix representing an affine transform from @@ -140,8 +167,26 @@ pub struct ExternalTextureParams { impl ExternalTextureParams { pub fn from_desc(desc: &wgt::ExternalTextureDescriptor) -> Self { + let gamut_conversion_matrix = [ + desc.gamut_conversion_matrix[0], + desc.gamut_conversion_matrix[1], + desc.gamut_conversion_matrix[2], + 0.0, // padding + desc.gamut_conversion_matrix[3], + desc.gamut_conversion_matrix[4], + desc.gamut_conversion_matrix[5], + 0.0, // padding + desc.gamut_conversion_matrix[6], + desc.gamut_conversion_matrix[7], + desc.gamut_conversion_matrix[8], + 0.0, // padding + ]; + Self { yuv_conversion_matrix: desc.yuv_conversion_matrix, + gamut_conversion_matrix, + src_transfer_function: desc.src_transfer_function, + dst_transfer_function: desc.dst_transfer_function, size: [desc.width, desc.height], sample_transform: desc.sample_transform, load_transform: desc.load_transform, @@ -445,6 +490,14 @@ impl Device { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ], + #[rustfmt::skip] + gamut_conversion_matrix: [ + 1.0, 0.0, 0.0, /* padding */ 0.0, + 0.0, 1.0, 0.0, /* padding */ 0.0, + 0.0, 0.0, 1.0, /* padding */ 0.0, + ], + src_transfer_function: Default::default(), + dst_transfer_function: Default::default(), size: [0, 0], #[rustfmt::skip] sample_transform: [ diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 10ec85121..2e21cb904 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -6285,6 +6285,31 @@ pub enum ExternalTextureFormat { Yu12, } +/// Parameters describing a gamma encoding transfer function in the form +/// tf = { k * linear | linear < b +/// { a * pow(linear, 1/g) - (a-1) | linear >= b +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Zeroable, bytemuck::Pod)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[allow(missing_docs)] +pub struct ExternalTextureTransferFunction { + pub a: f32, + pub b: f32, + pub g: f32, + pub k: f32, +} + +impl Default for ExternalTextureTransferFunction { + fn default() -> Self { + Self { + a: 1.0, + b: 1.0, + g: 1.0, + k: 1.0, + } + } +} + /// Describes an [`ExternalTexture`](../wgpu/struct.ExternalTexture.html). /// /// Note that [`width`] and [`height`] are the values that should be returned by @@ -6325,6 +6350,27 @@ pub struct ExternalTextureDescriptor { /// This is ignored when `format` is [`ExternalTextureFormat::Rgba`]. pub yuv_conversion_matrix: [f32; 16], + /// 3x3 column-major matrix to transform linear RGB values in the source + /// color space to linear RGB values in the destination color space. In + /// combination with [`Self::src_transfer_function`] and + /// [`Self::dst_transfer_function`] this can be used to ensure that + /// [`ImageSample`] and [`ImageLoad`] operations return values in the + /// desired destination color space rather than the source color space of + /// the underlying planes. + /// + /// [`ImageSample`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageSample + /// [`ImageLoad`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageLoad + pub gamut_conversion_matrix: [f32; 9], + + /// Transfer function for the source color space. The *inverse* of this + /// will be applied to decode non-linear RGB to linear RGB in the source + /// color space. + pub src_transfer_function: ExternalTextureTransferFunction, + + /// Transfer function for the destination color space. This will be applied + /// to encode linear RGB to non-linear RGB in the destination color space. + pub dst_transfer_function: ExternalTextureTransferFunction, + /// Transform to apply to [`ImageSample`] coordinates. /// /// This is a 3x2 column-major matrix representing an affine transform from @@ -6370,6 +6416,9 @@ impl ExternalTextureDescriptor { yuv_conversion_matrix: self.yuv_conversion_matrix, sample_transform: self.sample_transform, load_transform: self.load_transform, + gamut_conversion_matrix: self.gamut_conversion_matrix, + src_transfer_function: self.src_transfer_function, + dst_transfer_function: self.dst_transfer_function, } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 893d8101b..dcfc19338 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -91,20 +91,21 @@ pub use wgt::{ CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CopyExternalImageDestInfo, CoreCounters, DepthBiasState, DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, DownlevelLimits, Dx12BackendOptions, Dx12Compiler, - DxcShaderModel, DynamicOffset, Extent3d, ExternalTextureFormat, Face, Features, FeaturesWGPU, - FeaturesWebGPU, FilterMode, FrontFace, GlBackendOptions, GlFenceBehavior, Gles3MinorVersion, - HalCounters, ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, - InternalCounters, Limits, MemoryBudgetThresholds, MemoryHints, MultisampleState, - NoopBackendOptions, Origin2d, Origin3d, PipelineStatisticsTypes, PollError, PollStatus, - PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, - PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, - RequestAdapterError, SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, - ShaderRuntimeChecks, ShaderStages, StencilFaceState, StencilOperation, StencilState, - StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TexelCopyBufferLayout, TextureAspect, - TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, - TextureSampleType, TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace, - VertexAttribute, VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, - COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, + DxcShaderModel, DynamicOffset, Extent3d, ExternalTextureFormat, + ExternalTextureTransferFunction, Face, Features, FeaturesWGPU, FeaturesWebGPU, FilterMode, + FrontFace, GlBackendOptions, GlFenceBehavior, Gles3MinorVersion, HalCounters, + ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, InternalCounters, + Limits, MemoryBudgetThresholds, MemoryHints, MultisampleState, NoopBackendOptions, Origin2d, + Origin3d, PipelineStatisticsTypes, PollError, PollStatus, PolygonMode, PowerPreference, + PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, + PushConstantRange, QueryType, RenderBundleDepthStencil, RequestAdapterError, + SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderRuntimeChecks, + ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, + SurfaceCapabilities, SurfaceStatus, TexelCopyBufferLayout, TextureAspect, TextureDimension, + TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, + TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace, VertexAttribute, + VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_ALIGNMENT, };