Skip to content

Commit 43a267b

Browse files
committed
Added all the other sampling functions. Also some fixes and cleanup
1 parent c298bf2 commit 43a267b

File tree

9 files changed

+286
-20
lines changed

9 files changed

+286
-20
lines changed

crates/spirv-std/macros/src/lib.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ const SAMPLE_PARAM_COUNT: usize = 3;
630630
const SAMPLE_PARAM_TYPES: [&str; SAMPLE_PARAM_COUNT] = ["B", "L", "S"];
631631
const SAMPLE_PARAM_OPERANDS: [&str; SAMPLE_PARAM_COUNT] = ["Bias", "Lod", "Sample"];
632632
const SAMPLE_PARAM_NAMES: [&str; SAMPLE_PARAM_COUNT] = ["bias", "lod", "sample_index"];
633+
const SAMPLE_PARAM_EXPLICIT_LOD_MASK: usize = 0b010; // which params require the use of ExplicitLod rather than ImplicitLod
633634

634635
struct SampleImplRewriter(usize, syn::Type);
635636

@@ -653,9 +654,11 @@ impl SampleImplRewriter {
653654
}
654655
ty_str.push(',');
655656
}
656-
ty_str.push_str(">");
657+
ty_str.push('>');
657658
let ty: syn::Type = syn::parse(ty_str.parse().unwrap()).unwrap();
658659

660+
// use the type to insert it into the generic argument of the trait we're implementing
661+
// e.g., `ImageWithMethods<Dummy>` becomes `ImageWithMethods<SampleParams<SomeTy<B>, NoneTy, NoneTy>>`
659662
if let Some(t) = &mut new_impl.trait_ {
660663
if let syn::PathArguments::AngleBracketed(a) =
661664
&mut t.1.segments.last_mut().unwrap().arguments
@@ -665,10 +668,13 @@ impl SampleImplRewriter {
665668
}
666669
}
667670
}
671+
672+
// rewrite the implemented functions
668673
SampleImplRewriter(mask, ty).visit_item_impl_mut(&mut new_impl);
669674
new_impl
670675
}
671676

677+
// generates an operands string for use in the assembly, e.g. "Bias %bias Lod %lod", based on the mask
672678
fn get_operands(&self) -> String {
673679
let mut op = String::new();
674680
for i in 0..SAMPLE_PARAM_COUNT {
@@ -682,6 +688,7 @@ impl SampleImplRewriter {
682688
op
683689
}
684690

691+
// generates list of assembly loads for the data, e.g. "%bias = OpLoad _ {bias}", etc.
685692
fn add_loads(&self, t: &mut Vec<TokenTree>) {
686693
for i in 0..SAMPLE_PARAM_COUNT {
687694
if self.0 & (1 << i) != 0 {
@@ -695,10 +702,11 @@ impl SampleImplRewriter {
695702
}
696703
}
697704

705+
// generates list of register specifications, e.g. `bias = in(reg) &params.bias.0, ...` as separate tokens
698706
fn add_regs(&self, t: &mut Vec<TokenTree>) {
699707
for i in 0..SAMPLE_PARAM_COUNT {
700708
if self.0 & (1 << i) != 0 {
701-
let s = format!("{0} = in(reg) &params.{0},", SAMPLE_PARAM_NAMES[i]);
709+
let s = format!("{0} = in(reg) &params.{0}.0,", SAMPLE_PARAM_NAMES[i]);
702710
let ts: proc_macro2::TokenStream = s.parse().unwrap();
703711
t.extend(ts);
704712
}
@@ -708,6 +716,7 @@ impl SampleImplRewriter {
708716

709717
impl VisitMut for SampleImplRewriter {
710718
fn visit_impl_item_method_mut(&mut self, item: &mut syn::ImplItemMethod) {
719+
// rewrite the last parameter of this method to be of type `SampleParams<...>` we generated earlier
711720
if let Some(syn::FnArg::Typed(p)) = item.sig.inputs.last_mut() {
712721
*p.ty.as_mut() = self.1.clone();
713722
}
@@ -716,6 +725,7 @@ impl VisitMut for SampleImplRewriter {
716725

717726
fn visit_macro_mut(&mut self, m: &mut syn::Macro) {
718727
if m.path.is_ident("asm") {
728+
// this is where the asm! block is manipulated
719729
let t = m.tokens.clone();
720730
let mut new_t = Vec::new();
721731
let mut altered = false;
@@ -724,11 +734,21 @@ impl VisitMut for SampleImplRewriter {
724734
match tt {
725735
TokenTree::Literal(l) => {
726736
if let Ok(l) = syn::parse::<syn::LitStr>(l.to_token_stream().into()) {
737+
// found a string literal
727738
let s = l.value();
728739
if s.contains("$PARAMS") {
729740
altered = true;
741+
// add load instructions before the sampling instruction
730742
self.add_loads(&mut new_t);
743+
// and insert image operands
731744
let s = s.replace("$PARAMS", &self.get_operands());
745+
let lod_type = if self.0 & SAMPLE_PARAM_EXPLICIT_LOD_MASK != 0 {
746+
"ExplicitLod"
747+
} else {
748+
"ImplicitLod "
749+
};
750+
let s = s.replace("$LOD", lod_type);
751+
732752
new_t.push(TokenTree::Literal(proc_macro2::Literal::string(
733753
s.as_str(),
734754
)));
@@ -746,18 +766,21 @@ impl VisitMut for SampleImplRewriter {
746766
}
747767

748768
if altered {
769+
// finally, add register specs
749770
self.add_regs(&mut new_t);
750771
}
751772

773+
// replace all tokens within the asm! block with our new list
752774
m.tokens = new_t.into_iter().collect();
753775
}
754776
}
755777
}
756778

757-
/// Generates permutations of a sampling function containing inline assembly with an image
758-
/// instruction ending with a placeholder `$PARAMS` operand. The last parameter must be named
759-
/// `params`, its type will be rewritten. Relevant generic arguments are added to the function
760-
/// signature. See `SAMPLE_PARAM_TYPES` for a list of names you cannot use as generic arguments.
779+
/// Generates permutations of an `ImageWithMethods` implementation containing sampling functions
780+
/// that have asm instruction ending with a placeholder `$PARAMS` operand. The last parameter
781+
/// of each function must be named `params`, its type will be rewritten. Relevant generic
782+
/// arguments are added to the impl generics.
783+
/// See `SAMPLE_PARAM_TYPES` for a list of names you cannot use as generic arguments.
761784
#[proc_macro_attribute]
762785
#[doc(hidden)]
763786
pub fn gen_sample_param_permutations(_attr: TokenStream, item: TokenStream) -> TokenStream {
@@ -768,6 +791,7 @@ pub fn gen_sample_param_permutations(_attr: TokenStream, item: TokenStream) -> T
768791
fns.push(SampleImplRewriter::rewrite(m, &item_impl));
769792
}
770793

771-
println!("{}", quote! { #(#fns)* }.to_string());
794+
// uncomment to output generated tokenstream to stdout
795+
// println!("{}", quote! { #(#fns)* }.to_string());
772796
quote! { #(#fns)* }.into()
773797
}

crates/spirv-std/src/image.rs

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,13 +1135,72 @@ pub trait ImageWithMethods<
11351135
>
11361136
{
11371137
/// Fetch a single texel with a sampler set at compile time
1138+
#[doc(alias = "OpImageFetch")]
11381139
fn fetch_with<I>(
11391140
&self,
11401141
coordinate: impl ImageCoordinate<I, DIM, ARRAYED>,
11411142
params: Params,
11421143
) -> SampledType::SampleResult
11431144
where
11441145
I: Integer;
1146+
1147+
/// Gathers the requested component from four texels.
1148+
#[doc(alias = "OpImageGather")]
1149+
fn gather_with<F>(
1150+
&self,
1151+
sampler: Sampler,
1152+
coordinate: impl ImageCoordinate<F, DIM, ARRAYED>,
1153+
component: u32,
1154+
params: Params,
1155+
) -> SampledType::Vec4
1156+
where
1157+
Self: HasGather,
1158+
F: Float;
1159+
1160+
/// Sample texels at `coord` from the image using `sampler`.
1161+
fn sample_with<F>(
1162+
&self,
1163+
sampler: Sampler,
1164+
coord: impl ImageCoordinate<F, DIM, ARRAYED>,
1165+
params: Params,
1166+
) -> SampledType::SampleResult
1167+
where
1168+
F: Float;
1169+
1170+
/// Sample the image's depth reference
1171+
#[doc(alias = "OpImageSampleDrefImplicitLod")]
1172+
fn sample_depth_reference_with<F>(
1173+
&self,
1174+
sampler: Sampler,
1175+
coordinate: impl ImageCoordinate<F, DIM, ARRAYED>,
1176+
depth_reference: f32,
1177+
params: Params,
1178+
) -> SampledType
1179+
where
1180+
F: Float;
1181+
1182+
/// Sample the image with a project coordinate
1183+
#[doc(alias = "OpImageSampleProjImplicitLod")]
1184+
fn sample_with_project_coordinate_with<F>(
1185+
&self,
1186+
sampler: Sampler,
1187+
project_coordinate: impl ImageCoordinate<F, DIM, { Arrayed::True as u32 }>,
1188+
params: Params,
1189+
) -> SampledType::SampleResult
1190+
where
1191+
F: Float;
1192+
1193+
/// Sample the image's depth reference with the project coordinate
1194+
#[doc(alias = "OpImageSampleProjDrefImplicitLod")]
1195+
fn sample_depth_reference_with_project_coordinate_with<F>(
1196+
&self,
1197+
sampler: Sampler,
1198+
project_coordinate: impl ImageCoordinate<F, DIM, { Arrayed::True as u32 }>,
1199+
depth_reference: f32,
1200+
params: Params,
1201+
) -> SampledType
1202+
where
1203+
F: Float;
11451204
}
11461205

11471206
#[crate::macros::gen_sample_param_permutations]
@@ -1191,6 +1250,167 @@ impl<
11911250
}
11921251
result.truncate_into()
11931252
}
1253+
1254+
/// Gathers the requested component from four texels.
1255+
#[crate::macros::gpu_only]
1256+
#[doc(alias = "OpImageGather")]
1257+
#[inline]
1258+
fn gather_with<F>(
1259+
&self,
1260+
sampler: Sampler,
1261+
coordinate: impl ImageCoordinate<F, DIM, ARRAYED>,
1262+
component: u32,
1263+
params: SampleParams,
1264+
) -> SampledType::Vec4
1265+
where
1266+
Self: HasGather,
1267+
F: Float,
1268+
{
1269+
let mut result = SampledType::Vec4::default();
1270+
unsafe {
1271+
asm! {
1272+
"%typeSampledImage = OpTypeSampledImage typeof*{this}",
1273+
"%image = OpLoad _ {this}",
1274+
"%sampler = OpLoad _ {sampler}",
1275+
"%coordinate = OpLoad _ {coordinate}",
1276+
"%sampledImage = OpSampledImage %typeSampledImage %image %sampler",
1277+
"%result = OpImageGather typeof*{result} %sampledImage %coordinate {component} $PARAMS",
1278+
"OpStore {result} %result",
1279+
result = in(reg) &mut result,
1280+
this = in(reg) self,
1281+
sampler = in(reg) &sampler,
1282+
coordinate = in(reg) &coordinate,
1283+
component = in(reg) component,
1284+
}
1285+
}
1286+
result
1287+
}
1288+
1289+
/// Sample texels at `coord` from the image using `sampler`.
1290+
#[crate::macros::gpu_only]
1291+
fn sample_with<F>(
1292+
&self,
1293+
sampler: Sampler,
1294+
coord: impl ImageCoordinate<F, DIM, ARRAYED>,
1295+
params: SampleParams,
1296+
) -> SampledType::SampleResult
1297+
where
1298+
F: Float,
1299+
{
1300+
unsafe {
1301+
let mut result = SampledType::Vec4::default();
1302+
asm!(
1303+
"%typeSampledImage = OpTypeSampledImage typeof*{this}",
1304+
"%image = OpLoad _ {this}",
1305+
"%sampler = OpLoad _ {sampler}",
1306+
"%coord = OpLoad _ {coord}",
1307+
"%sampledImage = OpSampledImage %typeSampledImage %image %sampler",
1308+
"%result = OpImageSample$LOD typeof*{result} %sampledImage %coord $PARAMS",
1309+
"OpStore {result} %result",
1310+
result = in(reg) &mut result,
1311+
this = in(reg) self,
1312+
sampler = in(reg) &sampler,
1313+
coord = in(reg) &coord,
1314+
);
1315+
result.truncate_into()
1316+
}
1317+
}
1318+
1319+
/// Sample the image's depth reference
1320+
#[crate::macros::gpu_only]
1321+
#[doc(alias = "OpImageSampleDrefImplicitLod")]
1322+
fn sample_depth_reference_with<F>(
1323+
&self,
1324+
sampler: Sampler,
1325+
coordinate: impl ImageCoordinate<F, DIM, ARRAYED>,
1326+
depth_reference: f32,
1327+
params: SampleParams,
1328+
) -> SampledType
1329+
where
1330+
F: Float,
1331+
{
1332+
let mut result = Default::default();
1333+
unsafe {
1334+
asm!(
1335+
"%image = OpLoad _ {this}",
1336+
"%sampler = OpLoad _ {sampler}",
1337+
"%coordinate = OpLoad _ {coordinate}",
1338+
"%depth_reference = OpLoad _ {depth_reference}", // not required to do this way, but done for consistency
1339+
"%sampledImage = OpSampledImage _ %image %sampler",
1340+
"%result = OpImageSampleDref$LOD _ %sampledImage %coordinate %depth_reference $PARAMS",
1341+
"OpStore {result} %result",
1342+
result = in(reg) &mut result,
1343+
this = in(reg) self,
1344+
sampler = in(reg) &sampler,
1345+
coordinate = in(reg) &coordinate,
1346+
depth_reference = in(reg) &depth_reference,
1347+
);
1348+
}
1349+
result
1350+
}
1351+
1352+
/// Sample the image with a project coordinate
1353+
#[crate::macros::gpu_only]
1354+
#[doc(alias = "OpImageSampleProjImplicitLod")]
1355+
fn sample_with_project_coordinate_with<F>(
1356+
&self,
1357+
sampler: Sampler,
1358+
project_coordinate: impl ImageCoordinate<F, DIM, { Arrayed::True as u32 }>,
1359+
params: SampleParams,
1360+
) -> SampledType::SampleResult
1361+
where
1362+
F: Float,
1363+
{
1364+
unsafe {
1365+
let mut result = SampledType::Vec4::default();
1366+
asm!(
1367+
"%image = OpLoad _ {this}",
1368+
"%sampler = OpLoad _ {sampler}",
1369+
"%project_coordinate = OpLoad _ {project_coordinate}",
1370+
"%sampledImage = OpSampledImage _ %image %sampler",
1371+
"%result = OpImageSampleProj$LOD _ %sampledImage %project_coordinate $PARAMS",
1372+
"OpStore {result} %result",
1373+
result = in(reg) &mut result,
1374+
this = in(reg) self,
1375+
sampler = in(reg) &sampler,
1376+
project_coordinate = in(reg) &project_coordinate,
1377+
);
1378+
result.truncate_into()
1379+
}
1380+
}
1381+
1382+
/// Sample the image's depth reference with the project coordinate
1383+
#[crate::macros::gpu_only]
1384+
#[doc(alias = "OpImageSampleProjDrefImplicitLod")]
1385+
fn sample_depth_reference_with_project_coordinate_with<F>(
1386+
&self,
1387+
sampler: Sampler,
1388+
project_coordinate: impl ImageCoordinate<F, DIM, { Arrayed::True as u32 }>,
1389+
depth_reference: f32,
1390+
params: SampleParams,
1391+
) -> SampledType
1392+
where
1393+
F: Float,
1394+
{
1395+
let mut result = Default::default();
1396+
unsafe {
1397+
asm!(
1398+
"%image = OpLoad _ {this}",
1399+
"%sampler = OpLoad _ {sampler}",
1400+
"%project_coordinate = OpLoad _ {project_coordinate}",
1401+
"%depth_reference = OpLoad _ {depth_reference}", // not required to do this way, but done for consistency
1402+
"%sampledImage = OpSampledImage _ %image %sampler",
1403+
"%result = OpImageSampleProjDref$LOD _ %sampledImage %project_coordinate %depth_reference $PARAMS",
1404+
"OpStore {result} %result",
1405+
result = in(reg) &mut result,
1406+
this = in(reg) self,
1407+
sampler = in(reg) &sampler,
1408+
project_coordinate = in(reg) &project_coordinate,
1409+
depth_reference = in(reg) &depth_reference,
1410+
);
1411+
}
1412+
result
1413+
}
11941414
}
11951415

11961416
/// This is a marker trait to represent the constraints on `OpImageGather` too complex to be

crates/spirv-std/src/image/sample.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ impl<T> OptionTy for SomeTy<T> {
1515
pub struct NoneTy;
1616

1717
/// Helper struct that denotes that the type does exist and is of type T, analog to `Option::Some(T)`
18-
pub struct SomeTy<T>(T);
18+
pub struct SomeTy<T>(pub T);
1919

2020
/// Helper struct that allows building image operands. Start with a global function that returns this
2121
/// struct, and then chain additional calls.
2222
/// Example: `image.sample_with(coords, params::bias(3.0).sample_index(1))`
2323
pub struct SampleParams<B: OptionTy, L: OptionTy, S: OptionTy> {
24+
/// 'Bias' image operand
2425
pub bias: B,
26+
27+
/// 'Lod' image operand
2528
pub lod: L,
29+
30+
/// 'Sample' image operand
2631
pub sample_index: S,
2732
}
2833

0 commit comments

Comments
 (0)