Skip to content

Commit fecc71d

Browse files
authored
Add support for sampled images (#320)
* Add support for sampled images Combined image samplers are allowed as resources and require a generic parameter indicating the underlying image type. * fix formatting issues * address review comments * fix formatting issues
1 parent a653c61 commit fecc71d

File tree

7 files changed

+81
-2
lines changed

7 files changed

+81
-2
lines changed

Diff for: crates/rustc_codegen_spirv/src/abi.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::symbols::{parse_attrs, SpirvAttribute};
77
use rspirv::spirv::{Capability, StorageClass, Word};
88
use rustc_middle::bug;
99
use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
10+
use rustc_middle::ty::subst::SubstsRef;
1011
use rustc_middle::ty::{GeneratorSubsts, PolyFnSig, Ty, TyKind, TypeAndMut};
1112
use rustc_span::Span;
1213
use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
@@ -336,7 +337,7 @@ fn trans_type_impl<'tcx>(
336337
ty: TyAndLayout<'tcx>,
337338
is_immediate: bool,
338339
) -> Word {
339-
if let TyKind::Adt(adt, _) = *ty.ty.kind() {
340+
if let TyKind::Adt(adt, substs) = *ty.ty.kind() {
340341
for attr in parse_attrs(cx, cx.tcx.get_attrs(adt.did)) {
341342
if matches!(attr, SpirvAttribute::Block) {
342343
if !adt.is_struct() {
@@ -367,7 +368,7 @@ fn trans_type_impl<'tcx>(
367368
return trans_struct(cx, span, ty, true);
368369
}
369370

370-
if let Some(image) = trans_image(cx, span, ty, attr) {
371+
if let Some(image) = trans_image(cx, span, ty, substs, attr) {
371372
return image;
372373
}
373374
}
@@ -792,6 +793,7 @@ fn trans_image<'tcx>(
792793
cx: &CodegenCx<'tcx>,
793794
span: Span,
794795
ty: TyAndLayout<'tcx>,
796+
substs: SubstsRef<'tcx>,
795797
attr: SpirvAttribute,
796798
) -> Option<Word> {
797799
match attr {
@@ -831,6 +833,28 @@ fn trans_image<'tcx>(
831833
}
832834
Some(SpirvType::Sampler.def(span, cx))
833835
}
836+
SpirvAttribute::SampledImage => {
837+
// see SpirvType::sizeof
838+
if ty.size != Size::from_bytes(4) {
839+
cx.tcx
840+
.sess
841+
.err("#[spirv(sampled_image)] type must have size 4");
842+
return None;
843+
}
844+
845+
// We use a generic to indicate the underlying image type of the sampled image.
846+
// The spirv type of it will be generated by querying the type of the first generic.
847+
if let Some(image_ty) = substs.types().next() {
848+
// TODO: enforce that the generic param is an image type?
849+
let image_type = trans_type_impl(cx, span, cx.layout_of(image_ty), false);
850+
Some(SpirvType::SampledImage { image_type }.def(span, cx))
851+
} else {
852+
cx.tcx
853+
.sess
854+
.err("#[spirv(sampled_image)] type must have a generic image type");
855+
None
856+
}
857+
}
834858
_ => None,
835859
}
836860
}

Diff for: crates/rustc_codegen_spirv/src/builder/builder_methods.rs

+2
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
198198
SpirvType::Function { .. } => self.fatal("memset on functions not implemented yet"),
199199
SpirvType::Image { .. } => self.fatal("cannot memset image"),
200200
SpirvType::Sampler => self.fatal("cannot memset sampler"),
201+
SpirvType::SampledImage { .. } => self.fatal("cannot memset sampled image"),
201202
}
202203
}
203204

@@ -253,6 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
253254
SpirvType::Function { .. } => self.fatal("memset on functions not implemented yet"),
254255
SpirvType::Image { .. } => self.fatal("cannot memset image"),
255256
SpirvType::Sampler => self.fatal("cannot memset sampler"),
257+
SpirvType::SampledImage { .. } => self.fatal("cannot memset sampled image"),
256258
}
257259
}
258260

Diff for: crates/rustc_codegen_spirv/src/codegen_cx/constant.rs

+4
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,10 @@ impl<'tcx> CodegenCx<'tcx> {
501501
.tcx
502502
.sess
503503
.fatal("Cannot create a constant sampler value"),
504+
SpirvType::SampledImage { .. } => self
505+
.tcx
506+
.sess
507+
.fatal("Cannot create a constant sampled image value"),
504508
}
505509
}
506510

Diff for: crates/rustc_codegen_spirv/src/codegen_cx/type_.rs

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> {
177177
SpirvType::Function { .. } => TypeKind::Function,
178178
SpirvType::Image { .. } => TypeKind::Integer,
179179
SpirvType::Sampler => TypeKind::Integer,
180+
SpirvType::SampledImage { .. } => TypeKind::Integer,
180181
}
181182
}
182183
fn type_ptr_to(&self, ty: Self::Type) -> Self::Type {

Diff for: crates/rustc_codegen_spirv/src/spirv_type.rs

+15
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ pub enum SpirvType {
7171
access_qualifier: Option<AccessQualifier>,
7272
},
7373
Sampler,
74+
SampledImage {
75+
image_type: Word,
76+
},
7477
}
7578

7679
impl SpirvType {
@@ -226,6 +229,7 @@ impl SpirvType {
226229
access_qualifier,
227230
),
228231
Self::Sampler => cx.emit_global().type_sampler(),
232+
Self::SampledImage { image_type } => cx.emit_global().type_sampled_image(image_type),
229233
};
230234
cx.type_cache.def(result, self);
231235
result
@@ -293,6 +297,7 @@ impl SpirvType {
293297
Self::Function { .. } => cx.tcx.data_layout.pointer_size,
294298
Self::Image { .. } => Size::from_bytes(4),
295299
Self::Sampler => Size::from_bytes(4),
300+
Self::SampledImage { .. } => Size::from_bytes(4),
296301
};
297302
Some(result)
298303
}
@@ -318,6 +323,7 @@ impl SpirvType {
318323
Self::Function { .. } => cx.tcx.data_layout.pointer_align.abi,
319324
Self::Image { .. } => Align::from_bytes(4).unwrap(),
320325
Self::Sampler => Align::from_bytes(4).unwrap(),
326+
Self::SampledImage { .. } => Align::from_bytes(4).unwrap(),
321327
}
322328
}
323329
}
@@ -455,6 +461,11 @@ impl fmt::Debug for SpirvTypePrinter<'_, '_> {
455461
.field("access_qualifier", &access_qualifier)
456462
.finish(),
457463
SpirvType::Sampler => f.debug_struct("Sampler").field("id", &self.id).finish(),
464+
SpirvType::SampledImage { image_type } => f
465+
.debug_struct("SampledImage")
466+
.field("id", &self.id)
467+
.field("image_type", &self.cx.debug_type(image_type))
468+
.finish(),
458469
};
459470
{
460471
let mut debug_stack = DEBUG_STACK.lock().unwrap();
@@ -589,6 +600,10 @@ impl SpirvTypePrinter<'_, '_> {
589600
.field("access_qualifier", &access_qualifier)
590601
.finish(),
591602
SpirvType::Sampler => f.write_str("Sampler"),
603+
SpirvType::SampledImage { image_type } => f
604+
.debug_struct("SampledImage")
605+
.field("image_type", &self.cx.debug_type(image_type))
606+
.finish(),
592607
}
593608
}
594609
}

Diff for: crates/rustc_codegen_spirv/src/symbols.rs

+2
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ impl Symbols {
338338
("sampler", SpirvAttribute::Sampler),
339339
("block", SpirvAttribute::Block),
340340
("flat", SpirvAttribute::Flat),
341+
("sampled_image", SpirvAttribute::SampledImage),
341342
]
342343
.iter()
343344
.cloned();
@@ -453,6 +454,7 @@ pub enum SpirvAttribute {
453454
access_qualifier: Option<AccessQualifier>,
454455
},
455456
Sampler,
457+
SampledImage,
456458
Block,
457459
Flat,
458460
}

Diff for: crates/spirv-std/src/textures.rs

+31
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,34 @@ impl Image2dArray {
9494
}
9595
}
9696
}
97+
98+
#[allow(unused_attributes)]
99+
#[spirv(sampled_image)]
100+
#[derive(Copy, Clone)]
101+
pub struct SampledImage<I> {
102+
_image: I,
103+
}
104+
105+
impl SampledImage<Image2d> {
106+
pub fn sample(&self, coord: Vec3A) -> Vec4 {
107+
#[cfg(not(target_arch = "spirv"))]
108+
{
109+
let _ = coord;
110+
panic!("Image sampling not supported on CPU");
111+
}
112+
#[cfg(target_arch = "spirv")]
113+
unsafe {
114+
let mut result = Default::default();
115+
asm!(
116+
"%sampledImage = OpLoad typeof*{1} {1}",
117+
"%coord = OpLoad typeof*{2} {2}",
118+
"%result = OpImageSampleImplicitLod typeof*{0} %sampledImage %coord",
119+
"OpStore {0} %result",
120+
in(reg) &mut result,
121+
in(reg) self,
122+
in(reg) &coord
123+
);
124+
result
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)