use super::*;
pub(in crate::passes) fn lower_sample_depth(
ctx: &mut Ctx,
_name: &str,
res: Option<Word>,
rty: Option<Word>,
args: &[Word],
v4: Word,
) -> Result<Vec<Instruction>, String> {
let (res, rty) = match (res, rty) {
(Some(r), Some(t)) => (r, t),
_ => return Err("air.sample_depth has no result".into()),
};
if args.len() < 4 {
return Err("air.sample_depth missing texture/sampler/coord".into());
}
let (mut img, samp, coord) = (resolve_image_value(ctx, args[0]), args[1], args[3]);
if texture_operand_is_private_pointer(ctx, img) {
if let Some(sampled_img) = single_sampled_image_for_private_read(ctx, img) {
img = sampled_img;
} else {
return lower_null_texture_result(ctx, res, rty);
}
}
let (dim, arrayed) = ctx
.image_dims
.get(&img)
.copied()
.unwrap_or((Dim::Dim2D, false));
let comp = ctx
.image_comp
.get(&img)
.copied()
.unwrap_or(crate::passes::ImageComp::Float);
if arrayed {
return Err("air.sample_depth array textures are unsupported".into());
}
if comp != crate::passes::ImageComp::Float {
return Err("air.sample_depth on non-float texture".into());
}
let img_ty = ctx.ty_image(dim, arrayed, comp);
let si_ty = ctx.ty_sampled_image(img_ty);
let si = ctx.module.fresh_id();
let color = ctx.module.fresh_id();
let depth = ctx.module.fresh_id();
let mut out = vec![Instruction::new(
Op::SampledImage,
Some(si_ty),
Some(si),
vec![Operand::IdRef(img), Operand::IdRef(samp)],
)];
let coord_for_sample = build_sample_coord(ctx, dim, arrayed, coord, args, &mut out)?;
push_image_sample(
ctx,
&mut out,
v4,
color,
si,
coord_for_sample,
None,
false,
None,
);
out.push(Instruction::new(
Op::CompositeExtract,
Some(ctx.ty_float()),
Some(depth),
vec![Operand::IdRef(color), Operand::LiteralBit32(0)],
));
let rdef = type_def_of(ctx, rty);
let is_struct = rdef
.as_ref()
.map(|d| d.class.opcode == Op::TypeStruct)
.unwrap_or(false);
if is_struct {
let i8u = ctx.ty_int8();
let undef8 = ctx.module.fresh_id();
out.push(Instruction::new(Op::Undef, Some(i8u), Some(undef8), vec![]));
out.push(Instruction::new(
Op::CompositeConstruct,
Some(rty),
Some(res),
vec![Operand::IdRef(depth), Operand::IdRef(undef8)],
));
} else {
out.push(Instruction::new(
Op::CopyObject,
Some(rty),
Some(res),
vec![Operand::IdRef(depth)],
));
}
Ok(out)
}
pub(in crate::passes) fn lower_sample_compare_depth(
ctx: &mut Ctx,
_name: &str,
res: Option<Word>,
rty: Option<Word>,
args: &[Word],
v4: Word,
) -> Result<Vec<Instruction>, String> {
let (res, rty) = match (res, rty) {
(Some(r), Some(t)) => (r, t),
_ => return Err("air.sample_compare_depth has no result".into()),
};
if args.len() < 5 {
return Err("air.sample_compare_depth missing texture/sampler/coord/reference".into());
}
let (mut img, samp, coord, reference) =
(resolve_image_value(ctx, args[0]), args[1], args[3], args[4]);
if texture_operand_is_private_pointer(ctx, img) {
if let Some(sampled_img) = single_sampled_image_for_private_read(ctx, img) {
img = sampled_img;
} else {
return lower_null_texture_result(ctx, res, rty);
}
}
let (dim, arrayed) = ctx
.image_dims
.get(&img)
.copied()
.unwrap_or((Dim::Dim2D, false));
let comp = ctx
.image_comp
.get(&img)
.copied()
.unwrap_or(crate::passes::ImageComp::Float);
if arrayed {
return Err("air.sample_compare_depth array textures are unsupported".into());
}
if comp != crate::passes::ImageComp::Float {
return Err("air.sample_compare_depth on non-float texture".into());
}
let img_ty = ctx.ty_image(dim, arrayed, comp);
let si_ty = ctx.ty_sampled_image(img_ty);
let float_ty = ctx.ty_float();
let bool_ty = ctx.ty_bool();
let si = ctx.module.fresh_id();
let color = ctx.module.fresh_id();
let depth = ctx.module.fresh_id();
let passed = ctx.module.fresh_id();
let shadow = ctx.module.fresh_id();
let one = ctx.const_float(1.0);
let zero = ctx.const_float(0.0);
let mut out = vec![Instruction::new(
Op::SampledImage,
Some(si_ty),
Some(si),
vec![Operand::IdRef(img), Operand::IdRef(samp)],
)];
let coord_for_sample = build_sample_coord(ctx, dim, arrayed, coord, args, &mut out)?;
push_image_sample(
ctx,
&mut out,
v4,
color,
si,
coord_for_sample,
None,
false,
None,
);
out.push(Instruction::new(
Op::CompositeExtract,
Some(float_ty),
Some(depth),
vec![Operand::IdRef(color), Operand::LiteralBit32(0)],
));
out.push(Instruction::new(
Op::FOrdLessThanEqual,
Some(bool_ty),
Some(passed),
vec![Operand::IdRef(depth), Operand::IdRef(reference)],
));
out.push(Instruction::new(
Op::Select,
Some(float_ty),
Some(shadow),
vec![
Operand::IdRef(passed),
Operand::IdRef(one),
Operand::IdRef(zero),
],
));
let rdef = type_def_of(ctx, rty);
let is_struct = rdef
.as_ref()
.map(|d| d.class.opcode == Op::TypeStruct)
.unwrap_or(false);
if is_struct {
let i8u = ctx.ty_int8();
let undef8 = ctx.module.fresh_id();
out.push(Instruction::new(Op::Undef, Some(i8u), Some(undef8), vec![]));
out.push(Instruction::new(
Op::CompositeConstruct,
Some(rty),
Some(res),
vec![Operand::IdRef(shadow), Operand::IdRef(undef8)],
));
} else {
out.push(Instruction::new(
Op::CopyObject,
Some(rty),
Some(res),
vec![Operand::IdRef(shadow)],
));
}
Ok(out)
}
pub(in crate::passes) fn find_sample_lod(
ctx: &mut Ctx,
arrayed: bool,
args: &[Word],
out: &mut Vec<Instruction>,
) -> Option<Word> {
let start = if arrayed { 4 } else { 3 };
args.get(start..)?
.iter()
.find_map(|arg| sample_lod_as_f32(ctx, *arg, out))
}
pub(in crate::passes) fn sample_spatial_dims(dim: Dim) -> Option<usize> {
match dim {
Dim::Dim1D => Some(1),
Dim::Dim2D => Some(2),
Dim::Dim3D => Some(3),
_ => None,
}
}
pub(in crate::passes) fn push_image_sample(
ctx: &mut Ctx,
out: &mut Vec<Instruction>,
result_ty: Word,
result: Word,
sampled_image: Word,
coord: Word,
explicit_lod: Option<Word>,
force_lod0: bool,
const_offset: Option<Word>,
) {
let lod = explicit_lod.or_else(|| {
(force_lod0 || matches!(ctx.stage, Stage::Kernel)).then(|| ctx.const_float(0.0))
});
let mut operands = vec![Operand::IdRef(sampled_image), Operand::IdRef(coord)];
let mut image_operands = spirv::ImageOperands::empty();
if lod.is_some() {
image_operands |= spirv::ImageOperands::LOD;
}
if const_offset.is_some() {
image_operands |= spirv::ImageOperands::CONST_OFFSET;
}
if !image_operands.is_empty() {
operands.push(Operand::ImageOperands(image_operands));
if let Some(lod) = lod {
operands.push(Operand::IdRef(lod));
}
if let Some(offset) = const_offset {
operands.push(Operand::IdRef(offset));
}
}
out.push(Instruction::new(
if lod.is_some() {
Op::ImageSampleExplicitLod
} else {
Op::ImageSampleImplicitLod
},
Some(result_ty),
Some(result),
operands,
));
}
pub(in crate::passes) fn sample_lod_as_f32(
ctx: &mut Ctx,
lod: Word,
out: &mut Vec<Instruction>,
) -> Option<Word> {
let ty = value_result_type(ctx, lod)?;
let def = type_def_of(ctx, ty)?;
if def.class.opcode != Op::TypeFloat {
return None;
}
let width = match def.operands.first() {
Some(Operand::LiteralBit32(w)) => *w,
_ => return None,
};
if width == 32 {
return Some(lod);
}
if width == 16 {
let widened = ctx.module.fresh_id();
out.push(Instruction::new(
Op::FConvert,
Some(ctx.ty_float()),
Some(widened),
vec![Operand::IdRef(lod)],
));
return Some(widened);
}
None
}