mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-25 16:25:25 +00:00
Implement textures (#276)
This commit is contained in:
parent
59869ec58b
commit
a73f54aa86
@ -305,6 +305,13 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> {
|
||||
}
|
||||
|
||||
fn trans_type_impl<'tcx>(cx: &CodegenCx<'tcx>, ty: TyAndLayout<'tcx>, is_immediate: bool) -> Word {
|
||||
if let TyKind::Adt(adt, _) = *ty.ty.kind() {
|
||||
for attr in parse_attrs(cx, cx.tcx.get_attrs(adt.did)) {
|
||||
if let Some(image) = trans_image(cx, ty, attr) {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: ty.layout is orthogonal to ty.ty, e.g. `ManuallyDrop<Result<isize, isize>>` has abi
|
||||
// `ScalarPair`.
|
||||
// There's a few layers that we go through here. First we inspect layout.abi, then if relevant, layout.fields, etc.
|
||||
@ -705,3 +712,49 @@ fn name_of_struct(ty: TyAndLayout<'_>) -> String {
|
||||
}
|
||||
name
|
||||
}
|
||||
|
||||
fn trans_image<'tcx>(
|
||||
cx: &CodegenCx<'tcx>,
|
||||
ty: TyAndLayout<'tcx>,
|
||||
attr: SpirvAttribute,
|
||||
) -> Option<Word> {
|
||||
match attr {
|
||||
SpirvAttribute::Image {
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
} => {
|
||||
// see SpirvType::sizeof
|
||||
if ty.size != Size::from_bytes(4) {
|
||||
cx.tcx.sess.err("#[spirv(image)] type must have size 4");
|
||||
return None;
|
||||
}
|
||||
// Hardcode to float for now
|
||||
let sampled_type = SpirvType::Float(32).def(cx);
|
||||
let ty = SpirvType::Image {
|
||||
sampled_type,
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
};
|
||||
Some(ty.def(cx))
|
||||
}
|
||||
SpirvAttribute::Sampler => {
|
||||
// see SpirvType::sizeof
|
||||
if ty.size != Size::from_bytes(4) {
|
||||
cx.tcx.sess.err("#[spirv(sampler)] type must have size 4");
|
||||
return None;
|
||||
}
|
||||
Some(SpirvType::Sampler.def(cx))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -185,6 +185,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
SpirvType::Pointer { .. } => self.fatal("memset on pointers not implemented yet"),
|
||||
SpirvType::Function { .. } => self.fatal("memset on functions not implemented yet"),
|
||||
SpirvType::Image { .. } => self.fatal("cannot memset image"),
|
||||
SpirvType::Sampler => self.fatal("cannot memset sampler"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +240,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
SpirvType::Pointer { .. } => self.fatal("memset on pointers not implemented yet"),
|
||||
SpirvType::Function { .. } => self.fatal("memset on functions not implemented yet"),
|
||||
SpirvType::Image { .. } => self.fatal("cannot memset image"),
|
||||
SpirvType::Sampler => self.fatal("cannot memset sampler"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,13 +113,17 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
let line = tokens.last_mut().unwrap();
|
||||
if line
|
||||
.last()
|
||||
.map_or(false, |prev| matches!(prev, Token::Word("typeof")))
|
||||
{
|
||||
*line.last_mut().unwrap() = Token::Typeof(&operands[operand_idx], span);
|
||||
} else {
|
||||
line.push(Token::Placeholder(&operands[operand_idx], span));
|
||||
let typeof_kind = line.last().and_then(|prev| match prev {
|
||||
Token::Word("typeof") => Some(TypeofKind::Plain),
|
||||
Token::Word("typeof*") => Some(TypeofKind::Dereference),
|
||||
_ => None,
|
||||
});
|
||||
match typeof_kind {
|
||||
Some(kind) => {
|
||||
*line.last_mut().unwrap() =
|
||||
Token::Typeof(&operands[operand_idx], span, kind)
|
||||
}
|
||||
None => line.push(Token::Placeholder(&operands[operand_idx], span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,10 +136,19 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeofKind {
|
||||
Plain,
|
||||
Dereference,
|
||||
}
|
||||
|
||||
enum Token<'a, 'cx, 'tcx> {
|
||||
Word(&'a str),
|
||||
Placeholder(&'a InlineAsmOperandRef<'tcx, Builder<'cx, 'tcx>>, Span),
|
||||
Typeof(&'a InlineAsmOperandRef<'tcx, Builder<'cx, 'tcx>>, Span),
|
||||
Typeof(
|
||||
&'a InlineAsmOperandRef<'tcx, Builder<'cx, 'tcx>>,
|
||||
Span,
|
||||
TypeofKind,
|
||||
),
|
||||
}
|
||||
|
||||
enum OutRegister<'a> {
|
||||
@ -204,7 +217,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
Token::Placeholder(_, _) => true,
|
||||
Token::Word(id_str) if id_str.starts_with('%') => true,
|
||||
Token::Word(_) => false,
|
||||
Token::Typeof(_, _) => false,
|
||||
Token::Typeof(_, _, _) => false,
|
||||
} {
|
||||
let result_id = match self.parse_id_out(id_map, first_token) {
|
||||
Some(result_id) => result_id,
|
||||
@ -230,7 +243,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
};
|
||||
let inst_name = match first_token {
|
||||
Token::Word(inst_name) => inst_name,
|
||||
Token::Placeholder(_, span) | Token::Typeof(_, span) => {
|
||||
Token::Placeholder(_, span) | Token::Typeof(_, span, _) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(span, "cannot use a dynamic value as an instruction type");
|
||||
@ -354,7 +367,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
None
|
||||
}
|
||||
},
|
||||
Token::Typeof(_, span) => {
|
||||
Token::Typeof(_, span, _) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(span, "cannot assign to a typeof expression");
|
||||
@ -432,10 +445,26 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
None
|
||||
}
|
||||
},
|
||||
Token::Typeof(hole, span) => match hole {
|
||||
Token::Typeof(hole, span, kind) => match hole {
|
||||
InlineAsmOperandRef::In { reg, value } => {
|
||||
self.check_reg(span, reg);
|
||||
Some(value.immediate().ty)
|
||||
let ty = value.immediate().ty;
|
||||
Some(match kind {
|
||||
TypeofKind::Plain => ty,
|
||||
TypeofKind::Dereference => match self.lookup_type(ty) {
|
||||
SpirvType::Pointer { pointee, .. } => pointee,
|
||||
other => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!(
|
||||
"cannot use typeof* on non-pointer type: {}",
|
||||
other.debug(ty, self)
|
||||
),
|
||||
);
|
||||
ty
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
InlineAsmOperandRef::Out {
|
||||
reg,
|
||||
@ -559,7 +588,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
let word = match token {
|
||||
Token::Word(word) => Some(word),
|
||||
Token::Placeholder(_, _) => None,
|
||||
Token::Typeof(_, _) => None,
|
||||
Token::Typeof(_, _, _) => None,
|
||||
};
|
||||
match (kind, word) {
|
||||
(OperandKind::IdResultType, _) => {
|
||||
@ -663,7 +692,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
span,
|
||||
&format!("expected a literal, not a dynamic value for a {:?}", kind),
|
||||
),
|
||||
Some(Token::Typeof(_, span)) => self.tcx.sess.span_err(
|
||||
Some(Token::Typeof(_, span, _)) => self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!("expected a literal, not a type for a {:?}", kind),
|
||||
),
|
||||
@ -858,7 +887,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
|
||||
&format!("expected a literal, not a dynamic value for a {:?}", kind),
|
||||
);
|
||||
}
|
||||
Token::Typeof(_, span) => {
|
||||
Token::Typeof(_, span, _) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!("expected a literal, not a type for a {:?}", kind),
|
||||
|
@ -482,6 +482,11 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
.tcx
|
||||
.sess
|
||||
.fatal("TODO: SpirvType::Function not supported yet in create_const_alloc"),
|
||||
SpirvType::Image { .. } => self.tcx.sess.fatal("Cannot create a constant image value"),
|
||||
SpirvType::Sampler => self
|
||||
.tcx
|
||||
.sess
|
||||
.fatal("Cannot create a constant sampler value"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,6 +174,8 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> {
|
||||
SpirvType::RuntimeArray { .. } => TypeKind::Array,
|
||||
SpirvType::Pointer { .. } => TypeKind::Pointer,
|
||||
SpirvType::Function { .. } => TypeKind::Function,
|
||||
SpirvType::Image { .. } => TypeKind::Integer,
|
||||
SpirvType::Sampler => TypeKind::Integer,
|
||||
}
|
||||
}
|
||||
fn type_ptr_to(&self, ty: Self::Type) -> Self::Type {
|
||||
|
@ -3,7 +3,9 @@ use crate::builder_spirv::SpirvValue;
|
||||
use crate::codegen_cx::CodegenCx;
|
||||
use bimap::BiHashMap;
|
||||
use rspirv::dr::Operand;
|
||||
use rspirv::spirv::{Capability, Decoration, StorageClass, Word};
|
||||
use rspirv::spirv::{
|
||||
AccessQualifier, Capability, Decoration, Dim, ImageFormat, StorageClass, Word,
|
||||
};
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
@ -56,6 +58,17 @@ pub enum SpirvType {
|
||||
return_type: Word,
|
||||
arguments: Vec<Word>,
|
||||
},
|
||||
Image {
|
||||
sampled_type: Word,
|
||||
dim: Dim,
|
||||
depth: u32,
|
||||
arrayed: u32,
|
||||
multisampled: u32,
|
||||
sampled: u32,
|
||||
image_format: ImageFormat,
|
||||
access_qualifier: Option<AccessQualifier>,
|
||||
},
|
||||
Sampler,
|
||||
}
|
||||
|
||||
impl SpirvType {
|
||||
@ -183,6 +196,26 @@ impl SpirvType {
|
||||
} => cx
|
||||
.emit_global()
|
||||
.type_function(return_type, arguments.iter().cloned()),
|
||||
Self::Image {
|
||||
sampled_type,
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
} => cx.emit_global().type_image(
|
||||
sampled_type,
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
),
|
||||
Self::Sampler => cx.emit_global().type_sampler(),
|
||||
};
|
||||
cx.type_cache.def(result, self);
|
||||
result
|
||||
@ -244,6 +277,8 @@ impl SpirvType {
|
||||
Self::RuntimeArray { .. } => return None,
|
||||
Self::Pointer { .. } => cx.tcx.data_layout.pointer_size,
|
||||
Self::Function { .. } => cx.tcx.data_layout.pointer_size,
|
||||
Self::Image { .. } => Size::from_bytes(4),
|
||||
Self::Sampler => Size::from_bytes(4),
|
||||
};
|
||||
Some(result)
|
||||
}
|
||||
@ -267,6 +302,8 @@ impl SpirvType {
|
||||
Self::RuntimeArray { element } => cx.lookup_type(element).alignof(cx),
|
||||
Self::Pointer { .. } => cx.tcx.data_layout.pointer_align.abi,
|
||||
Self::Function { .. } => cx.tcx.data_layout.pointer_align.abi,
|
||||
Self::Image { .. } => Align::from_bytes(4).unwrap(),
|
||||
Self::Sampler => Align::from_bytes(4).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,6 +417,28 @@ impl fmt::Debug for SpirvTypePrinter<'_, '_> {
|
||||
.field("arguments", &args)
|
||||
.finish()
|
||||
}
|
||||
SpirvType::Image {
|
||||
sampled_type,
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
} => f
|
||||
.debug_struct("Image")
|
||||
.field("id", &self.id)
|
||||
.field("sampled_type", &self.cx.debug_type(sampled_type))
|
||||
.field("dim", &dim)
|
||||
.field("depth", &depth)
|
||||
.field("arrayed", &arrayed)
|
||||
.field("multisampled", &multisampled)
|
||||
.field("sampled", &sampled)
|
||||
.field("image_format", &image_format)
|
||||
.field("access_qualifier", &access_qualifier)
|
||||
.finish(),
|
||||
SpirvType::Sampler => f.debug_struct("Sampler").field("id", &self.id).finish(),
|
||||
};
|
||||
{
|
||||
let mut debug_stack = DEBUG_STACK.lock().unwrap();
|
||||
@ -489,6 +548,27 @@ impl SpirvTypePrinter<'_, '_> {
|
||||
f.write_str(") -> ")?;
|
||||
ty(self.cx, stack, f, return_type)
|
||||
}
|
||||
SpirvType::Image {
|
||||
sampled_type,
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
} => f
|
||||
.debug_struct("Image")
|
||||
.field("sampled_type", &self.cx.debug_type(sampled_type))
|
||||
.field("dim", &dim)
|
||||
.field("depth", &depth)
|
||||
.field("arrayed", &arrayed)
|
||||
.field("multisampled", &multisampled)
|
||||
.field("sampled", &sampled)
|
||||
.field("image_format", &image_format)
|
||||
.field("access_qualifier", &access_qualifier)
|
||||
.finish(),
|
||||
SpirvType::Sampler => f.write_str("Sampler"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::builder::libm_intrinsics;
|
||||
use crate::codegen_cx::CodegenCx;
|
||||
use rspirv::spirv::{BuiltIn, ExecutionMode, ExecutionModel, StorageClass};
|
||||
use rspirv::spirv::{
|
||||
AccessQualifier, BuiltIn, Dim, ExecutionMode, ExecutionModel, ImageFormat, StorageClass,
|
||||
};
|
||||
use rustc_ast::ast::{AttrKind, Attribute, Lit, LitIntType, LitKind, NestedMetaItem};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use std::collections::HashMap;
|
||||
@ -30,7 +32,14 @@ pub struct Symbols {
|
||||
pub spirv15: Symbol,
|
||||
descriptor_set: Symbol,
|
||||
binding: Symbol,
|
||||
really_unsafe_ignore_bitcasts: Symbol,
|
||||
image: Symbol,
|
||||
dim: Symbol,
|
||||
depth: Symbol,
|
||||
arrayed: Symbol,
|
||||
multisampled: Symbol,
|
||||
sampled: Symbol,
|
||||
image_format: Symbol,
|
||||
access_qualifier: Symbol,
|
||||
attributes: HashMap<Symbol, SpirvAttribute>,
|
||||
execution_modes: HashMap<Symbol, (ExecutionMode, ExecutionModeExtraDim)>,
|
||||
pub libm_intrinsics: HashMap<Symbol, libm_intrinsics::LibmIntrinsic>,
|
||||
@ -321,9 +330,19 @@ impl Symbols {
|
||||
let execution_models = EXECUTION_MODELS
|
||||
.iter()
|
||||
.map(|&(a, b)| (a, SpirvAttribute::Entry(b.into())));
|
||||
let custom_attributes = [
|
||||
(
|
||||
"really_unsafe_ignore_bitcasts",
|
||||
SpirvAttribute::ReallyUnsafeIgnoreBitcasts,
|
||||
),
|
||||
("sampler", SpirvAttribute::Sampler),
|
||||
]
|
||||
.iter()
|
||||
.cloned();
|
||||
let attributes_iter = builtins
|
||||
.chain(storage_classes)
|
||||
.chain(execution_models)
|
||||
.chain(custom_attributes)
|
||||
.map(|(a, b)| (Symbol::intern(a), b));
|
||||
let mut attributes = HashMap::new();
|
||||
for (a, b) in attributes_iter {
|
||||
@ -362,7 +381,14 @@ impl Symbols {
|
||||
spirv15: Symbol::intern("spirv1.5"),
|
||||
descriptor_set: Symbol::intern("descriptor_set"),
|
||||
binding: Symbol::intern("binding"),
|
||||
really_unsafe_ignore_bitcasts: Symbol::intern("really_unsafe_ignore_bitcasts"),
|
||||
image: Symbol::intern("image"),
|
||||
dim: Symbol::intern("dim"),
|
||||
depth: Symbol::intern("depth"),
|
||||
arrayed: Symbol::intern("arrayed"),
|
||||
multisampled: Symbol::intern("multisampled"),
|
||||
sampled: Symbol::intern("sampled"),
|
||||
image_format: Symbol::intern("image_format"),
|
||||
access_qualifier: Symbol::intern("access_qualifier"),
|
||||
attributes,
|
||||
execution_modes,
|
||||
libm_intrinsics,
|
||||
@ -415,6 +441,16 @@ pub enum SpirvAttribute {
|
||||
DescriptorSet(u32),
|
||||
Binding(u32),
|
||||
ReallyUnsafeIgnoreBitcasts,
|
||||
Image {
|
||||
dim: Dim,
|
||||
depth: u32,
|
||||
arrayed: u32,
|
||||
multisampled: u32,
|
||||
sampled: u32,
|
||||
image_format: ImageFormat,
|
||||
access_qualifier: Option<AccessQualifier>,
|
||||
},
|
||||
Sampler,
|
||||
}
|
||||
|
||||
// Note that we could mark the attr as used via cx.tcx.sess.mark_attr_used(attr), but unused
|
||||
@ -448,8 +484,8 @@ pub fn parse_attrs(
|
||||
Vec::new()
|
||||
};
|
||||
args.into_iter().filter_map(move |ref arg| {
|
||||
if arg.has_name(cx.sym.really_unsafe_ignore_bitcasts) {
|
||||
Some(SpirvAttribute::ReallyUnsafeIgnoreBitcasts)
|
||||
if arg.has_name(cx.sym.image) {
|
||||
parse_image(cx, arg)
|
||||
} else if arg.has_name(cx.sym.descriptor_set) {
|
||||
match parse_attr_int_value(cx, arg) {
|
||||
Some(x) => Some(SpirvAttribute::DescriptorSet(x)),
|
||||
@ -493,6 +529,136 @@ pub fn parse_attrs(
|
||||
result.collect::<Vec<_>>().into_iter()
|
||||
}
|
||||
|
||||
fn parse_image(cx: &CodegenCx<'_>, attr: &NestedMetaItem) -> Option<SpirvAttribute> {
|
||||
let args = match attr.meta_item_list() {
|
||||
Some(args) => args,
|
||||
None => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(attr.span(), "image attribute must have arguments");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if args.len() != 6 && args.len() != 7 {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(attr.span(), "image attribute must have 6 or 7 arguments");
|
||||
return None;
|
||||
}
|
||||
let check = |idx: usize, sym: Symbol| -> bool {
|
||||
if args[idx].has_name(sym) {
|
||||
false
|
||||
} else {
|
||||
cx.tcx.sess.span_err(
|
||||
args[idx].span(),
|
||||
&format!("image attribute argument {} must be {}=...", idx + 1, sym),
|
||||
);
|
||||
true
|
||||
}
|
||||
};
|
||||
if check(0, cx.sym.dim)
|
||||
| check(1, cx.sym.depth)
|
||||
| check(2, cx.sym.arrayed)
|
||||
| check(3, cx.sym.multisampled)
|
||||
| check(4, cx.sym.sampled)
|
||||
| check(5, cx.sym.image_format)
|
||||
| (args.len() == 7 && check(6, cx.sym.access_qualifier))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let arg_values = args
|
||||
.iter()
|
||||
.map(
|
||||
|arg| match arg.meta_item().and_then(|arg| arg.name_value_literal()) {
|
||||
Some(arg) => Some(arg),
|
||||
None => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(arg.span(), "image attribute must be name=value");
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
let dim = match arg_values[0].kind {
|
||||
LitKind::Str(dim, _) => match dim.with(|s| s.parse()) {
|
||||
Ok(dim) => dim,
|
||||
Err(()) => {
|
||||
cx.tcx.sess.span_err(args[0].span(), "invalid dim value");
|
||||
return None;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[0].span(), "dim value must be str");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let parse_lit = |idx: usize, name: &str| -> Option<u32> {
|
||||
match arg_values[idx].kind {
|
||||
LitKind::Int(v, _) => Some(v as u32),
|
||||
_ => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[idx].span(), &format!("{} value must be int", name));
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
let depth = parse_lit(1, "depth")?;
|
||||
let arrayed = parse_lit(2, "arrayed")?;
|
||||
let multisampled = parse_lit(3, "multisampled")?;
|
||||
let sampled = parse_lit(4, "sampled")?;
|
||||
let image_format = match arg_values[5].kind {
|
||||
LitKind::Str(dim, _) => match dim.with(|s| s.parse()) {
|
||||
Ok(dim) => dim,
|
||||
Err(()) => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[5].span(), "invalid image_format value");
|
||||
return None;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[5].span(), "image_format value must be str");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let access_qualifier = if args.len() == 7 {
|
||||
Some(match arg_values[6].kind {
|
||||
LitKind::Str(dim, _) => match dim.with(|s| s.parse()) {
|
||||
Ok(dim) => dim,
|
||||
Err(()) => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[6].span(), "invalid access_qualifier value");
|
||||
return None;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(args[6].span(), "access_qualifier value must be str");
|
||||
return None;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some(SpirvAttribute::Image {
|
||||
dim,
|
||||
depth,
|
||||
arrayed,
|
||||
multisampled,
|
||||
sampled,
|
||||
image_format,
|
||||
access_qualifier,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_attr_int_value(cx: &CodegenCx<'_>, arg: &NestedMetaItem) -> Option<u32> {
|
||||
let arg = match arg.meta_item() {
|
||||
Some(arg) => arg,
|
||||
|
@ -37,8 +37,11 @@
|
||||
nonstandard_style
|
||||
)]
|
||||
|
||||
mod textures;
|
||||
|
||||
pub use glam;
|
||||
pub use num_traits;
|
||||
pub use textures::*;
|
||||
|
||||
#[cfg(all(not(test), target_arch = "spirv"))]
|
||||
#[panic_handler]
|
||||
|
52
crates/spirv-std/src/textures.rs
Normal file
52
crates/spirv-std/src/textures.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use glam::{Vec2, Vec4};
|
||||
|
||||
#[allow(unused_attributes)]
|
||||
#[spirv(sampler)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Sampler {
|
||||
_x: u32,
|
||||
}
|
||||
|
||||
#[allow(unused_attributes)]
|
||||
#[spirv(image(
|
||||
// sampled_type is hardcoded to f32 for now
|
||||
dim = "Dim2D",
|
||||
depth = 0,
|
||||
arrayed = 0,
|
||||
multisampled = 0,
|
||||
sampled = 1,
|
||||
image_format = "Unknown"
|
||||
))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Image2d {
|
||||
_x: u32,
|
||||
}
|
||||
|
||||
impl Image2d {
|
||||
pub fn sample(&self, sampler: Sampler, coord: Vec2) -> Vec4 {
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
{
|
||||
let _ = sampler;
|
||||
let _ = coord;
|
||||
panic!("Image sampling not supported on CPU");
|
||||
}
|
||||
#[cfg(target_arch = "spirv")]
|
||||
unsafe {
|
||||
let mut result = Default::default();
|
||||
asm!(
|
||||
"%typeSampledImage = OpTypeSampledImage typeof*{1}",
|
||||
"%image = OpLoad typeof*{1} {1}",
|
||||
"%sampler = OpLoad typeof*{2} {2}",
|
||||
"%coord = OpLoad typeof*{3} {3}",
|
||||
"%sampledImage = OpSampledImage %typeSampledImage %image %sampler",
|
||||
"%result = OpImageSampleImplicitLod typeof*{0} %sampledImage %coord",
|
||||
"OpStore {0} %result",
|
||||
in(reg) &mut result,
|
||||
in(reg) self,
|
||||
in(reg) &sampler,
|
||||
in(reg) &coord
|
||||
);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user