Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Textures! #276

Merged
merged 1 commit into from
Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions crates/rustc_codegen_spirv/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Comment on lines +732 to +735
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving this as a note, my preference is encoding it as &Image where

extern {
    #[spirv(image)]
    type Image;
}

But I have no idea if this is workable, so we should leave it for future (if ever) experimentation.


With a hardcoded size, one fun way to stop rustc from letting you nest the layout in anything else (with any more data), is to make it a newtype of [u8; (1 << 47) - 1]. That's because you can't have a size of 247 (or larger), on a 64-bit target (and there's a similar limitation on 32-bit targets but it's closer to 232).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other way to think about this is we could represent them as small as 1-byte structs, but no less, so that the offset bijectively maps to the field, and generally to avoid any ZST special-casing.

The only reason to use pointer-size is the analogy with WASM, which has e.g. "function pointers" (and more generally externref), that are abstract values which can be referred to by an usize index into a global "table", if need be.
(Is that a plausible concern/direction with SPIR-V? Could we actually have a global array of e.g. Images?)

We can also avoid any Abi special-casing by using [u8; 1], IIRC, since that should create Abi::Aggregate.
(Either way we should assert the .abi is what we expect, in case it does change in the future)

// 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,
}
}
4 changes: 4 additions & 0 deletions crates/rustc_codegen_spirv/src/builder/builder_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}

Expand Down Expand Up @@ -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"),
}
}

Expand Down
61 changes: 45 additions & 16 deletions crates/rustc_codegen_spirv/src/builder/spirv_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}
}
Expand All @@ -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> {
Expand Down Expand Up @@ -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,
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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),
),
Expand Down Expand Up @@ -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),
Expand Down
5 changes: 5 additions & 0 deletions crates/rustc_codegen_spirv/src/codegen_cx/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/rustc_codegen_spirv/src/codegen_cx/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
82 changes: 81 additions & 1 deletion crates/rustc_codegen_spirv/src/spirv_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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(),
}
}
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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"),
}
}
}
Expand Down
Loading