[spv-in] default output builtins

This commit is contained in:
Dzmitry Malyshau
2021-05-03 13:47:51 -04:00
committed by Dzmitry Malyshau
parent 9fe75ed7f1
commit be00a05fa5
6 changed files with 241 additions and 109 deletions

View File

@@ -2027,6 +2027,7 @@ impl<W: Write> Writer<W> {
result.binding.as_ref(),
));
}
writeln!(self.out, "struct {} {{", stage_out_name)?;
for (name, ty, binding) in result_members {
let ty_name = TypeContext {

View File

@@ -99,6 +99,8 @@ pub enum Error {
InvalidEdgeClassification,
#[error("recursive function call %{0}")]
FunctionCallCycle(spirv::Word),
#[error("invalid array size {0:?}")]
InvalidArraySize(Handle<crate::Constant>),
#[error("invalid barrier scope %{0}")]
InvalidBarrierScope(spirv::Word),
#[error("invalid barrier memory semantics %{0}")]

View File

@@ -296,33 +296,34 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
}
}
if self.options.adjust_coordinate_space {
let position_index = members.iter().position(|member| match member.binding {
Some(crate::Binding::BuiltIn(crate::BuiltIn::Position)) => true,
_ => false,
});
if let Some(component_index) = position_index {
// The IR is Y-up, while SPIR-V is Y-down.
let old_len = function.expressions.len();
let global_expr = components[component_index];
let access_expr = function.expressions.append(crate::Expression::AccessIndex {
base: global_expr,
index: 1,
});
let load_expr = function.expressions.append(crate::Expression::Load {
pointer: access_expr,
});
let neg_expr = function.expressions.append(crate::Expression::Unary {
op: crate::UnaryOperator::Negate,
expr: load_expr,
});
function.body.push(crate::Statement::Emit(
function.expressions.range_from(old_len),
));
function.body.push(crate::Statement::Store {
pointer: access_expr,
value: neg_expr,
});
for (member_index, member) in members.iter().enumerate() {
match member.binding {
Some(crate::Binding::BuiltIn(crate::BuiltIn::Position))
if self.options.adjust_coordinate_space =>
{
let old_len = function.expressions.len();
let global_expr = components[member_index];
let access_expr =
function.expressions.append(crate::Expression::AccessIndex {
base: global_expr,
index: 1,
});
let load_expr = function.expressions.append(crate::Expression::Load {
pointer: access_expr,
});
let neg_expr = function.expressions.append(crate::Expression::Unary {
op: crate::UnaryOperator::Negate,
expr: load_expr,
});
function.body.push(crate::Statement::Emit(
function.expressions.range_from(old_len),
));
function.body.push(crate::Statement::Store {
pointer: access_expr,
value: neg_expr,
});
}
_ => {}
}
}

View File

@@ -31,6 +31,7 @@ mod error;
mod flow;
mod function;
mod image;
mod null;
use convert::*;
pub use error::Error;
@@ -3217,84 +3218,6 @@ impl<I: Iterator<Item = u32>> Parser<I> {
Ok(())
}
fn generate_null_constant(
&mut self,
constants: &mut Arena<crate::Constant>,
types: &mut Arena<crate::Type>,
ty: Handle<crate::Type>,
) -> Result<crate::ConstantInner, Error> {
fn make_scalar_inner(kind: crate::ScalarKind, width: crate::Bytes) -> crate::ConstantInner {
crate::ConstantInner::Scalar {
width,
value: match kind {
crate::ScalarKind::Uint => crate::ScalarValue::Uint(0),
crate::ScalarKind::Sint => crate::ScalarValue::Sint(0),
crate::ScalarKind::Float => crate::ScalarValue::Float(0.0),
crate::ScalarKind::Bool => crate::ScalarValue::Bool(false),
},
}
}
let inner = match types[ty].inner {
crate::TypeInner::Scalar { kind, width } => make_scalar_inner(kind, width),
crate::TypeInner::Vector { size, kind, width } => {
let mut components = Vec::with_capacity(size as usize);
for _ in 0..size as usize {
components.push(constants.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: make_scalar_inner(kind, width),
}));
}
crate::ConstantInner::Composite { ty, components }
}
crate::TypeInner::Matrix {
columns,
rows,
width,
} => {
let vector_ty = types.fetch_or_append(crate::Type {
name: None,
inner: crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
size: rows,
width,
},
});
let vector_inner = self.generate_null_constant(constants, types, vector_ty)?;
let vector_handle = constants.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: vector_inner,
});
crate::ConstantInner::Composite {
ty,
components: vec![vector_handle; columns as usize],
}
}
crate::TypeInner::Struct { ref members, .. } => {
let mut components = Vec::with_capacity(members.len());
// copy out the types to avoid borrowing `members`
let member_tys = members.iter().map(|member| member.ty).collect::<Vec<_>>();
for member_ty in member_tys {
let inner = self.generate_null_constant(constants, types, member_ty)?;
components.push(constants.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner,
}));
}
crate::ConstantInner::Composite { ty, components }
}
//TODO: arrays
ref other => {
log::warn!("null constant type {:?}", other);
return Err(Error::UnsupportedType(ty));
}
};
Ok(inner)
}
fn parse_null_constant(
&mut self,
inst: Instruction,
@@ -3307,7 +3230,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
let type_lookup = self.lookup_type.lookup(type_id)?;
let ty = type_lookup.handle;
let inner = self.generate_null_constant(&mut module.constants, &mut module.types, ty)?;
let inner = null::generate_null_constant(ty, &mut module.types, &mut module.constants)?;
self.lookup_constant.insert(
id,
@@ -3471,14 +3394,67 @@ impl<I: Iterator<Item = u32>> Parser<I> {
(inner, var)
}
ExtendedClass::Output => {
// For output interface blocks. this would be a structure.
// For output interface blocks, this would be a structure.
let binding = dec.io_binding().ok();
let init = match binding {
Some(crate::Binding::BuiltIn(built_in)) => {
match null::generate_default_built_in(
Some(built_in),
effective_ty,
&mut module.types,
&mut module.constants,
) {
Ok(handle) => Some(handle),
Err(e) => {
log::warn!("Failed to initialize output built-in: {}", e);
None
}
}
}
Some(crate::Binding::Location { .. }) => None,
None => match module.types[effective_ty].inner {
crate::TypeInner::Struct { ref members, .. } => {
// A temporary to avoid borrowing `module.types`
let pairs = members
.iter()
.map(|member| {
let built_in = match member.binding {
Some(crate::Binding::BuiltIn(built_in)) => Some(built_in),
_ => None,
};
(built_in, member.ty)
})
.collect::<Vec<_>>();
let mut components = Vec::with_capacity(members.len());
for (built_in, member_ty) in pairs {
let handle = null::generate_default_built_in(
built_in,
member_ty,
&mut module.types,
&mut module.constants,
)?;
components.push(handle);
}
Some(module.constants.append(crate::Constant {
name: None,
specialization: None,
inner: crate::ConstantInner::Composite {
ty: effective_ty,
components,
},
}))
}
_ => None,
},
};
let var = crate::GlobalVariable {
name: dec.name,
class: crate::StorageClass::Private,
binding: None,
ty: effective_ty,
init: None,
init,
storage_access: crate::StorageAccess::empty(),
};
let inner = Variable::Output(crate::FunctionResult {

149
src/front/spv/null.rs Normal file
View File

@@ -0,0 +1,149 @@
use super::Error;
use crate::arena::{Arena, Handle};
fn make_scalar_inner(kind: crate::ScalarKind, width: crate::Bytes) -> crate::ConstantInner {
crate::ConstantInner::Scalar {
width,
value: match kind {
crate::ScalarKind::Uint => crate::ScalarValue::Uint(0),
crate::ScalarKind::Sint => crate::ScalarValue::Sint(0),
crate::ScalarKind::Float => crate::ScalarValue::Float(0.0),
crate::ScalarKind::Bool => crate::ScalarValue::Bool(false),
},
}
}
pub fn generate_null_constant(
ty: Handle<crate::Type>,
type_arena: &mut Arena<crate::Type>,
constant_arena: &mut Arena<crate::Constant>,
) -> Result<crate::ConstantInner, Error> {
let inner = match type_arena[ty].inner {
crate::TypeInner::Scalar { kind, width } => make_scalar_inner(kind, width),
crate::TypeInner::Vector { size, kind, width } => {
let mut components = Vec::with_capacity(size as usize);
for _ in 0..size as usize {
components.push(constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: make_scalar_inner(kind, width),
}));
}
crate::ConstantInner::Composite { ty, components }
}
crate::TypeInner::Matrix {
columns,
rows,
width,
} => {
let vector_ty = type_arena.fetch_or_append(crate::Type {
name: None,
inner: crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
size: rows,
width,
},
});
let vector_inner = generate_null_constant(vector_ty, type_arena, constant_arena)?;
let vector_handle = constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: vector_inner,
});
crate::ConstantInner::Composite {
ty,
components: vec![vector_handle; columns as usize],
}
}
crate::TypeInner::Struct { ref members, .. } => {
let mut components = Vec::with_capacity(members.len());
// copy out the types to avoid borrowing `members`
let member_tys = members.iter().map(|member| member.ty).collect::<Vec<_>>();
for member_ty in member_tys {
let inner = generate_null_constant(member_ty, type_arena, constant_arena)?;
components.push(constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner,
}));
}
crate::ConstantInner::Composite { ty, components }
}
crate::TypeInner::Array {
base,
size: crate::ArraySize::Constant(handle),
..
} => {
let size = constant_arena[handle]
.to_array_length()
.ok_or(Error::InvalidArraySize(handle))?;
let inner = generate_null_constant(base, type_arena, constant_arena)?;
let value = constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner,
});
crate::ConstantInner::Composite {
ty,
components: vec![value; size as usize],
}
}
ref other => {
log::warn!("null constant type {:?}", other);
return Err(Error::UnsupportedType(ty));
}
};
Ok(inner)
}
/// Create a default value for an output built-in.
pub fn generate_default_built_in(
built_in: Option<crate::BuiltIn>,
ty: Handle<crate::Type>,
type_arena: &mut Arena<crate::Type>,
constant_arena: &mut Arena<crate::Constant>,
) -> Result<Handle<crate::Constant>, Error> {
let inner = match built_in {
Some(crate::BuiltIn::Position) => {
let zero = constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: crate::ConstantInner::Scalar {
value: crate::ScalarValue::Float(0.0),
width: 4,
},
});
let one = constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner: crate::ConstantInner::Scalar {
value: crate::ScalarValue::Float(1.0),
width: 4,
},
});
crate::ConstantInner::Composite {
ty,
components: vec![zero, zero, zero, one],
}
}
Some(crate::BuiltIn::PointSize) => crate::ConstantInner::Scalar {
value: crate::ScalarValue::Float(1.0),
width: 4,
},
Some(crate::BuiltIn::FragDepth) => crate::ConstantInner::Scalar {
value: crate::ScalarValue::Float(0.0),
width: 4,
},
Some(crate::BuiltIn::SampleMask) => crate::ConstantInner::Scalar {
value: crate::ScalarValue::Uint(!0),
width: 4,
},
//Note: `crate::BuiltIn::ClipDistance` is intentionally left for the default path
_ => generate_null_constant(ty, type_arena, constant_arena)?,
};
Ok(constant_arena.fetch_or_append(crate::Constant {
name: None,
specialization: None,
inner,
}))
}

View File

@@ -16,6 +16,9 @@ struct type10 {
float gl_PointSize1;
type6 gl_ClipDistance1;
};
constant metal::float4 const_type4_ = {0.0, 0.0, 0.0, 1.0};
constant type6 const_type6_ = {0.0};
constant gl_PerVertex const_gl_PerVertex = {const_type4_, 1.0, const_type6_, const_type6_};
void main1(
thread metal::float2& v_uv,
@@ -44,7 +47,7 @@ vertex main2Output main2(
) {
metal::float2 v_uv = {};
metal::float2 a_uv = {};
gl_PerVertex perVertexStruct = {};
gl_PerVertex perVertexStruct = const_gl_PerVertex;
metal::float2 a_pos = {};
const auto a_uv1 = varyings.a_uv1;
const auto a_pos1 = varyings.a_pos1;