mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-28 01:34:02 +00:00
[wgsl-in] Ensure textureSampleLevel's level argument is an integer for depth textures (#6529)
Until now we accepted a float, as is the case for non-depth textures. This makes us compliant with the spec. The validator is updated to expect an Sint or Uint when the ImageClass is ImageClass::Depth. The SPIR-V frontend converts the LOD argument from float to Sint (assuming that it is representable), likewise The SPIR-V backend now converts the LOD from either Sint or Uint to Float. HLSL and MSL backends require no changes as they implicitly do that conversion. GLSL does not support non-compare LOD samples, therefore no changes are required.
This commit is contained in:
parent
c110bf22d8
commit
baecb5fbf1
@ -924,7 +924,43 @@ impl<'w> BlockContext<'w> {
|
|||||||
depth_id,
|
depth_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let lod_id = self.cached[lod_handle];
|
let mut lod_id = self.cached[lod_handle];
|
||||||
|
// SPIR-V expects the LOD to be a float for all image classes.
|
||||||
|
// lod_id, however, will be an integer for depth images,
|
||||||
|
// therefore we must do a conversion.
|
||||||
|
if matches!(
|
||||||
|
self.ir_module.types[image_type].inner,
|
||||||
|
crate::TypeInner::Image {
|
||||||
|
class: crate::ImageClass::Depth { .. },
|
||||||
|
..
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
let lod_f32_id = self.gen_id();
|
||||||
|
let f32_type_id = self.get_type_id(LookupType::Local(LocalType::Numeric(
|
||||||
|
NumericType::Scalar(crate::Scalar::F32),
|
||||||
|
)));
|
||||||
|
let convert_op = match *self.fun_info[lod_handle]
|
||||||
|
.ty
|
||||||
|
.inner_with(&self.ir_module.types)
|
||||||
|
{
|
||||||
|
crate::TypeInner::Scalar(crate::Scalar {
|
||||||
|
kind: crate::ScalarKind::Uint,
|
||||||
|
width: 4,
|
||||||
|
}) => spirv::Op::ConvertUToF,
|
||||||
|
crate::TypeInner::Scalar(crate::Scalar {
|
||||||
|
kind: crate::ScalarKind::Sint,
|
||||||
|
width: 4,
|
||||||
|
}) => spirv::Op::ConvertSToF,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
block.body.push(Instruction::unary(
|
||||||
|
convert_op,
|
||||||
|
f32_type_id,
|
||||||
|
lod_f32_id,
|
||||||
|
lod_id,
|
||||||
|
));
|
||||||
|
lod_id = lod_f32_id;
|
||||||
|
}
|
||||||
mask |= spirv::ImageOperands::LOD;
|
mask |= spirv::ImageOperands::LOD;
|
||||||
inst.add_operand(mask.bits());
|
inst.add_operand(mask.bits());
|
||||||
inst.add_operand(lod_id);
|
inst.add_operand(lod_id);
|
||||||
|
@ -30,6 +30,7 @@ impl<'function> super::BlockContext<'function> {
|
|||||||
match self.expressions[handle] {
|
match self.expressions[handle] {
|
||||||
crate::Expression::GlobalVariable(handle) => Ok(self.global_arena[handle].ty),
|
crate::Expression::GlobalVariable(handle) => Ok(self.global_arena[handle].ty),
|
||||||
crate::Expression::FunctionArgument(i) => Ok(self.arguments[i as usize].ty),
|
crate::Expression::FunctionArgument(i) => Ok(self.arguments[i as usize].ty),
|
||||||
|
crate::Expression::Access { base, .. } => Ok(self.get_image_expr_ty(base)?),
|
||||||
ref other => Err(Error::InvalidImageExpression(other.clone())),
|
ref other => Err(Error::InvalidImageExpression(other.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,6 +461,7 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let span = self.span_from_with_op(start);
|
||||||
|
|
||||||
let mut image_ops = if words_left != 0 {
|
let mut image_ops = if words_left != 0 {
|
||||||
words_left -= 1;
|
words_left -= 1;
|
||||||
@ -486,9 +488,34 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
|
|||||||
let lod_lexp = self.lookup_expression.lookup(lod_expr)?;
|
let lod_lexp = self.lookup_expression.lookup(lod_expr)?;
|
||||||
let lod_handle =
|
let lod_handle =
|
||||||
self.get_expr_handle(lod_expr, lod_lexp, ctx, emitter, block, body_idx);
|
self.get_expr_handle(lod_expr, lod_lexp, ctx, emitter, block, body_idx);
|
||||||
|
|
||||||
|
let is_depth_image = {
|
||||||
|
let image_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?;
|
||||||
|
let image_ty = ctx.get_image_expr_ty(image_lexp.image)?;
|
||||||
|
matches!(
|
||||||
|
ctx.type_arena[image_ty].inner,
|
||||||
|
crate::TypeInner::Image {
|
||||||
|
class: crate::ImageClass::Depth { .. },
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
level = if options.compare {
|
level = if options.compare {
|
||||||
log::debug!("Assuming {:?} is zero", lod_handle);
|
log::debug!("Assuming {:?} is zero", lod_handle);
|
||||||
crate::SampleLevel::Zero
|
crate::SampleLevel::Zero
|
||||||
|
} else if is_depth_image {
|
||||||
|
log::debug!(
|
||||||
|
"Assuming level {:?} converts losslessly to an integer",
|
||||||
|
lod_handle
|
||||||
|
);
|
||||||
|
let expr = crate::Expression::As {
|
||||||
|
expr: lod_handle,
|
||||||
|
kind: crate::ScalarKind::Sint,
|
||||||
|
convert: Some(4),
|
||||||
|
};
|
||||||
|
let s32_lod_handle = ctx.expressions.append(expr, span);
|
||||||
|
crate::SampleLevel::Exact(s32_lod_handle)
|
||||||
} else {
|
} else {
|
||||||
crate::SampleLevel::Exact(lod_handle)
|
crate::SampleLevel::Exact(lod_handle)
|
||||||
};
|
};
|
||||||
|
@ -106,7 +106,7 @@ pub enum ExpressionError {
|
|||||||
InvalidGatherComponent(crate::SwizzleComponent),
|
InvalidGatherComponent(crate::SwizzleComponent),
|
||||||
#[error("Gather can't be done for image dimension {0:?}")]
|
#[error("Gather can't be done for image dimension {0:?}")]
|
||||||
InvalidGatherDimension(crate::ImageDimension),
|
InvalidGatherDimension(crate::ImageDimension),
|
||||||
#[error("Sample level (exact) type {0:?} is not a scalar float")]
|
#[error("Sample level (exact) type {0:?} has an invalid type")]
|
||||||
InvalidSampleLevelExactType(Handle<crate::Expression>),
|
InvalidSampleLevelExactType(Handle<crate::Expression>),
|
||||||
#[error("Sample level (bias) type {0:?} is not a scalar float")]
|
#[error("Sample level (bias) type {0:?} is not a scalar float")]
|
||||||
InvalidSampleLevelBiasType(Handle<crate::Expression>),
|
InvalidSampleLevelBiasType(Handle<crate::Expression>),
|
||||||
@ -530,11 +530,24 @@ impl super::Validator {
|
|||||||
crate::SampleLevel::Auto => ShaderStages::FRAGMENT,
|
crate::SampleLevel::Auto => ShaderStages::FRAGMENT,
|
||||||
crate::SampleLevel::Zero => ShaderStages::all(),
|
crate::SampleLevel::Zero => ShaderStages::all(),
|
||||||
crate::SampleLevel::Exact(expr) => {
|
crate::SampleLevel::Exact(expr) => {
|
||||||
match resolver[expr] {
|
match class {
|
||||||
Ti::Scalar(Sc {
|
crate::ImageClass::Depth { .. } => match resolver[expr] {
|
||||||
kind: Sk::Float, ..
|
Ti::Scalar(Sc {
|
||||||
}) => {}
|
kind: Sk::Sint | Sk::Uint,
|
||||||
_ => return Err(ExpressionError::InvalidSampleLevelExactType(expr)),
|
..
|
||||||
|
}) => {}
|
||||||
|
_ => {
|
||||||
|
return Err(ExpressionError::InvalidSampleLevelExactType(expr))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => match resolver[expr] {
|
||||||
|
Ti::Scalar(Sc {
|
||||||
|
kind: Sk::Float, ..
|
||||||
|
}) => {}
|
||||||
|
_ => {
|
||||||
|
return Err(ExpressionError::InvalidSampleLevelExactType(expr))
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ShaderStages::all()
|
ShaderStages::all()
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,9 @@ fn gather() -> @location(0) vec4<f32> {
|
|||||||
@fragment
|
@fragment
|
||||||
fn depth_no_comparison() -> @location(0) vec4<f32> {
|
fn depth_no_comparison() -> @location(0) vec4<f32> {
|
||||||
let tc = vec2<f32>(0.5);
|
let tc = vec2<f32>(0.5);
|
||||||
|
let level = 1;
|
||||||
let s2d = textureSample(image_2d_depth, sampler_reg, tc);
|
let s2d = textureSample(image_2d_depth, sampler_reg, tc);
|
||||||
let s2d_gather = textureGather(image_2d_depth, sampler_reg, tc);
|
let s2d_gather = textureGather(image_2d_depth, sampler_reg, tc);
|
||||||
return s2d + s2d_gather;
|
let s2d_level = textureSampleLevel(image_2d_depth, sampler_reg, tc, level);
|
||||||
|
return s2d + s2d_gather + s2d_level;
|
||||||
}
|
}
|
||||||
|
@ -369,5 +369,6 @@ float4 depth_no_comparison() : SV_Target0
|
|||||||
float2 tc_3 = (0.5).xx;
|
float2 tc_3 = (0.5).xx;
|
||||||
float s2d_1 = image_2d_depth.Sample(sampler_reg, tc_3);
|
float s2d_1 = image_2d_depth.Sample(sampler_reg, tc_3);
|
||||||
float4 s2d_gather = image_2d_depth.Gather(sampler_reg, tc_3);
|
float4 s2d_gather = image_2d_depth.Gather(sampler_reg, tc_3);
|
||||||
return ((s2d_1).xxxx + s2d_gather);
|
float s2d_level = image_2d_depth.SampleLevel(sampler_reg, tc_3, 1);
|
||||||
|
return (((s2d_1).xxxx + s2d_gather) + (s2d_level).xxxx);
|
||||||
}
|
}
|
||||||
|
@ -265,5 +265,6 @@ fragment depth_no_comparisonOutput depth_no_comparison(
|
|||||||
metal::float2 tc_3 = metal::float2(0.5);
|
metal::float2 tc_3 = metal::float2(0.5);
|
||||||
float s2d_1 = image_2d_depth.sample(sampler_reg, tc_3);
|
float s2d_1 = image_2d_depth.sample(sampler_reg, tc_3);
|
||||||
metal::float4 s2d_gather = image_2d_depth.gather(sampler_reg, tc_3);
|
metal::float4 s2d_gather = image_2d_depth.gather(sampler_reg, tc_3);
|
||||||
return depth_no_comparisonOutput { metal::float4(s2d_1) + s2d_gather };
|
float s2d_level = image_2d_depth.sample(sampler_reg, tc_3, metal::level(1));
|
||||||
|
return depth_no_comparisonOutput { (metal::float4(s2d_1) + s2d_gather) + metal::float4(s2d_level) };
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.1
|
; Version: 1.1
|
||||||
; Generator: rspirv
|
; Generator: rspirv
|
||||||
; Bound: 520
|
; Bound: 526
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpCapability Image1D
|
OpCapability Image1D
|
||||||
OpCapability Sampled1D
|
OpCapability Sampled1D
|
||||||
@ -687,8 +687,14 @@ OpBranch %512
|
|||||||
%515 = OpCompositeExtract %7 %514 0
|
%515 = OpCompositeExtract %7 %514 0
|
||||||
%516 = OpSampledImage %428 %511 %510
|
%516 = OpSampledImage %428 %511 %510
|
||||||
%517 = OpImageGather %23 %516 %280 %198
|
%517 = OpImageGather %23 %516 %280 %198
|
||||||
%518 = OpCompositeConstruct %23 %515 %515 %515 %515
|
%518 = OpSampledImage %428 %511 %510
|
||||||
%519 = OpFAdd %23 %518 %517
|
%520 = OpConvertSToF %7 %29
|
||||||
OpStore %508 %519
|
%519 = OpImageSampleExplicitLod %23 %518 %280 Lod %520
|
||||||
|
%521 = OpCompositeExtract %7 %519 0
|
||||||
|
%522 = OpCompositeConstruct %23 %515 %515 %515 %515
|
||||||
|
%523 = OpFAdd %23 %522 %517
|
||||||
|
%524 = OpCompositeConstruct %23 %521 %521 %521 %521
|
||||||
|
%525 = OpFAdd %23 %523 %524
|
||||||
|
OpStore %508 %525
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
@ -235,5 +235,6 @@ fn depth_no_comparison() -> @location(0) vec4<f32> {
|
|||||||
const tc_3 = vec2(0.5f);
|
const tc_3 = vec2(0.5f);
|
||||||
let s2d_1 = textureSample(image_2d_depth, sampler_reg, tc_3);
|
let s2d_1 = textureSample(image_2d_depth, sampler_reg, tc_3);
|
||||||
let s2d_gather = textureGather(image_2d_depth, sampler_reg, tc_3);
|
let s2d_gather = textureGather(image_2d_depth, sampler_reg, tc_3);
|
||||||
return (vec4(s2d_1) + s2d_gather);
|
let s2d_level = textureSampleLevel(image_2d_depth, sampler_reg, tc_3, 1i);
|
||||||
|
return ((vec4(s2d_1) + s2d_gather) + vec4(s2d_level));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user