Update IR to have entry points with inputs/outputs

This commit is contained in:
Dzmitry Malyshau
2021-03-07 00:03:05 -05:00
committed by Dzmitry Malyshau
parent 58a4e330dc
commit ebcd815250
50 changed files with 3175 additions and 2367 deletions

View File

@@ -202,16 +202,14 @@ impl<'a, 'b> FunctionCtx<'a, 'b> {
}
}
/// Helper method that retrieves the name of the argument in the current function
/// Helper method that generates a [`NameKey`](crate::proc::NameKey) for a function argument.
///
/// # Panics
/// - If the function is an entry point
/// - If the function arguments are less or equal to `arg`
/// - If `names` hasn't been filled properly
fn get_arg<'c>(&self, arg: u32, names: &'c FastHashMap<NameKey, String>) -> &'c str {
fn argument_key(&self, arg: u32) -> NameKey {
match self.func {
FunctionType::Function(handle) => &names[&NameKey::FunctionArgument(handle, arg)],
FunctionType::EntryPoint(_) => unreachable!(),
FunctionType::Function(handle) => NameKey::FunctionArgument(handle, arg),
FunctionType::EntryPoint(ep_index) => NameKey::EntryPointArgument(ep_index, arg),
}
}
}
@@ -230,6 +228,33 @@ impl IdGenerator {
}
}
/// Helper wrapper used to get a name for a varying
///
/// Varying have different naming schemes depending on their binding:
/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in)
/// - Varyings with location bindings are named `_location_X` where `X` is the location
struct VaryingName<'a> {
binding: &'a Binding,
output: bool,
}
impl fmt::Display for VaryingName<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.binding {
Binding::Location(location, _) => {
write!(
f,
"_{}_location_{}",
if self.output { "out" } else { "in" },
location,
)
}
Binding::BuiltIn(built_in) => {
write!(f, "{}", glsl_built_in(built_in))
}
}
}
}
/// Shorthand result used internally by the backend
type BackendResult = Result<(), Error>;
@@ -450,12 +475,6 @@ impl<'a, W: Write> Writer<'a, W> {
continue;
}
// Skip builtins
// TODO: Write them if they have modifiers
if let Some(crate::Binding::BuiltIn(_)) = global.binding {
continue;
}
match self.module.types[global.ty].inner {
// We treat images separately because they might require
// writing the storage format
@@ -506,6 +525,15 @@ impl<'a, W: Write> Writer<'a, W> {
_ => self.write_global(handle, global)?,
}
}
for arg in self.entry_point.function.arguments.iter() {
self.write_varying(arg.binding.as_ref(), arg.ty, false)?;
}
if let Some(ref result) = self.entry_point.function.result {
self.write_varying(result.binding.as_ref(), result.ty, true)?;
}
writeln!(self.out)?;
// Write all regular functions
for (handle, function) in self.module.functions.iter() {
// Check that the function doesn't use globals that aren't supported
@@ -516,7 +544,6 @@ impl<'a, W: Write> Writer<'a, W> {
// We also `clone` to satisfy the borrow checker
let name = self.names[&NameKey::Function(handle)].clone();
let fun_info = &self.analysis[handle];
// Write the function
@@ -719,22 +746,6 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, "writeonly ")?;
}
// Write the interpolation modifier if needed
//
// We ignore all interpolation modifiers that aren't used in input globals in fragment
// shaders or output globals in vertex shaders
//
// TODO: Should this throw an error?
if let Some(interpolation) = global.interpolation {
match (self.options.shader_stage, global.class) {
(ShaderStage::Fragment, StorageClass::Input)
| (ShaderStage::Vertex, StorageClass::Output) => {
write!(self.out, "{} ", glsl_interpolation(interpolation)?)?;
}
_ => (),
};
}
// Write the storage class
// Trailing space is important
write!(self.out, "{} ", glsl_storage_class(global.class))?;
@@ -755,31 +766,65 @@ impl<'a, W: Write> Writer<'a, W> {
///
/// Globals have different naming schemes depending on their binding:
/// - Globals without bindings use the name from the [`Namer`](crate::proc::Namer)
/// - Globals with builtin bindings get the from [`glsl_built_in`](glsl_built_in)
/// - Globals with location bindings are named `_location_X` where `X` is the location
/// - Globals with resource binding are named `_group_X_binding_Y` where `X`
/// is the group and `Y` is the binding
fn get_global_name(&self, handle: Handle<GlobalVariable>, global: &GlobalVariable) -> String {
match global.binding {
Some(Binding::Location(location)) => {
format!(
"_location_{}{}",
location,
match (self.options.shader_stage, global.class) {
(ShaderStage::Fragment, StorageClass::Input) => "_vs",
(ShaderStage::Vertex, StorageClass::Output) => "_vs",
_ => "",
}
)
Some(ref br) => {
format!("_group_{}_binding_{}", br.group, br.binding)
}
Some(Binding::Resource { group, binding }) => {
format!("_group_{}_binding_{}", group, binding)
}
Some(Binding::BuiltIn(built_in)) => glsl_built_in(built_in).to_string(),
None => self.names[&NameKey::GlobalVariable(handle)].clone(),
}
}
/// Writes the varying declaration.
fn write_varying(
&mut self,
binding: Option<&Binding>,
ty: Handle<Type>,
output: bool,
) -> Result<(), Error> {
match self.module.types[ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
for member in members {
self.write_varying(member.binding.as_ref(), member.ty, output)?;
}
}
_ => {
let binding = match binding {
Some(binding @ &Binding::Location(..)) => binding,
_ => return Ok(()),
};
// Write the interpolation modifier if needed
//
// We ignore all interpolation modifiers that aren't used in input globals in fragment
// shaders or output globals in vertex shaders
//
// TODO: Should this throw an error?
if let Binding::Location(_, Some(interp)) = *binding {
if self.options.shader_stage == ShaderStage::Fragment {
write!(self.out, "{} ", glsl_interpolation(interp))?;
}
}
// Write the storage class
write!(self.out, "{} ", if output { "out" } else { "in" })?;
// Write the type
// `write_type` adds no leading or trailing spaces
self.write_type(ty)?;
// Finally write the global name and end the global with a `;` and a newline
// Leading space is important
writeln!(self.out, " {};", VaryingName { binding, output })?;
}
}
Ok(())
}
/// Helper method used to write functions (both entry points and regular functions)
///
/// # Notes
@@ -828,8 +873,10 @@ impl<'a, W: Write> Writer<'a, W> {
// Start by writing the return type if any otherwise write void
// This is the only place where `void` is a valid type
// (though it's more a keyword than a type)
if let Some(ty) = func.return_type {
self.write_type(ty)?;
if let FunctionType::EntryPoint(_) = ctx.func {
write!(self.out, "void")?;
} else if let Some(ref result) = func.result {
self.write_type(result.ty)?;
} else {
write!(self.out, "void")?;
}
@@ -841,14 +888,18 @@ impl<'a, W: Write> Writer<'a, W> {
//
// We need access to `Self` here so we use the reference passed to the closure as an
// argument instead of capturing as that would cause a borrow checker error
self.write_slice(&func.arguments, |this, i, arg| {
let arguments = match ctx.func {
FunctionType::EntryPoint(_) => &[][..],
FunctionType::Function(_) => &func.arguments,
};
self.write_slice(arguments, |this, i, arg| {
// Write the argument type
// `write_type` adds no trailing spaces
this.write_type(arg.ty)?;
// Write the argument name
// The leading space is important
write!(this.out, " {}", ctx.get_arg(i, &this.names))?;
write!(this.out, " {}", &this.names[&ctx.argument_key(i)])?;
Ok(())
})?;
@@ -856,6 +907,44 @@ impl<'a, W: Write> Writer<'a, W> {
// Close the parentheses and open braces to start the function body
writeln!(self.out, ") {{")?;
// Compose the function arguments from globals, in case of an entry point.
if let FunctionType::EntryPoint(ep_index) = ctx.func {
for (index, arg) in func.arguments.iter().enumerate() {
write!(self.out, "{}", INDENT)?;
self.write_type(arg.ty)?;
let name = &self.names[&NameKey::EntryPointArgument(ep_index, index as u32)];
write!(self.out, " {}", name)?;
write!(self.out, " = ")?;
match self.module.types[arg.ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
self.write_type(arg.ty)?;
write!(self.out, "(")?;
for (index, member) in members.iter().enumerate() {
let varying_name = VaryingName {
binding: member.binding.as_ref().unwrap(),
output: false,
};
if index != 0 {
write!(self.out, ", ")?;
}
write!(self.out, "{}", varying_name)?;
}
writeln!(self.out, ");")?;
}
_ => {
let varying_name = VaryingName {
binding: arg.binding.as_ref().unwrap(),
output: false,
};
writeln!(self.out, "{};", varying_name)?;
}
}
}
}
// Write all function locals
// Locals are `type name (= init)?;` where the init part (including the =) are optional
//
@@ -1228,13 +1317,54 @@ impl<'a, W: Write> Writer<'a, W> {
// `return expr;`, `expr` is optional
Statement::Return { value } => {
write!(self.out, "{}", INDENT.repeat(indent))?;
write!(self.out, "return")?;
// Write the expression to be returned if needed
if let Some(expr) = value {
write!(self.out, " ")?;
self.write_expr(expr, ctx)?;
match ctx.func {
FunctionType::Function(_) => {
write!(self.out, "return")?;
// Write the expression to be returned if needed
if let Some(expr) = value {
write!(self.out, " ")?;
self.write_expr(expr, ctx)?;
}
writeln!(self.out, ";")?;
}
FunctionType::EntryPoint(ep_index) => {
if let Some(ref result) =
self.module.entry_points[ep_index as usize].function.result
{
let value = value.unwrap();
match self.module.types[result.ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
for (index, member) in members.iter().enumerate() {
let varying_name = VaryingName {
binding: member.binding.as_ref().unwrap(),
output: true,
};
write!(self.out, "{} = ", varying_name)?;
self.write_expr(value, ctx)?;
let field_name = &self.names
[&NameKey::StructMember(result.ty, index as u32)];
writeln!(self.out, ".{};", field_name)?;
write!(self.out, "{}", INDENT.repeat(indent))?;
}
}
_ => {
let name = VaryingName {
binding: result.binding.as_ref().unwrap(),
output: true,
};
write!(self.out, "{} = ", name)?;
self.write_expr(value, ctx)?;
writeln!(self.out, ";")?;
write!(self.out, "{}", INDENT.repeat(indent))?;
}
}
}
writeln!(self.out, "return;")?;
}
}
writeln!(self.out, ";")?;
}
// This is one of the places were glsl adds to the syntax of C in this case the discard
// keyword which ceases all further processing in a fragment shader, it's called OpKill
@@ -1282,8 +1412,8 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, "{}", INDENT.repeat(indent))?;
if let Some(expr) = result {
let name = format!("_expr{}", expr.index());
let ty = self.module.functions[function].return_type.unwrap();
self.write_type(ty)?;
let result = self.module.functions[function].result.as_ref().unwrap();
self.write_type(result.ty)?;
write!(self.out, " {} = ", name)?;
self.cached_expressions.insert(expr, name);
}
@@ -1362,7 +1492,7 @@ impl<'a, W: Write> Writer<'a, W> {
}
// Function arguments are written as the argument name
Expression::FunctionArgument(pos) => {
write!(self.out, "{}", ctx.get_arg(pos, &self.names))?
write!(self.out, "{}", &self.names[&ctx.argument_key(pos)])?
}
// Global variables need some special work for their name but
// `get_global_name` does the work for us
@@ -2018,12 +2148,12 @@ fn glsl_built_in(built_in: BuiltIn) -> &'static str {
match built_in {
// vertex
BuiltIn::Position => "gl_Position",
BuiltIn::BaseInstance => "gl_BaseInstance",
BuiltIn::BaseVertex => "gl_BaseVertex",
BuiltIn::BaseInstance => "uint(gl_BaseInstance)",
BuiltIn::BaseVertex => "uint(gl_BaseVertex)",
BuiltIn::ClipDistance => "gl_ClipDistance",
BuiltIn::InstanceIndex => "gl_InstanceID",
BuiltIn::InstanceIndex => "uint(gl_InstanceID)",
BuiltIn::PointSize => "gl_PointSize",
BuiltIn::VertexIndex => "gl_VertexID",
BuiltIn::VertexIndex => "uint(gl_VertexID)",
// fragment
BuiltIn::FragCoord => "gl_FragCoord",
BuiltIn::FragDepth => "gl_FragDepth",
@@ -2044,8 +2174,6 @@ fn glsl_built_in(built_in: BuiltIn) -> &'static str {
fn glsl_storage_class(class: StorageClass) -> &'static str {
match class {
StorageClass::Function => "",
StorageClass::Input => "in",
StorageClass::Output => "out",
StorageClass::Private => "",
StorageClass::Storage => "buffer",
StorageClass::Uniform => "uniform",
@@ -2056,18 +2184,14 @@ fn glsl_storage_class(class: StorageClass) -> &'static str {
}
/// Helper function that returns the string corresponding to the glsl interpolation qualifier
///
/// # Errors
/// If [`Patch`](crate::Interpolation::Patch) is passed, as it isn't supported in glsl
fn glsl_interpolation(interpolation: Interpolation) -> Result<&'static str, Error> {
Ok(match interpolation {
fn glsl_interpolation(interpolation: Interpolation) -> &'static str {
match interpolation {
Interpolation::Perspective => "smooth",
Interpolation::Linear => "noperspective",
Interpolation::Flat => "flat",
Interpolation::Centroid => "centroid",
Interpolation::Sample => "sample",
Interpolation::Patch => return Err(Error::PatchInterpolationNotSupported),
})
}
}
/// Helper function that returns the glsl dimension string of [`ImageDimension`](crate::ImageDimension)

View File

@@ -7,11 +7,20 @@ from SPIR-V's descriptor sets, we require a separate mapping provided in the opt
This mapping may have one or more resource end points for each descriptor set + index
pair.
## Outputs
## Entry points
In Metal, built-in shader outputs can not be nested into structures within
the output struct. If there is a structure in the outputs, and it contains any built-ins,
we move them up to the root output structure that we define ourselves.
Even though MSL and our IR appear to be similar in that the entry points in both can
accept arguments and return values, the restrictions are different.
MSL allows the varyings to be either in separate arguments, or inside a single
`[[stage_in]]` struct. We gather input varyings and form this artificial structure.
We also add all the (non-Private) globals into the arguments.
At the beginning of the entry point, we assign the local constants and re-compose
the arguments as they are declared on IR side, so that the rest of the logic can
pretend that MSL doesn't have all the restrictions it has.
For the result type, if it's a structure, we re-compose it with a temporary value
holding the result.
!*/
use crate::{
@@ -112,15 +121,14 @@ impl Default for Options {
}
impl Options {
fn resolve_binding(
fn resolve_local_binding(
&self,
stage: crate::ShaderStage,
var: &crate::GlobalVariable,
binding: &crate::Binding,
mode: LocationMode,
) -> Result<ResolvedBinding, Error> {
match var.binding {
Some(crate::Binding::BuiltIn(built_in)) => Ok(ResolvedBinding::BuiltIn(built_in)),
Some(crate::Binding::Location(index)) => match mode {
match *binding {
crate::Binding::BuiltIn(built_in) => Ok(ResolvedBinding::BuiltIn(built_in)),
crate::Binding::Location(index, _) => match mode {
LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(index)),
LocationMode::FragmentOutput => Ok(ResolvedBinding::Color(index)),
LocationMode::Intermediate => Ok(ResolvedBinding::User {
@@ -139,25 +147,26 @@ impl Options {
Err(Error::Validation)
}
},
Some(crate::Binding::Resource { group, binding }) => {
let source = BindSource {
stage,
group,
binding,
};
match self.binding_map.get(&source) {
Some(target) => Ok(ResolvedBinding::Resource(target.clone())),
None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
prefix: "fake",
index: 0,
}),
None => Err(Error::MissingBindTarget(source)),
}
}
None => {
log::error!("Missing binding for {:?}", var.name);
Err(Error::Validation)
}
}
}
fn resolve_global_binding(
&self,
stage: crate::ShaderStage,
res_binding: &crate::ResourceBinding,
) -> Result<ResolvedBinding, Error> {
let source = BindSource {
stage,
group: res_binding.group,
binding: res_binding.binding,
};
match self.binding_map.get(&source) {
Some(target) => Ok(ResolvedBinding::Resource(target.clone())),
None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
prefix: "fake",
index: 0,
}),
None => Err(Error::MissingBindTarget(source)),
}
}
}

View File

@@ -92,15 +92,13 @@ fn vector_size_string(size: crate::VectorSize) -> &'static str {
}
}
const OUTPUT_STRUCT_NAME: &str = "output";
const LOCATION_INPUT_STRUCT_NAME: &str = "input";
const COMPONENTS: &[char] = &['x', 'y', 'z', 'w'];
fn separate(is_last: bool) -> &'static str {
if is_last {
""
} else {
fn separate(need_separator: bool) -> &'static str {
if need_separator {
","
} else {
""
}
}
@@ -111,8 +109,7 @@ impl crate::StorageClass {
/// called from the entry point.
fn needs_pass_through(&self) -> bool {
match *self {
crate::StorageClass::Input
| crate::StorageClass::Uniform
crate::StorageClass::Uniform
| crate::StorageClass::Storage
| crate::StorageClass::Handle => true,
_ => false,
@@ -121,7 +118,7 @@ impl crate::StorageClass {
fn get_name(&self, global_use: GlobalUse) -> Option<&'static str> {
match *self {
Self::Input | Self::Output | Self::Handle => None,
Self::Handle => None,
Self::Uniform => Some("constant"),
//TODO: should still be "constant" for read-only buffers
Self::Storage => Some(if global_use.contains(GlobalUse::WRITE) {
@@ -149,7 +146,7 @@ struct ExpressionContext<'a> {
struct StatementContext<'a> {
expression: ExpressionContext<'a>,
fun_info: &'a FunctionInfo,
return_value: Option<&'a str>,
result_struct: Option<&'a str>,
}
impl<W: Write> Writer<W> {
@@ -287,30 +284,16 @@ impl<W: Write> Writer<W> {
}
}
crate::Expression::FunctionArgument(index) => {
let fun_handle = match context.origin {
FunctionOrigin::Handle(handle) => handle,
FunctionOrigin::EntryPoint(_) => unreachable!(),
let name_key = match context.origin {
FunctionOrigin::Handle(handle) => NameKey::FunctionArgument(handle, index),
FunctionOrigin::EntryPoint(ep_index) => {
NameKey::EntryPointArgument(ep_index, index)
}
};
let name = &self.names[&NameKey::FunctionArgument(fun_handle, index)];
let name = &self.names[&name_key];
write!(self.out, "{}", name)?;
}
crate::Expression::GlobalVariable(handle) => {
let var = &context.module.global_variables[handle];
match var.class {
crate::StorageClass::Output => {
if let crate::TypeInner::Struct { .. } = context.module.types[var.ty].inner
{
return Ok(());
}
write!(self.out, "{}.", OUTPUT_STRUCT_NAME)?;
}
crate::StorageClass::Input => {
if let Some(crate::Binding::Location(_)) = var.binding {
write!(self.out, "{}.", LOCATION_INPUT_STRUCT_NAME)?;
}
}
_ => {}
}
let name = &self.names[&NameKey::GlobalVariable(handle)];
write!(self.out, "{}", name)?;
}
@@ -771,17 +754,42 @@ impl<W: Write> Writer<W> {
crate::Statement::Return {
value: Some(expr_handle),
} => {
write!(self.out, "{}return ", level)?;
self.put_expression(expr_handle, &context.expression)?;
match context.result_struct {
Some(struct_name) => {
let result_ty = context.expression.function.result.as_ref().unwrap().ty;
match context.expression.module.types[result_ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
let tmp = "_tmp";
write!(self.out, "{}const auto {} = ", level, tmp)?;
self.put_expression(expr_handle, &context.expression)?;
writeln!(self.out, ";")?;
write!(self.out, "{}return {} {{", level, struct_name)?;
for index in 0..members.len() as u32 {
let comma = if index == 0 { "" } else { "," };
let name =
&self.names[&NameKey::StructMember(result_ty, index)];
write!(self.out, "{} {}.{}", comma, tmp, name)?;
}
}
_ => {
write!(self.out, "{}return {} {{ ", level, struct_name)?;
self.put_expression(expr_handle, &context.expression)?;
}
}
write!(self.out, " }}")?;
}
None => {
write!(self.out, "{}return ", level)?;
self.put_expression(expr_handle, &context.expression)?;
}
}
writeln!(self.out, ";")?;
}
crate::Statement::Return { value: None } => {
writeln!(
self.out,
"{}return {};",
level,
context.return_value.unwrap_or_default(),
)?;
writeln!(self.out, "{}return;", level)?;
}
crate::Statement::Kill => {
writeln!(self.out, "{}{}::discard_fragment();", level, NAMESPACE)?;
@@ -1107,8 +1115,8 @@ impl<W: Write> Writer<W> {
}
let fun_name = &self.names[&NameKey::Function(fun_handle)];
let result_type_name = match fun.return_type {
Some(ret_ty) => &self.names[&NameKey::Type(ret_ty)],
let result_type_name = match fun.result {
Some(ref result) => &self.names[&NameKey::Type(result.ty)],
None => "void",
};
writeln!(self.out, "{} {}(", result_type_name, fun_name)?;
@@ -1117,7 +1125,7 @@ impl<W: Write> Writer<W> {
let name = &self.names[&NameKey::FunctionArgument(fun_handle, index as u32)];
let param_type_name = &self.names[&NameKey::Type(arg.ty)];
let separator =
separate(pass_through_globals.is_empty() && index + 1 == fun.arguments.len());
separate(!pass_through_globals.is_empty() || index + 1 != fun.arguments.len());
writeln!(
self.out,
"{}{} {}{}",
@@ -1131,7 +1139,7 @@ impl<W: Write> Writer<W> {
handle,
usage: fun_info[handle],
};
let separator = separate(index + 1 == pass_through_globals.len());
let separator = separate(index + 1 != pass_through_globals.len());
write!(self.out, "{}", INDENT)?;
tyvar.try_fmt(&mut self.out)?;
writeln!(self.out, "{}", separator)?;
@@ -1157,7 +1165,7 @@ impl<W: Write> Writer<W> {
analysis,
},
fun_info,
return_value: None,
result_struct: None,
};
self.named_expressions.clear();
self.put_block(Level(1), &fun.body, &context)?;
@@ -1183,27 +1191,11 @@ impl<W: Write> Writer<W> {
},
)?;
// find the entry point(s) and inputs/outputs
let mut last_used_global = None;
for (handle, var) in module.global_variables.iter() {
match var.class {
crate::StorageClass::Input => {
if let Some(crate::Binding::Location(_)) = var.binding {
continue;
}
}
crate::StorageClass::Output => continue,
_ => {}
}
if !fun_info[handle].is_empty() {
last_used_global = Some(handle);
}
}
let fun_name = &self.names[&NameKey::EntryPoint(ep_index as _)];
info.entry_point_names.push(fun_name.clone());
let output_name = format!("{}Output", fun_name);
let location_input_name = format!("{}Input", fun_name);
let stage_out_name = format!("{}Output", fun_name);
let stage_in_name = format!("{}Input", fun_name);
let (em_str, in_mode, out_mode) = match ep.stage {
crate::ShaderStage::Vertex => (
@@ -1221,110 +1213,135 @@ impl<W: Write> Writer<W> {
}
};
let return_value = match ep.stage {
crate::ShaderStage::Vertex | crate::ShaderStage::Fragment => {
// make dedicated input/output structs
writeln!(self.out, "struct {} {{", location_input_name)?;
for (handle, var) in module.global_variables.iter() {
if var.class != crate::StorageClass::Input
|| !fun_info[handle].contains(GlobalUse::READ)
{
continue;
let mut argument_members = Vec::new();
for (arg_index, arg) in fun.arguments.iter().enumerate() {
match module.types[arg.ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
for (member_index, member) in members.iter().enumerate() {
argument_members.push((
NameKey::StructMember(arg.ty, member_index as u32),
member.ty,
member.binding.as_ref(),
))
}
if let Some(crate::Binding::BuiltIn(_)) = var.binding {
// MSL disallows built-ins in input structs
continue;
}
_ => argument_members.push((
NameKey::EntryPointArgument(ep_index as _, arg_index as u32),
arg.ty,
arg.binding.as_ref(),
)),
}
}
let varyings_member_name = self.namer.call("varyings");
let mut varying_count = 0;
if !argument_members.is_empty() {
writeln!(self.out, "struct {} {{", stage_in_name)?;
for &(ref name_key, ty, binding) in argument_members.iter() {
let binding = match binding {
Some(ref binding @ &crate::Binding::Location(..)) => binding,
_ => continue,
};
varying_count += 1;
let name = &self.names[&name_key];
let type_name = &self.names[&NameKey::Type(ty)];
let resolved = options.resolve_local_binding(binding, in_mode)?;
write!(self.out, "{}{} {}", INDENT, type_name, name)?;
resolved.try_fmt_decorated(&mut self.out, "")?;
writeln!(self.out, ";")?;
}
writeln!(self.out, "}};")?;
}
let result_member_name = self.namer.call("member");
let result_type_name = match fun.result {
Some(ref result) => {
let mut result_members = Vec::new();
if let crate::TypeInner::Struct {
block: _,
ref members,
} = module.types[result.ty].inner
{
for (member_index, member) in members.iter().enumerate() {
result_members.push((
&self.names[&NameKey::StructMember(result.ty, member_index as u32)],
member.ty,
member.binding.as_ref(),
));
}
let tyvar = TypedGlobalVariable {
module,
names: &self.names,
handle,
usage: GlobalUse::empty(),
};
write!(self.out, "{}", INDENT)?;
tyvar.try_fmt(&mut self.out)?;
let resolved = options.resolve_binding(ep.stage, var, in_mode)?;
resolved.try_fmt_decorated(&mut self.out, ";")?;
writeln!(self.out)?;
} else {
result_members.push((
&result_member_name,
result.ty,
result.binding.as_ref(),
));
}
writeln!(self.out, "struct {} {{", stage_out_name)?;
for (name, ty, binding) in result_members {
let type_name = &self.names[&NameKey::Type(ty)];
let binding = binding.ok_or(Error::Validation)?;
let resolved = options.resolve_local_binding(binding, out_mode)?;
write!(self.out, "{}{} {}", INDENT, type_name, name)?;
resolved.try_fmt_decorated(&mut self.out, "")?;
writeln!(self.out, ";")?;
}
writeln!(self.out, "}};")?;
writeln!(self.out)?;
writeln!(self.out, "struct {} {{", output_name)?;
for (handle, var) in module.global_variables.iter() {
if var.class != crate::StorageClass::Output
|| !fun_info[handle].contains(GlobalUse::WRITE)
{
continue;
}
let tyvar = TypedGlobalVariable {
module,
names: &self.names,
handle,
usage: GlobalUse::empty(),
};
write!(self.out, "{}", INDENT)?;
tyvar.try_fmt(&mut self.out)?;
let resolved = options.resolve_binding(ep.stage, var, out_mode)?;
resolved.try_fmt_decorated(&mut self.out, ";")?;
writeln!(self.out)?;
}
writeln!(self.out, "}};")?;
writeln!(self.out)?;
writeln!(self.out, "{} {} {}(", em_str, output_name, fun_name)?;
let separator = separate(last_used_global.is_none());
writeln!(
self.out,
"{}{} {} [[stage_in]]{}",
INDENT, location_input_name, LOCATION_INPUT_STRUCT_NAME, separator
)?;
Some(OUTPUT_STRUCT_NAME)
}
crate::ShaderStage::Compute => {
writeln!(self.out, "{} void {}(", em_str, fun_name)?;
None
&stage_out_name
}
None => "void",
};
writeln!(self.out, "{} {} {}(", em_str, result_type_name, fun_name)?;
let mut is_first_argument = true;
if varying_count != 0 {
writeln!(
self.out,
" {} {} [[stage_in]]",
stage_in_name, varyings_member_name
)?;
is_first_argument = false;
}
for &(ref name_key, ty, binding) in argument_members.iter() {
let binding = match binding {
Some(ref binding @ &crate::Binding::BuiltIn(..)) => binding,
_ => continue,
};
let name = &self.names[&name_key];
let type_name = &self.names[&NameKey::Type(ty)];
let resolved = options.resolve_local_binding(binding, in_mode)?;
let separator = if is_first_argument {
is_first_argument = false;
' '
} else {
','
};
write!(self.out, "{} {} {}", separator, type_name, name)?;
resolved.try_fmt_decorated(&mut self.out, "\n")?;
}
for (handle, var) in module.global_variables.iter() {
let usage = fun_info[handle];
if usage.is_empty() || var.class == crate::StorageClass::Output {
if usage.is_empty() || var.class == crate::StorageClass::Private {
continue;
}
if var.class == crate::StorageClass::Input {
if let Some(crate::Binding::Location(_)) = var.binding {
// location inputs are put into a separate struct
continue;
}
}
let loc_mode = match (ep.stage, var.class) {
(crate::ShaderStage::Vertex, crate::StorageClass::Input) => {
LocationMode::VertexInput
}
(crate::ShaderStage::Vertex, crate::StorageClass::Output)
| (crate::ShaderStage::Fragment { .. }, crate::StorageClass::Input) => {
LocationMode::Intermediate
}
(crate::ShaderStage::Fragment { .. }, crate::StorageClass::Output) => {
LocationMode::FragmentOutput
}
_ => LocationMode::Uniform,
};
let tyvar = TypedGlobalVariable {
module,
names: &self.names,
handle,
usage,
};
let separator = separate(last_used_global == Some(handle));
write!(self.out, "{}", INDENT)?;
let separator = if is_first_argument {
is_first_argument = false;
' '
} else {
','
};
write!(self.out, "{} ", separator)?;
tyvar.try_fmt(&mut self.out)?;
if var.binding.is_some() {
let resolved = options.resolve_binding(ep.stage, var, loc_mode)?;
resolved.try_fmt_decorated(&mut self.out, separator)?;
if let Some(ref binding) = var.binding {
let resolved = options.resolve_global_binding(ep.stage, binding)?;
resolved.try_fmt_decorated(&mut self.out, "")?;
}
if let Some(value) = var.init {
let value_str = &self.names[&NameKey::Constant(value)];
@@ -1332,18 +1349,72 @@ impl<W: Write> Writer<W> {
}
writeln!(self.out)?;
}
// end of the entry point argument list
writeln!(self.out, ") {{")?;
match ep.stage {
crate::ShaderStage::Vertex | crate::ShaderStage::Fragment => {
writeln!(
self.out,
"{}{} {};",
INDENT, output_name, OUTPUT_STRUCT_NAME
)?;
// Metal doesn't support private mutable variables outside of functions,
// so we put them here, just like the locals.
for (handle, var) in module.global_variables.iter() {
let usage = fun_info[handle];
if usage.is_empty() || var.class != crate::StorageClass::Private {
continue;
}
crate::ShaderStage::Compute => {}
let tyvar = TypedGlobalVariable {
module,
names: &self.names,
handle,
usage,
};
write!(self.out, "{}", INDENT)?;
tyvar.try_fmt(&mut self.out)?;
if let Some(value) = var.init {
let value_str = &self.names[&NameKey::Constant(value)];
write!(self.out, " = {}", value_str)?;
}
writeln!(self.out, ";")?;
}
// Now refactor the inputs in a way that the rest of the code expects
for (arg_index, arg) in fun.arguments.iter().enumerate() {
let arg_name =
&self.names[&NameKey::EntryPointArgument(ep_index as _, arg_index as u32)];
match module.types[arg.ty].inner {
crate::TypeInner::Struct {
block: _,
ref members,
} => {
let struct_name = &self.names[&NameKey::Type(arg.ty)];
write!(
self.out,
"{}const {} {} = {{",
INDENT, struct_name, arg_name
)?;
for member_index in 0..members.len() {
let name =
&self.names[&NameKey::StructMember(arg.ty, member_index as u32)];
let separator = if member_index != 0 { ", " } else { "" };
write!(self.out, "{}{}", INDENT, separator)?;
if let Some(crate::Binding::Location(..)) = arg.binding {
write!(self.out, "{}.", varyings_member_name)?;
}
write!(self.out, "{}", name)?;
}
}
_ => {
if let Some(crate::Binding::Location(..)) = arg.binding {
writeln!(
self.out,
"{}const auto {} = {}.{};",
INDENT, arg_name, varyings_member_name, arg_name
)?;
}
}
}
}
// Finally, declare all the local variables that we need
//TODO: we can postpone this till the relevant expressions are emitted
for (local_handle, local) in fun.local_variables.iter() {
let name = &self.names[&NameKey::EntryPointLocal(ep_index as _, local_handle)];
let ty_name = &self.names[&NameKey::Type(local.ty)];
@@ -1363,13 +1434,12 @@ impl<W: Write> Writer<W> {
analysis,
},
fun_info,
return_value,
result_struct: Some(&stage_out_name),
};
self.named_expressions.clear();
self.put_block(Level(1), &fun.body, &context)?;
writeln!(self.out, "}}")?;
let is_last = ep_index == module.entry_points.len() - 1;
if !is_last {
if ep_index + 1 != module.entry_points.len() {
writeln!(self.out)?;
}
}

View File

@@ -27,6 +27,22 @@ impl PhysicalLayout {
pub(super) fn supports_storage_buffers(&self) -> bool {
self.version >= 0x10300
}
pub(super) fn map_storage_class(&self, class: crate::StorageClass) -> spirv::StorageClass {
match class {
crate::StorageClass::Handle => spirv::StorageClass::UniformConstant,
crate::StorageClass::Function => spirv::StorageClass::Function,
crate::StorageClass::Private => spirv::StorageClass::Private,
crate::StorageClass::Storage if self.supports_storage_buffers() => {
spirv::StorageClass::StorageBuffer
}
crate::StorageClass::Storage | crate::StorageClass::Uniform => {
spirv::StorageClass::Uniform
}
crate::StorageClass::WorkGroup => spirv::StorageClass::Workgroup,
crate::StorageClass::PushConstant => spirv::StorageClass::PushConstant,
}
}
}
impl LogicalLayout {

View File

@@ -46,12 +46,19 @@ struct LocalVariable {
instruction: Instruction,
}
#[derive(Default)]
struct EntryPointContext {
argument_ids: Vec<Word>,
result_ids_typed: Vec<(Word, Word)>,
}
#[derive(Default)]
struct Function {
signature: Option<Instruction>,
parameters: Vec<Instruction>,
variables: crate::FastHashMap<Handle<crate::LocalVariable>, LocalVariable>,
blocks: Vec<Block>,
entry_point_context: Option<EntryPointContext>,
}
impl Function {
@@ -86,7 +93,7 @@ enum LocalType {
vector_size: Option<crate::VectorSize>,
kind: crate::ScalarKind,
width: crate::Bytes,
pointer_class: Option<crate::StorageClass>,
pointer_class: Option<spirv::StorageClass>,
},
Matrix {
columns: crate::VectorSize,
@@ -95,15 +102,15 @@ enum LocalType {
},
Pointer {
base: Handle<crate::Type>,
class: crate::StorageClass,
class: spirv::StorageClass,
},
SampledImage {
image_type: Handle<crate::Type>,
},
}
impl LocalType {
fn from_inner(inner: &crate::TypeInner) -> Option<Self> {
impl PhysicalLayout {
fn make_local(&self, inner: &crate::TypeInner) -> Option<LocalType> {
Some(match *inner {
crate::TypeInner::Scalar { kind, width } => LocalType::Value {
vector_size: None,
@@ -126,7 +133,10 @@ impl LocalType {
rows,
width,
},
crate::TypeInner::Pointer { base, class } => LocalType::Pointer { base, class },
crate::TypeInner::Pointer { base, class } => LocalType::Pointer {
base,
class: self.map_storage_class(class),
},
crate::TypeInner::ValuePointer {
size,
kind,
@@ -136,7 +146,7 @@ impl LocalType {
vector_size: size,
kind,
width,
pointer_class: Some(class),
pointer_class: Some(self.map_storage_class(class)),
},
_ => return None,
})
@@ -318,10 +328,12 @@ impl Writer {
Ok(*e.get())
} else {
match lookup_ty {
LookupType::Handle(handle) => match LocalType::from_inner(&arena[handle].inner) {
Some(local) => self.get_type_id(arena, LookupType::Local(local)),
None => self.write_type_declaration_arena(arena, handle),
},
LookupType::Handle(handle) => {
match self.physical_layout.make_local(&arena[handle].inner) {
Some(local) => self.get_type_id(arena, LookupType::Local(local)),
None => self.write_type_declaration_arena(arena, handle),
}
}
LookupType::Local(local_ty) => self.write_type_declaration_local(arena, local_ty),
}
}
@@ -331,36 +343,25 @@ impl Writer {
&mut self,
arena: &Arena<crate::Type>,
handle: Handle<crate::Type>,
class: crate::StorageClass,
class: spirv::StorageClass,
) -> Result<Word, Error> {
let ty_id = self.get_type_id(arena, LookupType::Handle(handle))?;
if let crate::TypeInner::Pointer { .. } = arena[handle].inner {
return Ok(ty_id);
}
Ok(
match self
.lookup_type
.entry(LookupType::Local(LocalType::Pointer {
base: handle,
class,
})) {
Entry::Occupied(e) => *e.get(),
_ => {
let storage_class = self.parse_to_spirv_storage_class(class);
let id = self.generate_id();
let instruction = Instruction::type_pointer(id, storage_class, ty_id);
instruction.to_words(&mut self.logical_layout.declarations);
self.lookup_type.insert(
LookupType::Local(LocalType::Pointer {
base: handle,
class,
}),
id,
);
id
}
},
)
let lookup_type = LookupType::Local(LocalType::Pointer {
base: handle,
class,
});
Ok(if let Some(&id) = self.lookup_type.get(&lookup_type) {
id
} else {
let id = self.generate_id();
let instruction = Instruction::type_pointer(id, class, ty_id);
instruction.to_words(&mut self.logical_layout.declarations);
self.lookup_type.insert(lookup_type, id);
id
})
}
fn create_constant(&mut self, type_id: Word, value: &[Word]) -> Word {
@@ -375,6 +376,7 @@ impl Writer {
ir_function: &crate::Function,
info: &FunctionInfo,
ir_module: &crate::Module,
mut varying_ids: Option<&mut Vec<Word>>,
) -> Result<Word, Error> {
let mut function = Function::default();
@@ -403,7 +405,7 @@ impl Writer {
.init
.map(|constant| self.lookup_constant[&constant]);
let pointer_type_id =
self.get_pointer_id(&ir_module.types, variable.ty, crate::StorageClass::Function)?;
self.get_pointer_id(&ir_module.types, variable.ty, spirv::StorageClass::Function)?;
let instruction = Instruction::variable(
pointer_type_id,
id,
@@ -415,21 +417,101 @@ impl Writer {
.insert(handle, LocalVariable { id, instruction });
}
let return_type_id = match ir_function.return_type {
Some(handle) => self.get_type_id(&ir_module.types, LookupType::Handle(handle))?,
let prelude_id = self.generate_id();
let mut prelude = Block::new(prelude_id);
let mut ep_context = EntryPointContext::default();
let mut parameter_type_ids = Vec::with_capacity(ir_function.arguments.len());
for argument in ir_function.arguments.iter() {
let class = spirv::StorageClass::Input;
let argument_type_id =
self.get_type_id(&ir_module.types, LookupType::Handle(argument.ty))?;
if let Some(ref mut list) = varying_ids {
let id = if let Some(ref binding) = argument.binding {
let name = argument.name.as_ref().map(AsRef::as_ref);
let varying_id =
self.write_varying(ir_module, class, name, argument.ty, binding)?;
list.push(varying_id);
let id = self.generate_id();
prelude
.body
.push(Instruction::load(argument_type_id, id, varying_id, None));
id
} else if let crate::TypeInner::Struct {
block: _,
ref members,
} = ir_module.types[argument.ty].inner
{
let struct_id = self.generate_id();
let mut constituent_ids = Vec::with_capacity(members.len());
for member in members {
let type_id =
self.get_type_id(&ir_module.types, LookupType::Handle(member.ty))?;
let name = member.name.as_ref().map(AsRef::as_ref);
let binding = member.binding.as_ref().unwrap();
let varying_id =
self.write_varying(ir_module, class, name, member.ty, binding)?;
list.push(varying_id);
let id = self.generate_id();
prelude
.body
.push(Instruction::load(type_id, id, varying_id, None));
constituent_ids.push(id);
}
prelude.body.push(Instruction::composite_construct(
argument_type_id,
struct_id,
&constituent_ids,
));
struct_id
} else {
unreachable!("Missing argument binding on an entry point");
};
ep_context.argument_ids.push(id);
} else {
let id = self.generate_id();
let instruction = Instruction::function_parameter(argument_type_id, id);
function.parameters.push(instruction);
parameter_type_ids.push(argument_type_id);
};
}
let return_type_id = match ir_function.result {
Some(ref result) => {
if let Some(ref mut list) = varying_ids {
let class = spirv::StorageClass::Output;
if let Some(ref binding) = result.binding {
let type_id =
self.get_type_id(&ir_module.types, LookupType::Handle(result.ty))?;
let varying_id =
self.write_varying(ir_module, class, None, result.ty, binding)?;
list.push(varying_id);
ep_context.result_ids_typed.push((varying_id, type_id));
} else if let crate::TypeInner::Struct {
block: _,
ref members,
} = ir_module.types[result.ty].inner
{
for member in members {
let type_id =
self.get_type_id(&ir_module.types, LookupType::Handle(member.ty))?;
let name = member.name.as_ref().map(AsRef::as_ref);
let binding = member.binding.as_ref().unwrap();
let varying_id =
self.write_varying(ir_module, class, name, member.ty, binding)?;
list.push(varying_id);
ep_context.result_ids_typed.push((varying_id, type_id));
}
} else {
unreachable!("Missing result binding on an entry point");
}
self.void_type
} else {
self.get_type_id(&ir_module.types, LookupType::Handle(result.ty))?
}
}
None => self.void_type,
};
let mut parameter_type_ids = Vec::with_capacity(ir_function.arguments.len());
for argument in ir_function.arguments.iter() {
let id = self.generate_id();
let parameter_type_id =
self.get_type_id(&ir_module.types, LookupType::Handle(argument.ty))?;
parameter_type_ids.push(parameter_type_id);
function
.parameters
.push(Instruction::function_parameter(parameter_type_id, id));
}
let lookup_function_type = LookupFunctionType {
return_type_id,
@@ -451,8 +533,9 @@ impl Writer {
function_type,
));
let prelude_id = self.generate_id();
let mut prelude = Block::new(prelude_id);
if varying_ids.is_some() {
function.entry_point_context = Some(ep_context);
}
// fill up the `GlobalVariable::handle_id`
for gv in self.global_variables.iter_mut() {
@@ -510,18 +593,13 @@ impl Writer {
info: &FunctionInfo,
ir_module: &crate::Module,
) -> Result<Instruction, Error> {
let function_id = self.write_function(&entry_point.function, info, ir_module)?;
let mut interface_ids = Vec::new();
for (handle, var) in ir_module.global_variables.iter() {
if info[handle].is_empty() {
continue;
}
if let crate::StorageClass::Input | crate::StorageClass::Output = var.class {
let id = self.global_variables[handle.index()].id;
interface_ids.push(id);
}
}
let function_id = self.write_function(
&entry_point.function,
info,
ir_module,
Some(&mut interface_ids),
)?;
let exec_model = match entry_point.stage {
crate::ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
@@ -573,24 +651,6 @@ impl Writer {
}
}
fn parse_to_spirv_storage_class(&self, class: crate::StorageClass) -> spirv::StorageClass {
match class {
crate::StorageClass::Handle => spirv::StorageClass::UniformConstant,
crate::StorageClass::Function => spirv::StorageClass::Function,
crate::StorageClass::Input => spirv::StorageClass::Input,
crate::StorageClass::Output => spirv::StorageClass::Output,
crate::StorageClass::Private => spirv::StorageClass::Private,
crate::StorageClass::Storage if self.physical_layout.supports_storage_buffers() => {
spirv::StorageClass::StorageBuffer
}
crate::StorageClass::Storage | crate::StorageClass::Uniform => {
spirv::StorageClass::Uniform
}
crate::StorageClass::WorkGroup => spirv::StorageClass::Workgroup,
crate::StorageClass::PushConstant => spirv::StorageClass::PushConstant,
}
}
fn write_type_declaration_local(
&mut self,
arena: &Arena<crate::Type>,
@@ -639,7 +699,7 @@ impl Writer {
}
LocalType::Pointer { base, class } => {
let type_id = self.get_type_id(arena, LookupType::Handle(base))?;
Instruction::type_pointer(id, self.parse_to_spirv_storage_class(class), type_id)
Instruction::type_pointer(id, class, type_id)
}
LocalType::Value {
vector_size,
@@ -656,7 +716,7 @@ impl Writer {
pointer_class: None,
}),
)?;
Instruction::type_pointer(id, self.parse_to_spirv_storage_class(class), type_id)
Instruction::type_pointer(id, class, type_id)
}
LocalType::SampledImage { image_type } => {
let image_type_id = self.get_type_id(arena, LookupType::Handle(image_type))?;
@@ -860,9 +920,15 @@ impl Writer {
}
crate::TypeInner::Pointer { base, class } => {
let type_id = self.get_type_id(arena, LookupType::Handle(base))?;
self.lookup_type
.insert(LookupType::Local(LocalType::Pointer { base, class }), id);
Instruction::type_pointer(id, self.parse_to_spirv_storage_class(class), type_id)
let raw_class = self.physical_layout.map_storage_class(class);
self.lookup_type.insert(
LookupType::Local(LocalType::Pointer {
base,
class: raw_class,
}),
id,
);
Instruction::type_pointer(id, raw_class, type_id)
}
crate::TypeInner::ValuePointer {
size,
@@ -870,6 +936,7 @@ impl Writer {
width,
class,
} => {
let raw_class = self.physical_layout.map_storage_class(class);
let type_id = self.get_type_id(
arena,
LookupType::Local(LocalType::Value {
@@ -884,11 +951,11 @@ impl Writer {
vector_size: size,
kind,
width,
pointer_class: Some(class),
pointer_class: Some(raw_class),
}),
id,
);
Instruction::type_pointer(id, self.parse_to_spirv_storage_class(class), type_id)
Instruction::type_pointer(id, raw_class, type_id)
}
};
@@ -979,76 +1046,45 @@ impl Writer {
Ok(())
}
fn write_global_variable(
fn write_varying(
&mut self,
ir_module: &crate::Module,
handle: Handle<crate::GlobalVariable>,
) -> Result<(Instruction, Word, spirv::StorageClass), Error> {
let global_variable = &ir_module.global_variables[handle];
class: spirv::StorageClass,
debug_name: Option<&str>,
ty: Handle<crate::Type>,
binding: &crate::Binding,
) -> Result<Word, Error> {
let id = self.generate_id();
let class = self.parse_to_spirv_storage_class(global_variable.class);
self.check(class.required_capabilities())?;
let init_word = global_variable
.init
.map(|constant| self.lookup_constant[&constant]);
let pointer_type_id =
self.get_pointer_id(&ir_module.types, global_variable.ty, global_variable.class)?;
let instruction = Instruction::variable(pointer_type_id, id, class, init_word);
let pointer_type_id = self.get_pointer_id(&ir_module.types, ty, class)?;
Instruction::variable(pointer_type_id, id, class, None)
.to_words(&mut self.logical_layout.declarations);
if self.flags.contains(WriterFlags::DEBUG) {
if let Some(ref name) = global_variable.name {
if let Some(name) = debug_name {
self.debugs.push(Instruction::name(id, name));
}
}
let access_decoration = match global_variable.storage_access {
crate::StorageAccess::LOAD => Some(spirv::Decoration::NonWritable),
crate::StorageAccess::STORE => Some(spirv::Decoration::NonReadable),
_ => None,
};
if let Some(decoration) = access_decoration {
self.annotations
.push(Instruction::decorate(id, decoration, &[]));
}
if let Some(interpolation) = global_variable.interpolation {
let decoration = match interpolation {
crate::Interpolation::Linear => Some(spirv::Decoration::NoPerspective),
crate::Interpolation::Flat => Some(spirv::Decoration::Flat),
crate::Interpolation::Patch => Some(spirv::Decoration::Patch),
crate::Interpolation::Centroid => Some(spirv::Decoration::Centroid),
crate::Interpolation::Sample => Some(spirv::Decoration::Sample),
crate::Interpolation::Perspective => None,
};
if let Some(decoration) = decoration {
self.annotations
.push(Instruction::decorate(id, decoration, &[]));
}
}
match global_variable.binding {
Some(crate::Binding::Location(location)) => {
match *binding {
crate::Binding::Location(location, interpolation) => {
self.annotations.push(Instruction::decorate(
id,
spirv::Decoration::Location,
&[location],
));
let interp_decoration = match interpolation {
Some(crate::Interpolation::Linear) => Some(spirv::Decoration::NoPerspective),
Some(crate::Interpolation::Flat) => Some(spirv::Decoration::Flat),
Some(crate::Interpolation::Centroid) => Some(spirv::Decoration::Centroid),
Some(crate::Interpolation::Sample) => Some(spirv::Decoration::Sample),
Some(crate::Interpolation::Perspective) | None => None,
};
if let Some(decoration) = interp_decoration {
self.annotations
.push(Instruction::decorate(id, decoration, &[]));
}
}
Some(crate::Binding::Resource { group, binding }) => {
self.annotations.push(Instruction::decorate(
id,
spirv::Decoration::DescriptorSet,
&[group],
));
self.annotations.push(Instruction::decorate(
id,
spirv::Decoration::Binding,
&[binding],
));
}
Some(crate::Binding::BuiltIn(built_in)) => {
crate::Binding::BuiltIn(built_in) => {
use crate::BuiltIn as Bi;
let built_in = match built_in {
Bi::BaseInstance => spirv::BuiltIn::BaseInstance,
@@ -1079,7 +1115,57 @@ impl Writer {
&[built_in as u32],
));
}
None => {}
}
Ok(id)
}
fn write_global_variable(
&mut self,
ir_module: &crate::Module,
handle: Handle<crate::GlobalVariable>,
) -> Result<(Instruction, Word, spirv::StorageClass), Error> {
let global_variable = &ir_module.global_variables[handle];
let id = self.generate_id();
let class = self
.physical_layout
.map_storage_class(global_variable.class);
self.check(class.required_capabilities())?;
let init_word = global_variable
.init
.map(|constant| self.lookup_constant[&constant]);
let pointer_type_id = self.get_pointer_id(&ir_module.types, global_variable.ty, class)?;
let instruction = Instruction::variable(pointer_type_id, id, class, init_word);
if self.flags.contains(WriterFlags::DEBUG) {
if let Some(ref name) = global_variable.name {
self.debugs.push(Instruction::name(id, name));
}
}
let access_decoration = match global_variable.storage_access {
crate::StorageAccess::LOAD => Some(spirv::Decoration::NonWritable),
crate::StorageAccess::STORE => Some(spirv::Decoration::NonReadable),
_ => None,
};
if let Some(decoration) = access_decoration {
self.annotations
.push(Instruction::decorate(id, decoration, &[]));
}
if let Some(ref res_binding) = global_variable.binding {
self.annotations.push(Instruction::decorate(
id,
spirv::Decoration::DescriptorSet,
&[res_binding.group],
));
self.annotations.push(Instruction::decorate(
id,
spirv::Decoration::Binding,
&[res_binding.binding],
));
}
// TODO Initializer is optional and not (yet) included in the IR
@@ -1212,7 +1298,7 @@ impl Writer {
) -> Result<(), Error> {
let result_lookup_ty = match self.typifier.get_handle(expr_handle) {
Ok(ty_handle) => LookupType::Handle(ty_handle),
Err(inner) => LookupType::Local(LocalType::from_inner(inner).unwrap()),
Err(inner) => LookupType::Local(self.physical_layout.make_local(inner).unwrap()),
};
let result_type_id = self.get_type_id(&ir_module.types, result_lookup_ty)?;
@@ -1598,9 +1684,10 @@ impl Writer {
.push(Instruction::load(result_type_id, id, pointer_id, None));
id
}
crate::Expression::FunctionArgument(index) => {
function.parameters[index as usize].result_id.unwrap()
}
crate::Expression::FunctionArgument(index) => match function.entry_point_context {
Some(ref context) => context.argument_ids[index as usize],
None => function.parameters[index as usize].result_id.unwrap(),
},
crate::Expression::Call(_function) => self.lookup_function_call[&expr_handle],
crate::Expression::As {
expr,
@@ -1829,7 +1916,7 @@ impl Writer {
) -> Result<(Word, spirv::StorageClass), Error> {
let result_lookup_ty = match self.typifier.get_handle(expr_handle) {
Ok(ty_handle) => LookupType::Handle(ty_handle),
Err(inner) => LookupType::Local(LocalType::from_inner(inner).unwrap()),
Err(inner) => LookupType::Local(self.physical_layout.make_local(inner).unwrap()),
};
let result_type_id = self.get_type_id(&ir_module.types, result_lookup_ty)?;
@@ -2120,8 +2207,40 @@ impl Writer {
Some(Instruction::branch(loop_context.continuing_id.unwrap()));
}
crate::Statement::Return { value: Some(value) } => {
let id = self.cached[value];
block.termination = Some(Instruction::return_value(id));
let value_id = self.cached[value];
let instruction = match function.entry_point_context {
// If this is an entry point, and we need to return anything,
// let's instead store the output variables and return `void`.
Some(ref context) => {
let result = ir_function.result.as_ref().unwrap();
if result.binding.is_none() {
for (index, &(varying_id, type_id)) in
context.result_ids_typed.iter().enumerate()
{
let member_value_id = self.generate_id();
block.body.push(Instruction::composite_extract(
type_id,
member_value_id,
value_id,
&[index as u32],
));
block.body.push(Instruction::store(
varying_id,
member_value_id,
None,
));
}
} else {
let (varying_id, _) = context.result_ids_typed[0];
block
.body
.push(Instruction::store(varying_id, value_id, None));
};
Instruction::return_void()
}
None => Instruction::return_value(value_id),
};
block.termination = Some(instruction);
}
crate::Statement::Return { value: None } => {
block.termination = Some(Instruction::return_void());
@@ -2180,8 +2299,11 @@ impl Writer {
Some(expr) => {
self.cached[expr] = id;
self.lookup_function_call.insert(expr, id);
let ty_handle =
ir_module.functions[local_function].return_type.unwrap();
let ty_handle = ir_module.functions[local_function]
.result
.as_ref()
.unwrap()
.ty;
self.get_type_id(&ir_module.types, LookupType::Handle(ty_handle))?
}
None => self.void_type,
@@ -2253,7 +2375,7 @@ impl Writer {
for (handle, ir_function) in ir_module.functions.iter() {
let info = &analysis[handle];
let id = self.write_function(ir_function, info, ir_module)?;
let id = self.write_function(ir_function, info, ir_module, None)?;
self.lookup_function.insert(handle, id);
}

View File

@@ -2,8 +2,8 @@ use super::{constants::ConstantSolver, error::ErrorKind};
use crate::{
proc::{ResolveContext, Typifier},
Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap, Function, FunctionArgument,
GlobalVariable, Handle, Interpolation, LocalVariable, Module, RelationalFunction, ShaderStage,
Statement, StorageClass, Type, UnaryOperator,
GlobalVariable, Handle, Interpolation, LocalVariable, Module, RelationalFunction,
ResourceBinding, ShaderStage, Statement, StorageClass, Type, UnaryOperator,
};
#[derive(Debug)]
@@ -224,6 +224,7 @@ impl ExpressionRule {
#[derive(Debug)]
pub enum TypeQualifier {
StorageQualifier(StorageQualifier),
ResourceBinding(ResourceBinding),
Binding(Binding),
Interpolation(Interpolation),
}
@@ -250,11 +251,14 @@ pub struct FunctionCall {
#[derive(Debug, Clone, Copy)]
pub enum StorageQualifier {
StorageClass(StorageClass),
Input,
Output,
Const,
}
#[derive(Debug, Clone)]
pub enum StructLayout {
Binding(Binding),
Resource(ResourceBinding),
PushConstant,
}

View File

@@ -8,10 +8,11 @@ pomelo! {
BOOL_WIDTH,
Arena, BinaryOperator, Binding, Block, Constant,
ConstantInner, Expression,
Function, GlobalVariable, Handle, Interpolation,
LocalVariable, ScalarValue, ScalarKind,
Function, FunctionArgument, FunctionResult,
GlobalVariable, Handle, Interpolation,
LocalVariable, ResourceBinding, ScalarValue, ScalarKind,
Statement, StorageAccess, StorageClass, StructMember,
SwitchCase, Type, TypeInner, UnaryOperator, FunctionArgument,
SwitchCase, Type, TypeInner, UnaryOperator,
};
use pp_rs::token::PreprocessorError;
}
@@ -602,14 +603,15 @@ pomelo! {
layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen {
if let Some(&(_, loc)) = l.iter().find(|&q| q.0.as_str() == "location") {
StructLayout::Binding(Binding::Location(loc))
let interpolation = None; //TODO
StructLayout::Binding(Binding::Location(loc, interpolation))
} else if let Some(&(_, binding)) = l.iter().find(|&q| q.0.as_str() == "binding") {
let group = if let Some(&(_, set)) = l.iter().find(|&q| q.0.as_str() == "set") {
set
} else {
0
};
StructLayout::Binding(Binding::Resource{ group, binding })
StructLayout::Resource(ResourceBinding{ group, binding })
} else if l.iter().any(|q| q.0.as_str() == "push_constant") {
StructLayout::PushConstant
} else {
@@ -648,6 +650,7 @@ pomelo! {
single_type_qualifier ::= layout_qualifier(l) {
match l {
StructLayout::Binding(b) => TypeQualifier::Binding(b),
StructLayout::Resource(b) => TypeQualifier::ResourceBinding(b),
StructLayout::PushConstant => TypeQualifier::StorageQualifier(StorageQualifier::StorageClass(StorageClass::PushConstant)),
}
}
@@ -663,10 +666,10 @@ pomelo! {
}
// storage_qualifier ::= InOut;
storage_qualifier ::= In {
StorageQualifier::StorageClass(StorageClass::Input)
StorageQualifier::Input
}
storage_qualifier ::= Out {
StorageQualifier::StorageClass(StorageClass::Output)
StorageQualifier::Output
}
// storage_qualifier ::= Centroid;
// storage_qualifier ::= Patch;
@@ -724,6 +727,7 @@ pomelo! {
name: Some(name.clone()),
span: None,
ty,
binding: None, //TODO
}).collect()
} else {
return Err(ErrorKind::SemanticError("Struct member can't be void".into()))
@@ -1005,7 +1009,7 @@ pomelo! {
Function {
name: Some(n.1),
arguments: vec![],
return_type: t.1,
result: t.1.map(|ty| FunctionResult { ty, binding: None }),
local_variables: Arena::<LocalVariable>::new(),
expressions: Arena::<Expression>::new(),
body: vec![],
@@ -1019,12 +1023,12 @@ pomelo! {
(h, args)
}
parameter_declarator ::= parameter_type_specifier(ty) Identifier(n) {
FunctionArgument { name: Some(n.1), ty }
FunctionArgument { name: Some(n.1), ty, binding: None }
}
// parameter_declarator ::= type_specifier(ty) Identifier(ident) array_specifier;
parameter_declaration ::= parameter_declarator;
parameter_declaration ::= parameter_type_specifier(ty) {
FunctionArgument { name: None, ty }
FunctionArgument { name: None, ty, binding: None }
}
parameter_type_specifier ::= type_specifier(t) {
@@ -1077,13 +1081,8 @@ pomelo! {
StorageQualifier::StorageClass(storage_class) => {
// TODO: Check that the storage qualifiers allow for the bindings
let binding = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Binding(ref b) = *tq { Some(b.clone()) } else { None }
if let TypeQualifier::ResourceBinding(ref b) = *tq { Some(b.clone()) } else { None }
});
let interpolation = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Interpolation(interp) = *tq { Some(interp) } else { None }
});
for (id, initializer) in d.ids_initializers {
let init = initializer.map(|init| extra.solve_constant(init.expression)).transpose()?;
@@ -1104,7 +1103,6 @@ pomelo! {
binding: binding.clone(),
ty: d.ty,
init,
interpolation,
storage_access: StorageAccess::empty(), //TODO
},
);
@@ -1113,6 +1111,37 @@ pomelo! {
}
}
}
StorageQualifier::Input => {
let mut binding = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Binding(ref b) = *tq { Some(b.clone()) } else { None }
});
let interpolation = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Interpolation(interp) = *tq { Some(interp) } else { None }
});
if let Some(Binding::Location(_, ref mut interp)) = binding {
*interp = interpolation;
}
for (id, _initializer) in d.ids_initializers {
if let Some(id) = id {
//TODO!
let expr = extra.context.expressions.append(Expression::FunctionArgument(0));
extra.context.lookup_global_var_exps.insert(id, expr);
}
}
}
StorageQualifier::Output => {
let _binding = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Binding(ref b) = *tq { Some(b.clone()) } else { None }
});
for (id, _initializer) in d.ids_initializers {
if let Some(id) = id {
//TODO!
let expr = extra.context.expressions.append(Expression::FunctionArgument(0));
extra.context.lookup_global_var_exps.insert(id, expr);
}
}
}
StorageQualifier::Const => {
for (id, initializer) in d.ids_initializers {
if let Some(init) = initializer {

View File

@@ -1,7 +1,4 @@
use crate::{
Binding, BuiltIn, Expression, GlobalVariable, Handle, ScalarKind, StorageAccess, StorageClass,
Type, TypeInner, VectorSize,
};
use crate::{Expression, Handle, Type, TypeInner, VectorSize};
use super::ast::*;
use super::error::ErrorKind;
@@ -20,7 +17,7 @@ impl Program<'_> {
}
match name {
"gl_Position" => {
let h = self.module.global_variables.append(GlobalVariable {
/*let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Output,
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
@@ -40,12 +37,17 @@ impl Program<'_> {
let exp = self
.context
.expressions
.append(Expression::GlobalVariable(h));
.append(Expression::GlobalVariable(h));*/
let exp = self
.context
.expressions
.append(Expression::FunctionArgument(0)); //TODO
self.context.lookup_global_var_exps.insert(name.into(), exp);
Ok(Some(exp))
}
"gl_VertexIndex" => {
/* TODO
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,
@@ -71,6 +73,11 @@ impl Program<'_> {
kind: ScalarKind::Sint,
convert: true,
});
*/
let expr = self
.context
.expressions
.append(Expression::FunctionArgument(0)); //TODO
self.context
.lookup_global_var_exps
.insert(name.into(), expr);
@@ -78,6 +85,7 @@ impl Program<'_> {
Ok(Some(expr))
}
"gl_InstanceIndex" => {
/* TODO
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,
@@ -103,6 +111,11 @@ impl Program<'_> {
kind: ScalarKind::Sint,
convert: true,
});
*/
let expr = self
.context
.expressions
.append(Expression::FunctionArgument(0)); //TODO
self.context
.lookup_global_var_exps
.insert(name.into(), expr);

View File

@@ -2,7 +2,7 @@ use super::error::Error;
use num_traits::cast::FromPrimitive;
use std::convert::TryInto;
pub fn map_binary_operator(word: spirv::Op) -> Result<crate::BinaryOperator, Error> {
pub(super) fn map_binary_operator(word: spirv::Op) -> Result<crate::BinaryOperator, Error> {
use crate::BinaryOperator;
use spirv::Op;
@@ -34,7 +34,7 @@ pub fn map_binary_operator(word: spirv::Op) -> Result<crate::BinaryOperator, Err
}
}
pub fn map_relational_fun(word: spirv::Op) -> Result<crate::RelationalFunction, Error> {
pub(super) fn map_relational_fun(word: spirv::Op) -> Result<crate::RelationalFunction, Error> {
use crate::RelationalFunction as Rf;
use spirv::Op;
@@ -49,7 +49,7 @@ pub fn map_relational_fun(word: spirv::Op) -> Result<crate::RelationalFunction,
}
}
pub fn map_vector_size(word: spirv::Word) -> Result<crate::VectorSize, Error> {
pub(super) fn map_vector_size(word: spirv::Word) -> Result<crate::VectorSize, Error> {
match word {
2 => Ok(crate::VectorSize::Bi),
3 => Ok(crate::VectorSize::Tri),
@@ -58,7 +58,7 @@ pub fn map_vector_size(word: spirv::Word) -> Result<crate::VectorSize, Error> {
}
}
pub fn map_image_dim(word: spirv::Word) -> Result<crate::ImageDimension, Error> {
pub(super) fn map_image_dim(word: spirv::Word) -> Result<crate::ImageDimension, Error> {
use spirv::Dim as D;
match D::from_u32(word) {
Some(D::Dim1D) => Ok(crate::ImageDimension::D1),
@@ -69,7 +69,7 @@ pub fn map_image_dim(word: spirv::Word) -> Result<crate::ImageDimension, Error>
}
}
pub fn map_image_format(word: spirv::Word) -> Result<crate::StorageFormat, Error> {
pub(super) fn map_image_format(word: spirv::Word) -> Result<crate::StorageFormat, Error> {
match spirv::ImageFormat::from_u32(word) {
Some(spirv::ImageFormat::R8) => Ok(crate::StorageFormat::R8Unorm),
Some(spirv::ImageFormat::R8Snorm) => Ok(crate::StorageFormat::R8Snorm),
@@ -107,13 +107,13 @@ pub fn map_image_format(word: spirv::Word) -> Result<crate::StorageFormat, Error
}
}
pub fn map_width(word: spirv::Word) -> Result<crate::Bytes, Error> {
pub(super) fn map_width(word: spirv::Word) -> Result<crate::Bytes, Error> {
(word >> 3) // bits to bytes
.try_into()
.map_err(|_| Error::InvalidTypeWidth(word))
}
pub fn map_builtin(word: spirv::Word, is_output: bool) -> Result<crate::BuiltIn, Error> {
pub(super) fn map_builtin(word: spirv::Word, is_output: bool) -> Result<crate::BuiltIn, Error> {
use spirv::BuiltIn as Bi;
Ok(match spirv::BuiltIn::from_u32(word) {
Some(Bi::BaseInstance) => crate::BuiltIn::BaseInstance,
@@ -145,19 +145,20 @@ pub fn map_builtin(word: spirv::Word, is_output: bool) -> Result<crate::BuiltIn,
})
}
pub fn map_storage_class(word: spirv::Word) -> Result<crate::StorageClass, Error> {
pub(super) fn map_storage_class(word: spirv::Word) -> Result<super::ExtendedClass, Error> {
use super::ExtendedClass as Ec;
use spirv::StorageClass as Sc;
Ok(match Sc::from_u32(word) {
Some(Sc::Function) => crate::StorageClass::Function,
Some(Sc::Input) => crate::StorageClass::Input,
Some(Sc::Output) => crate::StorageClass::Output,
Some(Sc::Private) => crate::StorageClass::Private,
Some(Sc::UniformConstant) => crate::StorageClass::Handle,
Some(Sc::StorageBuffer) => crate::StorageClass::Storage,
Some(Sc::Function) => Ec::Global(crate::StorageClass::Function),
Some(Sc::Input) => Ec::Input,
Some(Sc::Output) => Ec::Output,
Some(Sc::Private) => Ec::Global(crate::StorageClass::Private),
Some(Sc::UniformConstant) => Ec::Global(crate::StorageClass::Handle),
Some(Sc::StorageBuffer) => Ec::Global(crate::StorageClass::Storage),
// we expect the `Storage` case to be filtered out before calling this function.
Some(Sc::Uniform) => crate::StorageClass::Uniform,
Some(Sc::Workgroup) => crate::StorageClass::WorkGroup,
Some(Sc::PushConstant) => crate::StorageClass::PushConstant,
Some(Sc::Uniform) => Ec::Global(crate::StorageClass::Uniform),
Some(Sc::Workgroup) => Ec::Global(crate::StorageClass::WorkGroup),
Some(Sc::PushConstant) => Ec::Global(crate::StorageClass::PushConstant),
_ => return Err(Error::UnsupportedStorageClass(word)),
})
}

View File

@@ -63,10 +63,14 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
crate::Function {
name: self.future_decor.remove(&fun_id).and_then(|dec| dec.name),
arguments: Vec::with_capacity(ft.parameter_type_ids.len()),
return_type: if self.lookup_void_type == Some(result_type_id) {
result: if self.lookup_void_type == Some(result_type_id) {
None
} else {
Some(self.lookup_type.lookup(result_type_id)?.handle)
let lookup_result_ty = self.lookup_type.lookup(result_type_id)?;
Some(crate::FunctionResult {
ty: lookup_result_ty.handle,
binding: None,
})
},
local_variables: Arena::new(),
expressions: self.make_expression_storage(),
@@ -99,8 +103,12 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
return Err(Error::WrongFunctionArgumentType(type_id));
}
let ty = self.lookup_type.lookup(type_id)?.handle;
fun.arguments
.push(crate::FunctionArgument { name: None, ty });
let decor = self.future_decor.remove(&id).unwrap_or_default();
fun.arguments.push(crate::FunctionArgument {
name: decor.name,
ty,
binding: None,
});
}
Instruction { op, .. } => return Err(Error::InvalidParameter(op)),
}
@@ -157,19 +165,128 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
fun.body = flow_graph.to_naga()?;
// done
let fun_handle = module.functions.append(fun);
match self.lookup_entry_point.remove(&fun_id) {
Some(ep) => {
// create a wrapping function
let mut function = crate::Function {
name: None,
arguments: Vec::new(),
result: None,
local_variables: Arena::new(),
expressions: Arena::new(),
body: Vec::new(),
};
// 1. copy the inputs from arguments to privates
for &v_id in ep.variable_ids.iter() {
let lvar = self.lookup_variable.lookup(v_id)?;
if let super::Variable::Input(ref arg) = lvar.inner {
function.body.push(crate::Statement::Store {
pointer: function
.expressions
.append(crate::Expression::GlobalVariable(lvar.handle)),
value:
function
.expressions
.append(crate::Expression::FunctionArgument(
function.arguments.len() as u32,
)),
});
let mut arg = arg.clone();
if ep.stage == crate::ShaderStage::Fragment {
if let Some(crate::Binding::Location(_, ref mut interpolation @ None)) =
arg.binding
{
*interpolation = Some(crate::Interpolation::Perspective);
// default
}
}
function.arguments.push(arg);
}
}
// 2. call the wrapped function
function.body.push(crate::Statement::Call {
function: fun_handle,
arguments: Vec::new(),
result: None,
});
// 3. copy the outputs from privates to the result
let mut members = Vec::new();
let mut components = Vec::new();
for &v_id in ep.variable_ids.iter() {
let lvar = self.lookup_variable.lookup(v_id)?;
if let super::Variable::Output(ref result) = lvar.inner {
members.push(crate::StructMember {
name: None,
span: None,
ty: result.ty,
binding: result.binding.clone(),
});
// populate just the globals first, then do `Load` in a
// separate step, so that we can get a range.
components.push(
function
.expressions
.append(crate::Expression::GlobalVariable(lvar.handle)),
);
}
}
let old_len = function.expressions.len();
for component in components.iter_mut() {
*component = function.expressions.append(crate::Expression::Load {
pointer: *component,
});
}
match members.len() {
0 => {}
1 => {
let member = members.remove(0);
function.body.push(crate::Statement::Emit(
function.expressions.range_from(old_len),
));
function.body.push(crate::Statement::Return {
value: components.first().cloned(),
});
function.result = Some(crate::FunctionResult {
ty: member.ty,
binding: member.binding,
});
}
_ => {
let ty = module.types.append(crate::Type {
name: None,
inner: crate::TypeInner::Struct {
block: false,
members,
},
});
let result_expr = function
.expressions
.append(crate::Expression::Compose { ty, components });
function.body.push(crate::Statement::Emit(
function.expressions.range_from(old_len),
));
function.body.push(crate::Statement::Return {
value: Some(result_expr),
});
function.result = Some(crate::FunctionResult { ty, binding: None });
}
}
module.entry_points.push(crate::EntryPoint {
name: ep.name,
stage: ep.stage,
early_depth_test: ep.early_depth_test,
workgroup_size: ep.workgroup_size,
function: fun,
function,
});
}
None => {
let handle = module.functions.append(fun);
self.lookup_function.insert(fun_id, handle);
self.lookup_function.insert(fun_id, fun_handle);
}
};

View File

@@ -8,6 +8,14 @@ There map `spv::Word` into a specific IR handle, plus potentially a bit of
extra info, such as the related SPIR-V type ID.
TODO: would be nice to find ways that avoid looking up as much
## Inputs/Outputs
We create a private variable for each input/output. The relevant inputs are
populated at the start of an entry point. The outputs are saved at the end.
The function associated with an entry point is wrapped in another function,
such that we can handle any `Return` statements without problems.
!*/
#![allow(dead_code)]
@@ -203,37 +211,31 @@ impl Decoration {
}
}
fn get_binding(&self, is_output: bool) -> Option<crate::Binding> {
//TODO: validate this better
fn resource_binding(&self) -> Option<crate::ResourceBinding> {
match *self {
Decoration {
desc_set: Some(group),
desc_index: Some(binding),
..
} => Some(crate::ResourceBinding { group, binding }),
_ => None,
}
}
fn io_binding(&self, is_output: bool) -> Result<crate::Binding, Error> {
match *self {
Decoration {
built_in: Some(built_in),
location: None,
desc_set: None,
desc_index: None,
..
} => match map_builtin(built_in, is_output) {
Ok(built_in) => Some(crate::Binding::BuiltIn(built_in)),
Err(e) => {
log::warn!("{:?}", e);
None
}
},
} => map_builtin(built_in, is_output).map(crate::Binding::BuiltIn),
Decoration {
built_in: None,
location: Some(loc),
desc_set: None,
desc_index: None,
interpolation,
..
} => Some(crate::Binding::Location(loc)),
Decoration {
built_in: None,
location: None,
desc_set: Some(group),
desc_index: Some(binding),
..
} => Some(crate::Binding::Resource { group, binding }),
_ => None,
} => Ok(crate::Binding::Location(loc, interpolation)),
_ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
}
}
}
@@ -266,8 +268,16 @@ struct LookupConstant {
type_id: spirv::Word,
}
#[derive(Debug)]
enum Variable {
Global,
Input(crate::FunctionArgument),
Output(crate::FunctionResult),
}
#[derive(Debug)]
struct LookupVariable {
inner: Variable,
handle: Handle<crate::GlobalVariable>,
type_id: spirv::Word,
}
@@ -279,11 +289,17 @@ struct LookupExpression {
}
#[derive(Clone, Debug)]
pub struct Assignment {
struct Assignment {
to: Handle<crate::Expression>,
value: Handle<crate::Expression>,
}
enum ExtendedClass {
Global(crate::StorageClass),
Input,
Output,
}
#[derive(Clone, Debug, Default)]
pub struct Options {
pub flow_graph_dump_prefix: Option<PathBuf>,
@@ -429,7 +445,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
dec.interpolation = Some(crate::Interpolation::Flat);
}
spirv::Decoration::Patch => {
dec.interpolation = Some(crate::Interpolation::Patch);
// skip
}
spirv::Decoration::Centroid => {
dec.interpolation = Some(crate::Interpolation::Centroid);
@@ -1706,6 +1722,9 @@ impl<I: Iterator<Item = u32>> Parser<I> {
self.index_constants.push(handle);
}
self.dummy_functions = Arena::new();
self.lookup_function.clear();
loop {
use spirv::Op;
@@ -1764,10 +1783,8 @@ impl<I: Iterator<Item = u32>> Parser<I> {
for (_, fun) in module.functions.iter_mut() {
self.patch_function_calls(fun)?;
}
for ep in module.entry_points.iter_mut() {
self.patch_function_calls(&mut ep.function)?;
}
self.lookup_function.clear();
// Note: we aren't patching the entry point functions, because they are simply
// wrappers behind real functions, and are already resolved.
// Check all the images and samplers to have consistent comparison property.
for (handle, flags) in self.handle_sampling.drain() {
@@ -2215,7 +2232,10 @@ impl<I: Iterator<Item = u32>> Parser<I> {
{
crate::StorageClass::Storage
}
_ => map_storage_class(storage_class)?,
_ => match map_storage_class(storage_class)? {
ExtendedClass::Global(class) => class,
ExtendedClass::Input | ExtendedClass::Output => crate::StorageClass::Private,
},
};
// Don't bother with pointer stuff for `Handle` types.
@@ -2325,6 +2345,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
name: decor.name,
span: None, //TODO
ty,
binding: None,
});
}
@@ -2695,78 +2716,119 @@ impl<I: Iterator<Item = u32>> Parser<I> {
} => true,
_ => false,
};
let class = if self.lookup_storage_buffer_types.contains(&effective_ty) {
crate::StorageClass::Storage
let ext_class = if self.lookup_storage_buffer_types.contains(&effective_ty) {
ExtendedClass::Global(crate::StorageClass::Storage)
} else {
map_storage_class(storage_class)?
};
let storage_access = if is_storage {
let mut access = crate::StorageAccess::all();
if dec.flags.contains(DecorationFlags::NON_READABLE) {
access ^= crate::StorageAccess::LOAD;
let (inner, var) = match ext_class {
ExtendedClass::Global(class) => {
let storage_access = if is_storage {
let mut access = crate::StorageAccess::all();
if dec.flags.contains(DecorationFlags::NON_READABLE) {
access ^= crate::StorageAccess::LOAD;
}
if dec.flags.contains(DecorationFlags::NON_WRITABLE) {
access ^= crate::StorageAccess::STORE;
}
access
} else {
crate::StorageAccess::empty()
};
let var = crate::GlobalVariable {
binding: dec.resource_binding(),
name: dec.name,
class,
ty: effective_ty,
init,
storage_access,
};
(Variable::Global, var)
}
if dec.flags.contains(DecorationFlags::NON_WRITABLE) {
access ^= crate::StorageAccess::STORE;
ExtendedClass::Input => {
let binding = dec.io_binding(false)?;
if let crate::Binding::BuiltIn(built_in) = binding {
let needs_inner_uint = match built_in {
crate::BuiltIn::BaseInstance
| crate::BuiltIn::BaseVertex
| crate::BuiltIn::InstanceIndex
| crate::BuiltIn::SampleIndex
| crate::BuiltIn::VertexIndex
| crate::BuiltIn::LocalInvocationIndex => Some(crate::TypeInner::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
}),
crate::BuiltIn::GlobalInvocationId
| crate::BuiltIn::LocalInvocationId
| crate::BuiltIn::WorkGroupId
| crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
}),
_ => None,
};
if let (Some(inner), Some(crate::ScalarKind::Sint)) = (
needs_inner_uint,
module.types[effective_ty].inner.scalar_kind(),
) {
log::warn!("Treating {:?} as unsigned", built_in);
effective_ty = module
.types
.fetch_or_append(crate::Type { name: None, inner });
}
}
let var = crate::GlobalVariable {
name: dec.name.clone(),
class: crate::StorageClass::Private,
binding: None,
ty: effective_ty,
init: None,
storage_access: crate::StorageAccess::empty(),
};
let inner = Variable::Input(crate::FunctionArgument {
name: dec.name,
ty: effective_ty,
binding: Some(binding),
});
(inner, var)
}
ExtendedClass::Output => {
let binding = dec.io_binding(true)?;
let var = crate::GlobalVariable {
name: dec.name,
class: crate::StorageClass::Private,
binding: None,
ty: effective_ty,
init: None,
storage_access: crate::StorageAccess::empty(),
};
let inner = Variable::Output(crate::FunctionResult {
ty: effective_ty,
binding: Some(binding),
});
(inner, var)
}
access
} else {
crate::StorageAccess::empty()
};
let binding = dec.get_binding(class == crate::StorageClass::Output);
if let Some(crate::Binding::BuiltIn(built_in)) = binding {
// SPIR-V only cares about some of the built-in types being integer.
// Naga requires them to be strictly unsigned, so we have to patch it.
let needs_inner_uint = match built_in {
crate::BuiltIn::BaseInstance
| crate::BuiltIn::BaseVertex
| crate::BuiltIn::InstanceIndex
| crate::BuiltIn::SampleIndex
| crate::BuiltIn::VertexIndex
| crate::BuiltIn::LocalInvocationIndex => Some(crate::TypeInner::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
}),
crate::BuiltIn::GlobalInvocationId
| crate::BuiltIn::LocalInvocationId
| crate::BuiltIn::WorkGroupId
| crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
}),
_ => None,
};
if let (Some(inner), Some(crate::ScalarKind::Sint)) = (
needs_inner_uint,
module.types[effective_ty].inner.scalar_kind(),
) {
log::warn!("Treating {:?} as unsigned", built_in);
effective_ty = module
.types
.fetch_or_append(crate::Type { name: None, inner });
}
}
let var = crate::GlobalVariable {
name: dec.name,
class,
binding,
ty: effective_ty,
init,
interpolation: dec.interpolation,
storage_access,
};
let handle = module.global_variables.append(var);
self.lookup_variable
.insert(id, LookupVariable { handle, type_id });
if module.types[effective_ty].inner.can_comparison_sample() {
log::debug!("\t\ttracking {:?} for sampling properties", handle);
self.handle_sampling
.insert(handle, image::SamplingFlags::empty());
}
self.lookup_variable.insert(
id,
LookupVariable {
inner,
handle,
type_id,
},
);
Ok(())
}
}

View File

@@ -2,8 +2,6 @@ use super::Error;
pub fn map_storage_class(word: &str) -> Result<crate::StorageClass, Error<'_>> {
match word {
"in" => Ok(crate::StorageClass::Input),
"out" => Ok(crate::StorageClass::Output),
"private" => Ok(crate::StorageClass::Private),
"uniform" => Ok(crate::StorageClass::Uniform),
"storage" => Ok(crate::StorageClass::Storage),

View File

@@ -109,6 +109,12 @@ pub enum Error<'a> {
ZeroStride,
#[error("not a composite type: {0:?}")]
NotCompositeType(Handle<crate::Type>),
#[error("Input/output binding is not consistent: location {0:?}, built-in {1:?} and interpolation {2:?}")]
InconsistentBinding(
Option<u32>,
Option<crate::BuiltIn>,
Option<crate::Interpolation>,
),
#[error("call to local `{0}(..)` can't be resolved")]
UnknownLocalFunction(&'a str),
#[error("builtin {0:?} is not implemented")]
@@ -416,6 +422,54 @@ pub enum Scope {
type LocalFunctionCall = (Handle<crate::Function>, Vec<Handle<crate::Expression>>);
#[derive(Default)]
struct BindingParser {
location: Option<u32>,
built_in: Option<crate::BuiltIn>,
interpolation: Option<crate::Interpolation>,
}
impl BindingParser {
fn parse<'a>(&mut self, lexer: &mut Lexer<'a>, name: &'a str) -> Result<(), Error<'a>> {
match name {
"location" => {
lexer.expect(Token::Paren('('))?;
self.location = Some(lexer.next_uint_literal()?);
lexer.expect(Token::Paren(')'))?;
}
"builtin" => {
lexer.expect(Token::Paren('('))?;
let raw = lexer.next_ident()?;
self.built_in = Some(conv::map_built_in(raw)?);
lexer.expect(Token::Paren(')'))?;
}
"interpolate" => {
lexer.expect(Token::Paren('('))?;
let raw = lexer.next_ident()?;
self.interpolation = Some(conv::map_interpolation(raw)?);
lexer.expect(Token::Paren(')'))?;
}
_ => return Err(Error::UnknownDecoration(name)),
}
Ok(())
}
fn finish<'a>(self) -> Result<Option<crate::Binding>, Error<'a>> {
match (self.location, self.built_in, self.interpolation) {
(None, None, None) => Ok(None),
(Some(loc), None, interpolation) => {
Ok(Some(crate::Binding::Location(loc, interpolation)))
}
(None, Some(bi), None) => Ok(Some(crate::Binding::BuiltIn(bi))),
(location, built_in, interpolation) => Err(Error::InconsistentBinding(
location,
built_in,
interpolation,
)),
}
}
}
struct ParsedVariable<'a> {
name: &'a str,
class: Option<crate::StorageClass>,
@@ -1447,6 +1501,7 @@ impl Parser {
lexer.expect(Token::Paren('{'))?;
loop {
let mut span = 0;
let mut bind_parser = BindingParser::default();
if lexer.skip(Token::DoubleParen('[')) {
self.scopes.push(Scope::Decoration);
let mut ready = true;
@@ -1458,17 +1513,22 @@ impl Parser {
(Token::Separator(','), _) if !ready => {
ready = true;
}
(Token::Word("span"), _) if ready => {
lexer.expect(Token::Paren('('))?;
//Note: 0 is not handled
span = lexer.next_uint_literal()?;
lexer.expect(Token::Paren(')'))?;
ready = false;
}
(Token::Word("offset"), _) if ready => {
lexer.expect(Token::Paren('('))?;
let _offset = lexer.next_uint_literal()?;
lexer.expect(Token::Paren(')'))?;
(Token::Word(word), _) if ready => {
match word {
"span" => {
lexer.expect(Token::Paren('('))?;
//Note: 0 is not handled
span = lexer.next_uint_literal()?;
lexer.expect(Token::Paren(')'))?;
}
"offset" => {
// skip - only here for parsing compatibility
lexer.expect(Token::Paren('('))?;
let _offset = lexer.next_uint_literal()?;
lexer.expect(Token::Paren(')'))?;
}
_ => bind_parser.parse(lexer, word)?,
}
ready = false;
}
other => return Err(Error::Unexpected(other, "decoration separator")),
@@ -1476,6 +1536,7 @@ impl Parser {
}
self.scopes.pop();
}
let name = match lexer.next() {
(Token::Word(word), _) => word,
(Token::Paren('}'), _) => return Ok(members),
@@ -1484,10 +1545,12 @@ impl Parser {
lexer.expect(Token::Separator(':'))?;
let (ty, _access) = self.parse_type_decl(lexer, None, type_arena, const_arena)?;
lexer.expect(Token::Separator(';'))?;
members.push(crate::StructMember {
name: Some(name.to_owned()),
span: NonZeroU32::new(span),
ty,
binding: bind_parser.finish()?,
});
}
}
@@ -2259,6 +2322,31 @@ impl Parser {
Ok(block)
}
fn parse_varying_binding<'a>(
&mut self,
lexer: &mut Lexer<'a>,
) -> Result<Option<crate::Binding>, Error<'a>> {
if !lexer.skip(Token::DoubleParen('[')) {
return Ok(None);
}
let mut bind_parser = BindingParser::default();
self.scopes.push(Scope::Decoration);
loop {
let word = lexer.next_ident()?;
bind_parser.parse(lexer, word)?;
match lexer.next() {
(Token::DoubleParen(']'), _) => {
break;
}
(Token::Separator(','), _) => {}
other => return Err(Error::Unexpected(other, "decoration separator")),
}
}
self.scopes.pop();
bind_parser.finish()
}
fn parse_function_decl<'a>(
&mut self,
lexer: &mut Lexer<'a>,
@@ -2278,10 +2366,12 @@ impl Parser {
// read parameter list
let mut arguments = Vec::new();
lexer.expect(Token::Paren('('))?;
let mut ready = true;
while !lexer.skip(Token::Paren(')')) {
if !arguments.is_empty() {
lexer.expect(Token::Separator(','))?;
if !ready {
return Err(Error::Unexpected(lexer.next(), "comma"));
}
let binding = self.parse_varying_binding(lexer)?;
let (param_name, param_type, _access) =
self.parse_variable_ident_decl(lexer, &mut module.types, &mut module.constants)?;
let param_index = arguments.len() as u32;
@@ -2291,13 +2381,16 @@ impl Parser {
arguments.push(crate::FunctionArgument {
name: Some(param_name.to_string()),
ty: param_type,
binding,
});
ready = lexer.skip(Token::Separator(','));
}
// read return type
let return_type = if lexer.skip(Token::Arrow) && !lexer.skip(Token::Word("void")) {
let (handle, _access) =
let result = if lexer.skip(Token::Arrow) && !lexer.skip(Token::Word("void")) {
let binding = self.parse_varying_binding(lexer)?;
let (ty, _access) =
self.parse_type_decl(lexer, None, &mut module.types, &mut module.constants)?;
Some(handle)
Some(crate::FunctionResult { ty, binding })
} else {
None
};
@@ -2305,7 +2398,7 @@ impl Parser {
let mut fun = crate::Function {
name: Some(fun_name.to_string()),
arguments,
return_type,
result,
local_variables: Arena::new(),
expressions,
body: Vec::new(),
@@ -2345,7 +2438,6 @@ impl Parser {
// read decorations
let mut binding = None;
// Perspective is the default qualifier.
let mut interpolation = None;
let mut stage = None;
let mut is_block = false;
let mut workgroup_size = [0u32; 3];
@@ -2356,18 +2448,6 @@ impl Parser {
self.scopes.push(Scope::Decoration);
loop {
match lexer.next_ident()? {
"location" => {
lexer.expect(Token::Paren('('))?;
let loc = lexer.next_uint_literal()?;
lexer.expect(Token::Paren(')'))?;
binding = Some(crate::Binding::Location(loc));
}
"builtin" => {
lexer.expect(Token::Paren('('))?;
let builtin = conv::map_built_in(lexer.next_ident()?)?;
lexer.expect(Token::Paren(')'))?;
binding = Some(crate::Binding::BuiltIn(builtin));
}
"binding" => {
lexer.expect(Token::Paren('('))?;
bind_index = Some(lexer.next_uint_literal()?);
@@ -2381,11 +2461,6 @@ impl Parser {
bind_group = Some(lexer.next_uint_literal()?);
lexer.expect(Token::Paren(')'))?;
}
"interpolate" => {
lexer.expect(Token::Paren('('))?;
interpolation = Some(conv::map_interpolation(lexer.next_ident()?)?);
lexer.expect(Token::Paren(')'))?;
}
"stage" => {
lexer.expect(Token::Paren('('))?;
stage = Some(conv::map_shader_stage(lexer.next_ident()?)?);
@@ -2433,7 +2508,7 @@ impl Parser {
}
}
if let (Some(group), Some(index)) = (bind_group, bind_index) {
binding = Some(crate::Binding::Resource {
binding = Some(crate::ResourceBinding {
group,
binding: index,
});
@@ -2494,33 +2569,21 @@ impl Parser {
self.parse_variable_decl(lexer, &mut module.types, &mut module.constants)?;
let class = match pvar.class {
Some(c) => c,
None => match binding {
Some(crate::Binding::BuiltIn(builtin)) => match builtin {
crate::BuiltIn::GlobalInvocationId => crate::StorageClass::Input,
crate::BuiltIn::Position => crate::StorageClass::Output,
_ => return Err(Error::UnimplementedBuiltin(builtin)),
},
Some(crate::Binding::Resource { .. }) => {
match module.types[pvar.ty].inner {
crate::TypeInner::Struct { .. } if pvar.access.is_empty() => {
crate::StorageClass::Uniform
}
crate::TypeInner::Struct { .. }
| crate::TypeInner::Array { .. } => crate::StorageClass::Storage,
crate::TypeInner::Image { .. }
| crate::TypeInner::Sampler { .. } => crate::StorageClass::Handle,
ref other => {
log::error!("Resource type {:?}", other);
return Err(Error::InvalidResourceType(pvar.ty));
}
None => match module.types[pvar.ty].inner {
crate::TypeInner::Struct { .. } if binding.is_some() => {
if pvar.access.is_empty() {
crate::StorageClass::Uniform
} else {
crate::StorageClass::Storage
}
}
_ => match module.types[pvar.ty].inner {
crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => {
crate::StorageClass::Handle
}
_ => crate::StorageClass::Private,
},
crate::TypeInner::Array { .. } if binding.is_some() => {
crate::StorageClass::Storage
}
crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => {
crate::StorageClass::Handle
}
_ => crate::StorageClass::Private,
},
};
let var_handle = module.global_variables.append(crate::GlobalVariable {
@@ -2529,7 +2592,6 @@ impl Parser {
binding: binding.take(),
ty: pvar.ty,
init: pvar.init,
interpolation,
storage_access: pvar.access,
});
lookup_global_expression

View File

@@ -123,10 +123,6 @@ pub enum ShaderStage {
pub enum StorageClass {
/// Function locals.
Function,
/// Pipeline input, per invocation.
Input,
/// Pipeline output, per invocation, mutable.
Output,
/// Private data, per invocation, mutable.
Private,
/// Workgroup shared data, mutable.
@@ -228,8 +224,6 @@ pub enum Interpolation {
Linear,
/// Indicates that no interpolation will be performed.
Flat,
/// Indicates a tessellation patch.
Patch,
/// When used with multi-sampling rasterization, allow
/// a single interpolation location for an entire pixel.
Centroid,
@@ -247,6 +241,8 @@ pub struct StructMember {
pub name: Option<String>,
pub span: Option<NonZeroU32>,
pub ty: Handle<Type>,
/// For I/O structs, defines the binding.
pub binding: Option<Binding>,
}
/// The number of dimensions an image has.
@@ -452,9 +448,18 @@ pub enum Binding {
/// Built-in shader variable.
BuiltIn(BuiltIn),
/// Indexed location.
Location(u32),
/// Binding within a resource group.
Resource { group: u32, binding: u32 },
Location(u32, Option<Interpolation>),
}
/// Pipeline binding information for global resources.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
pub struct ResourceBinding {
/// The bind group index.
pub group: u32,
/// Binding number within the group.
pub binding: u32,
}
/// Variable defined at module level.
@@ -466,19 +471,12 @@ pub struct GlobalVariable {
pub name: Option<String>,
/// How this variable is to be stored.
pub class: StorageClass,
/// How this variable is to be bound.
pub binding: Option<Binding>,
/// For resources, defines the binding point.
pub binding: Option<ResourceBinding>,
/// The type of this variable.
pub ty: Handle<Type>,
/// Initial value for this variable.
pub init: Option<Handle<Constant>>,
//TODO: require fragment input interpolation once the entry point I/O
// is refactored.
/// The interpolation qualifier, if any.
/// If the this `GlobalVariable` is a vertex output
/// or fragment input, `None` corresponds to the
/// `smooth`/`perspective` interpolation qualifier.
pub interpolation: Option<Interpolation>,
/// Access bit for storage types of images and buffers.
pub storage_access: StorageAccess,
}
@@ -841,7 +839,7 @@ pub enum Statement {
}
/// A function argument.
#[derive(Debug)]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
pub struct FunctionArgument {
@@ -849,6 +847,20 @@ pub struct FunctionArgument {
pub name: Option<String>,
/// Type of the argument.
pub ty: Handle<Type>,
/// For entry points, an argument has to have a binding
/// unless it's a structure.
pub binding: Option<Binding>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
pub struct FunctionResult {
/// Type of the result.
pub ty: Handle<Type>,
/// For entry points, the result has to have a binding
/// unless it's a structure.
pub binding: Option<Binding>,
}
/// A function defined in the module.
@@ -860,8 +872,8 @@ pub struct Function {
pub name: Option<String>,
/// Information about function argument.
pub arguments: Vec<FunctionArgument>,
/// The return type of this function, if any.
pub return_type: Option<Handle<Type>>,
/// The result of this function, if any.
pub result: Option<FunctionResult>,
/// Local variables defined and used in the function.
pub local_variables: Arena<LocalVariable>,
/// Expressions used inside this function.

View File

@@ -288,6 +288,7 @@ impl FunctionInfo {
&mut self,
handle: Handle<crate::Expression>,
expression_arena: &Arena<crate::Expression>,
arguments: &[crate::FunctionArgument],
global_var_arena: &Arena<crate::GlobalVariable>,
other_functions: &[FunctionInfo],
) -> Result<(), AnalysisError> {
@@ -316,33 +317,39 @@ impl FunctionInfo {
requirement: None,
}
}
// same as `LocalVariable` - generally non-uniform
E::FunctionArgument(_) => Uniformity::non_uniform_result(handle),
// depends on the builtin and storage class
E::GlobalVariable(gh) => {
assignable_global = Some(gh);
let var = &global_var_arena[gh];
let uniform = if let Some(crate::Binding::BuiltIn(built_in)) = var.binding {
match built_in {
// depends on the builtin or interpolation
E::FunctionArgument(index) => {
let arg = &arguments[index as usize];
let uniform = match arg.binding {
Some(crate::Binding::BuiltIn(built_in)) => match built_in {
// per-polygon built-ins are uniform
crate::BuiltIn::FrontFacing
// per-work-group built-ins are uniform
| crate::BuiltIn::WorkGroupId
| crate::BuiltIn::WorkGroupSize => true,
_ => false,
}
} else {
use crate::StorageClass as Sc;
match var.class {
// only flat inputs are uniform
Sc::Input => var.interpolation == Some(crate::Interpolation::Flat),
Sc::Output | Sc::Function | Sc::Private | Sc::WorkGroup => false,
// uniform data
Sc::Uniform | Sc::PushConstant => true,
// storage data is only uniform when read-only
Sc::Handle | Sc::Storage => {
!var.storage_access.contains(crate::StorageAccess::STORE)
}
},
// only flat inputs are uniform
Some(crate::Binding::Location(_, Some(crate::Interpolation::Flat))) => true,
_ => false,
};
Uniformity {
non_uniform_result: if uniform { None } else { Some(handle) },
requirement: None,
}
}
// depends on the storage class
E::GlobalVariable(gh) => {
use crate::StorageClass as Sc;
assignable_global = Some(gh);
let var = &global_var_arena[gh];
let uniform = match var.class {
Sc::Function | Sc::Private | Sc::WorkGroup => false,
// uniform data
Sc::Uniform | Sc::PushConstant => true,
// storage data is only uniform when read-only
Sc::Handle | Sc::Storage => {
!var.storage_access.contains(crate::StorageAccess::STORE)
}
};
Uniformity {
@@ -660,7 +667,13 @@ impl Analysis {
};
for (handle, _) in fun.expressions.iter() {
info.process_expression(handle, &fun.expressions, global_var_arena, &self.functions)?;
info.process_expression(
handle,
&fun.expressions,
&fun.arguments,
global_var_arena,
&self.functions,
)?;
}
let uniformity = info.process_block(&fun.body, &self.functions, None)?;
@@ -727,18 +740,16 @@ fn uniform_control_flow() {
name: None,
init: None,
ty,
binding: Some(crate::Binding::BuiltIn(crate::BuiltIn::VertexIndex)),
class: crate::StorageClass::Input,
interpolation: None,
storage_access: crate::StorageAccess::empty(),
class: crate::StorageClass::Handle,
binding: None,
storage_access: crate::StorageAccess::STORE,
});
let uniform_global = global_var_arena.append(crate::GlobalVariable {
name: None,
init: None,
ty,
binding: Some(crate::Binding::Location(0)),
class: crate::StorageClass::Input,
interpolation: Some(crate::Interpolation::Flat),
binding: None,
class: crate::StorageClass::Uniform,
storage_access: crate::StorageAccess::empty(),
});
@@ -772,7 +783,7 @@ fn uniform_control_flow() {
expressions: vec![ExpressionInfo::default(); expressions.len()].into_boxed_slice(),
};
for (handle, _) in expressions.iter() {
info.process_expression(handle, &expressions, &global_var_arena, &[])
info.process_expression(handle, &expressions, &[], &global_var_arena, &[])
.unwrap();
}
assert_eq!(info[non_uniform_global_expr].ref_count, 1);

View File

@@ -14,6 +14,7 @@ pub enum NameKey {
FunctionLocal(Handle<crate::Function>, Handle<crate::LocalVariable>),
EntryPoint(EntryPointIndex),
EntryPointLocal(EntryPointIndex, Handle<crate::LocalVariable>),
EntryPointArgument(EntryPointIndex, u32),
}
/// This processor assigns names to all the things in a module
@@ -160,6 +161,13 @@ impl Namer {
for (ep_index, ep) in module.entry_points.iter().enumerate() {
let ep_name = self.call(&ep.name);
output.insert(NameKey::EntryPoint(ep_index as _), ep_name);
for (index, arg) in ep.function.arguments.iter().enumerate() {
let name = self.call_or(&arg.name, "param");
output.insert(
NameKey::EntryPointArgument(ep_index as _, index as u32),
name,
);
}
for (handle, var) in ep.function.local_variables.iter() {
let name = self.call_or(&var.name, "local");
output.insert(NameKey::EntryPointLocal(ep_index as _, handle), name);

View File

@@ -646,10 +646,11 @@ impl Typifier {
}
},
crate::Expression::Call(function) => {
let ty = ctx.functions[function]
.return_type
let result = ctx.functions[function]
.result
.as_ref()
.ok_or(ResolveError::FunctionReturnsVoid)?;
Resolution::Handle(ty)
Resolution::Handle(result.ty)
}
crate::Expression::ArrayLength(_) => Resolution::Value(Ti::Scalar {
kind: crate::ScalarKind::Uint,

View File

@@ -70,8 +70,7 @@ pub struct Validator {
// already have to use the typifier, so the work here is redundant in a way.
typifier: Typifier,
type_flags: Vec<TypeFlags>,
location_in_mask: BitSet,
location_out_mask: BitSet,
location_mask: BitSet,
bind_group_masks: Vec<BitSet>,
select_cases: FastHashSet<i32>,
valid_expression_list: Vec<Handle<crate::Expression>>,
@@ -112,8 +111,6 @@ pub enum GlobalVariableError {
InvalidUsage,
#[error("Type isn't compatible with the storage class")]
InvalidType,
#[error("Interpolation is not valid")]
InvalidInterpolation,
#[error("Storage access {seen:?} exceeds the allowed {allowed:?}")]
InvalidStorageAccess {
allowed: crate::StorageAccess,
@@ -126,8 +123,6 @@ pub enum GlobalVariableError {
},
#[error("Binding decoration is missing or not applicable")]
InvalidBinding,
#[error("BuiltIn type for {0:?} is invalid")]
InvalidBuiltInType(crate::BuiltIn),
}
#[derive(Clone, Debug, Error)]
@@ -136,6 +131,22 @@ pub enum LocalVariableError {
InitializerType,
}
#[derive(Clone, Debug, Error)]
pub enum VaryingError {
#[error("The type does not match the varying")]
InvalidType(Handle<crate::Type>),
#[error("Interpolation is not valid")]
InvalidInterpolation,
#[error("BuiltIn {0:?} is not available at this stage")]
InvalidBuiltInStage(crate::BuiltIn),
#[error("BuiltIn type for {0:?} is invalid")]
InvalidBuiltInType(crate::BuiltIn),
#[error("Struct member {0} is missing a binding")]
MemberMissingBinding(u32),
#[error("Multiple bindings at location {location} are present")]
BindingCollision { location: u32 },
}
#[derive(Clone, Debug, Error)]
pub enum ExpressionError {
#[error("Is invalid")]
@@ -241,16 +252,14 @@ pub enum EntryPointError {
UnexpectedWorkgroupSize,
#[error("Workgroup size is out of range")]
OutOfRangeWorkgroupSize,
#[error("Can't have arguments")]
UnexpectedArguments,
#[error("Can't have a return value")]
UnexpectedReturnValue,
#[error("Global variable {0:?} is used incorrectly as {1:?}")]
InvalidGlobalUsage(Handle<crate::GlobalVariable>, GlobalUse),
#[error("Bindings for {0:?} conflict with other global variables")]
#[error("Bindings for {0:?} conflict with other resource")]
BindingCollision(Handle<crate::GlobalVariable>),
#[error("Built-in {0:?} is not applicable to this entry point")]
InvalidBuiltIn(crate::BuiltIn),
#[error("Argument {0} varying error")]
Argument(u32, #[source] VaryingError),
#[error("Result varying error")]
Result(#[source] VaryingError),
#[error("Location {location} onterpolation of an integer has to be flat")]
InvalidIntegerInterpolation { location: u32 },
#[error(transparent)]
@@ -300,111 +309,6 @@ pub enum ValidationError {
Corrupted,
}
impl crate::GlobalVariable {
fn forbid_interpolation(&self) -> Result<(), GlobalVariableError> {
match self.interpolation {
Some(_) => Err(GlobalVariableError::InvalidInterpolation),
None => Ok(()),
}
}
fn check_resource(&self) -> Result<(), GlobalVariableError> {
match self.binding {
Some(crate::Binding::Resource { .. }) => {}
Some(crate::Binding::BuiltIn(_)) | Some(crate::Binding::Location(_)) | None => {
return Err(GlobalVariableError::InvalidBinding)
}
}
self.forbid_interpolation()
}
fn check_varying(&self, types: &Arena<crate::Type>) -> Result<(), GlobalVariableError> {
match self.binding {
Some(crate::Binding::BuiltIn(built_in)) => {
use crate::{BuiltIn as Bi, ScalarKind as Sk, TypeInner as Ti, VectorSize as Vs};
// Only validate the type here. Whether or not it's legal to access
// this builtin is up to the entry point.
let width = 4;
let expected_ty_inner = match built_in {
Bi::BaseInstance
| Bi::BaseVertex
| Bi::InstanceIndex
| Bi::VertexIndex
| Bi::SampleIndex
| Bi::SampleMaskIn
| Bi::SampleMaskOut
| Bi::LocalInvocationIndex => Some(Ti::Scalar {
kind: Sk::Uint,
width,
}),
Bi::PointSize | Bi::FragDepth => Some(Ti::Scalar {
kind: Sk::Float,
width,
}),
Bi::Position | Bi::FragCoord => Some(Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width,
}),
Bi::FrontFacing => Some(Ti::Scalar {
kind: Sk::Bool,
width: crate::BOOL_WIDTH,
}),
Bi::GlobalInvocationId
| Bi::LocalInvocationId
| Bi::WorkGroupId
| Bi::WorkGroupSize => Some(Ti::Vector {
size: Vs::Tri,
kind: Sk::Uint,
width,
}),
Bi::ClipDistance => None,
};
let ty_inner = &types[self.ty].inner;
if Some(ty_inner) != expected_ty_inner.as_ref() {
match (built_in, &types[self.ty].inner) {
(Bi::ClipDistance, &Ti::Array { base, .. }) => match types[base].inner {
Ti::Scalar {
kind: Sk::Float, ..
} => {}
ref other => {
log::warn!("Wrong array base type: {:?}", other);
return Err(GlobalVariableError::InvalidBuiltInType(built_in));
}
},
(_, other) => {
log::warn!("Wrong builtin type: {:?}", other);
return Err(GlobalVariableError::InvalidBuiltInType(built_in));
}
}
}
self.forbid_interpolation()?
}
Some(crate::Binding::Location(_)) => match types[self.ty].inner {
crate::TypeInner::Scalar { .. }
| crate::TypeInner::Vector { .. }
| crate::TypeInner::Matrix { .. } => {}
_ => return Err(GlobalVariableError::InvalidType),
},
Some(crate::Binding::Resource { .. }) => {
return Err(GlobalVariableError::InvalidBinding)
}
None => {
match types[self.ty].inner {
//TODO: check the member types
crate::TypeInner::Struct {
block: _,
members: _,
} => self.forbid_interpolation()?,
_ => return Err(GlobalVariableError::InvalidType),
}
}
}
Ok(())
}
}
fn storage_usage(access: crate::StorageAccess) -> GlobalUse {
let mut storage_usage = GlobalUse::QUERY;
if access.contains(crate::StorageAccess::LOAD) {
@@ -416,27 +320,184 @@ fn storage_usage(access: crate::StorageAccess) -> GlobalUse {
storage_usage
}
fn built_in_usage(built_in: crate::BuiltIn) -> (crate::ShaderStage, GlobalUse) {
use crate::{BuiltIn as Bi, ShaderStage as Ss};
match built_in {
Bi::BaseInstance => (Ss::Vertex, GlobalUse::READ),
Bi::BaseVertex => (Ss::Vertex, GlobalUse::READ),
Bi::ClipDistance => (Ss::Vertex, GlobalUse::WRITE),
Bi::InstanceIndex => (Ss::Vertex, GlobalUse::READ),
Bi::PointSize => (Ss::Vertex, GlobalUse::WRITE),
Bi::Position => (Ss::Vertex, GlobalUse::WRITE),
Bi::VertexIndex => (Ss::Vertex, GlobalUse::READ),
Bi::FragCoord => (Ss::Fragment, GlobalUse::READ),
Bi::FragDepth => (Ss::Fragment, GlobalUse::WRITE),
Bi::FrontFacing => (Ss::Fragment, GlobalUse::READ),
Bi::SampleIndex => (Ss::Fragment, GlobalUse::READ),
Bi::SampleMaskIn => (Ss::Fragment, GlobalUse::READ),
Bi::SampleMaskOut => (Ss::Fragment, GlobalUse::WRITE),
Bi::GlobalInvocationId => (Ss::Compute, GlobalUse::READ),
Bi::LocalInvocationId => (Ss::Compute, GlobalUse::READ),
Bi::LocalInvocationIndex => (Ss::Compute, GlobalUse::READ),
Bi::WorkGroupId => (Ss::Compute, GlobalUse::READ),
Bi::WorkGroupSize => (Ss::Compute, GlobalUse::READ),
struct VaryingContext<'a> {
ty: Handle<crate::Type>,
stage: crate::ShaderStage,
output: bool,
types: &'a Arena<crate::Type>,
location_mask: &'a mut BitSet,
}
impl VaryingContext<'_> {
fn validate_impl(&mut self, binding: &crate::Binding) -> Result<(), VaryingError> {
use crate::{
BuiltIn as Bi, ScalarKind as Sk, ShaderStage as St, TypeInner as Ti, VectorSize as Vs,
};
let ty_inner = &self.types[self.ty].inner;
match *binding {
crate::Binding::BuiltIn(built_in) => {
let width = 4;
let (visible, type_good) = match built_in {
Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => (
self.stage == St::Vertex && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
),
Bi::ClipDistance => (
self.stage == St::Vertex && self.output,
match *ty_inner {
Ti::Array { base, .. } => {
self.types[base].inner
== Ti::Scalar {
kind: Sk::Float,
width,
}
}
_ => false,
},
),
Bi::PointSize => (
self.stage == St::Vertex && self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Float,
width,
},
),
Bi::Position => (
self.stage == St::Vertex && self.output,
*ty_inner
== Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width,
},
),
Bi::FragCoord => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width,
},
),
Bi::FragDepth => (
self.stage == St::Fragment && self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Float,
width,
},
),
Bi::FrontFacing => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Bool,
width: crate::BOOL_WIDTH,
},
),
Bi::SampleIndex | Bi::SampleMaskIn => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
),
Bi::SampleMaskOut => (
self.stage == St::Fragment && self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
),
Bi::LocalInvocationIndex => (
self.stage == St::Compute && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
),
Bi::GlobalInvocationId
| Bi::LocalInvocationId
| Bi::WorkGroupId
| Bi::WorkGroupSize => (
self.stage == St::Compute && !self.output,
*ty_inner
== Ti::Vector {
size: Vs::Tri,
kind: Sk::Uint,
width,
},
),
};
if !visible {
return Err(VaryingError::InvalidBuiltInStage(built_in));
}
if !type_good {
log::warn!("Wrong builtin type: {:?}", ty_inner);
return Err(VaryingError::InvalidBuiltInType(built_in));
}
}
crate::Binding::Location(location, interpolation) => {
if !self.location_mask.insert(location as usize) {
return Err(VaryingError::BindingCollision { location });
}
let needs_interpolation =
self.stage == crate::ShaderStage::Fragment && !self.output;
if !needs_interpolation && interpolation.is_some() {
return Err(VaryingError::InvalidInterpolation);
}
match ty_inner.scalar_kind() {
Some(crate::ScalarKind::Float) => {}
Some(_)
if needs_interpolation
&& interpolation != Some(crate::Interpolation::Flat) =>
{
return Err(VaryingError::InvalidInterpolation);
}
_ => return Err(VaryingError::InvalidType(self.ty)),
}
}
}
Ok(())
}
fn validate(mut self, binding: Option<&crate::Binding>) -> Result<(), VaryingError> {
match binding {
Some(binding) => self.validate_impl(binding),
None => {
match self.types[self.ty].inner {
//TODO: check the member types
crate::TypeInner::Struct {
block: false,
ref members,
} => {
for (index, member) in members.iter().enumerate() {
self.ty = member.ty;
match member.binding {
None => {
return Err(VaryingError::MemberMissingBinding(index as u32))
}
Some(ref binding) => self.validate_impl(binding)?,
}
}
}
_ => return Err(VaryingError::InvalidType(self.ty)),
}
Ok(())
}
}
}
}
@@ -446,8 +507,7 @@ impl Validator {
Validator {
typifier: Typifier::new(),
type_flags: Vec::new(),
location_in_mask: BitSet::new(),
location_out_mask: BitSet::new(),
location_mask: BitSet::new(),
bind_group_masks: Vec::new(),
select_cases: FastHashSet::default(),
valid_expression_list: Vec::new(),
@@ -619,17 +679,9 @@ impl Validator {
types: &Arena<crate::Type>,
) -> Result<(), GlobalVariableError> {
log::debug!("var {:?}", var);
let (allowed_storage_access, required_type_flags) = match var.class {
let (allowed_storage_access, required_type_flags, is_resource) = match var.class {
crate::StorageClass::Function => return Err(GlobalVariableError::InvalidUsage),
crate::StorageClass::Input | crate::StorageClass::Output => {
var.check_varying(types)?;
(
crate::StorageAccess::empty(),
TypeFlags::DATA | TypeFlags::INTERFACE,
)
}
crate::StorageClass::Storage => {
var.check_resource()?;
match types[var.ty].inner {
crate::TypeInner::Struct { .. } => (),
_ => return Err(GlobalVariableError::InvalidType),
@@ -637,10 +689,10 @@ impl Validator {
(
crate::StorageAccess::all(),
TypeFlags::DATA | TypeFlags::HOST_SHARED,
true,
)
}
crate::StorageClass::Uniform => {
var.check_resource()?;
match types[var.ty].inner {
crate::TypeInner::Struct { .. } => (),
_ => return Err(GlobalVariableError::InvalidType),
@@ -648,10 +700,10 @@ impl Validator {
(
crate::StorageAccess::empty(),
TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::HOST_SHARED,
true,
)
}
crate::StorageClass::Handle => {
var.check_resource()?;
let access = match types[var.ty].inner {
crate::TypeInner::Image {
class: crate::ImageClass::Storage(_),
@@ -662,18 +714,15 @@ impl Validator {
}
_ => return Err(GlobalVariableError::InvalidType),
};
(access, TypeFlags::empty())
(access, TypeFlags::empty(), true)
}
crate::StorageClass::Private | crate::StorageClass::WorkGroup => {
if var.binding.is_some() {
return Err(GlobalVariableError::InvalidBinding);
}
var.forbid_interpolation()?;
(crate::StorageAccess::empty(), TypeFlags::DATA)
(crate::StorageAccess::empty(), TypeFlags::DATA, false)
}
crate::StorageClass::PushConstant => (
crate::StorageAccess::LOAD,
TypeFlags::DATA | TypeFlags::HOST_SHARED,
false,
),
};
@@ -692,6 +741,10 @@ impl Validator {
});
}
if is_resource != var.binding.is_some() {
return Err(GlobalVariableError::InvalidBinding);
}
Ok(())
}
@@ -765,7 +818,7 @@ impl Validator {
.map(|expr| self.resolve_type_impl(expr, context.types))
.transpose()
.map_err(CallError::ResultValue)?;
let expected_ty = fun.return_type.map(|ty| &context.types[ty].inner);
let expected_ty = fun.result.as_ref().map(|fr| &context.types[fr.ty].inner);
if result_ty != expected_ty {
log::error!(
"Called function returns {:?} where {:?} is expected",
@@ -773,7 +826,7 @@ impl Validator {
expected_ty
);
return Err(CallError::ResultType {
required: fun.return_type,
required: fun.result.as_ref().map(|fr| fr.ty),
seen_expression: result,
});
}
@@ -1054,7 +1107,7 @@ impl Validator {
expressions: &fun.expressions,
types: &module.types,
functions: &module.functions,
return_type: fun.return_type,
return_type: fun.result.as_ref().map(|fr| fr.ty),
},
)
}
@@ -1080,73 +1133,43 @@ impl Validator {
return Err(EntryPointError::UnexpectedWorkgroupSize);
}
self.location_in_mask.clear();
self.location_out_mask.clear();
self.location_mask.clear();
for (index, fa) in ep.function.arguments.iter().enumerate() {
let ctx = VaryingContext {
ty: fa.ty,
stage: ep.stage,
output: false,
types: &module.types,
location_mask: &mut self.location_mask,
};
ctx.validate(fa.binding.as_ref())
.map_err(|e| EntryPointError::Argument(index as u32, e))?;
}
self.location_mask.clear();
if let Some(ref fr) = ep.function.result {
let ctx = VaryingContext {
ty: fr.ty,
stage: ep.stage,
output: true,
types: &module.types,
location_mask: &mut self.location_mask,
};
ctx.validate(fr.binding.as_ref())
.map_err(EntryPointError::Result)?;
}
for bg in self.bind_group_masks.iter_mut() {
bg.clear();
}
for (var_handle, var) in module.global_variables.iter() {
let usage = info[var_handle];
if usage.is_empty() {
continue;
}
if let Some(crate::Binding::Location(location)) = var.binding {
if ep.stage == crate::ShaderStage::Fragment
&& var.class == crate::StorageClass::Input
{
match module.types[var.ty].inner.scalar_kind() {
Some(crate::ScalarKind::Float) => {}
Some(_) if var.interpolation != Some(crate::Interpolation::Flat) => {
return Err(EntryPointError::InvalidIntegerInterpolation { location });
}
_ => {}
}
}
}
let allowed_usage = match var.class {
crate::StorageClass::Function => unreachable!(),
crate::StorageClass::Input => {
match var.binding {
Some(crate::Binding::BuiltIn(built_in)) => {
let (allowed_stage, allowed_usage) = built_in_usage(built_in);
if allowed_stage != ep.stage || !allowed_usage.contains(GlobalUse::READ)
{
return Err(EntryPointError::InvalidBuiltIn(built_in));
}
}
Some(crate::Binding::Location(loc)) => {
if !self.location_in_mask.insert(loc as usize) {
return Err(EntryPointError::BindingCollision(var_handle));
}
}
Some(crate::Binding::Resource { .. }) => unreachable!(),
None => (),
}
GlobalUse::READ
}
crate::StorageClass::Output => {
match var.binding {
Some(crate::Binding::BuiltIn(built_in)) => {
let (allowed_stage, allowed_usage) = built_in_usage(built_in);
if allowed_stage != ep.stage
|| !allowed_usage.contains(GlobalUse::WRITE)
{
return Err(EntryPointError::InvalidBuiltIn(built_in));
}
}
Some(crate::Binding::Location(loc)) => {
if !self.location_out_mask.insert(loc as usize) {
return Err(EntryPointError::BindingCollision(var_handle));
}
}
Some(crate::Binding::Resource { .. }) => unreachable!(),
None => (),
}
GlobalUse::READ | GlobalUse::WRITE
}
crate::StorageClass::Uniform => GlobalUse::READ | GlobalUse::QUERY,
crate::StorageClass::Storage => storage_usage(var.storage_access),
crate::StorageClass::Handle => match module.types[var.ty].inner {
@@ -1169,23 +1192,16 @@ impl Validator {
return Err(EntryPointError::InvalidGlobalUsage(var_handle, usage));
}
if let Some(crate::Binding::Resource { group, binding }) = var.binding {
while self.bind_group_masks.len() <= group as usize {
if let Some(ref bind) = var.binding {
while self.bind_group_masks.len() <= bind.group as usize {
self.bind_group_masks.push(BitSet::new());
}
if !self.bind_group_masks[group as usize].insert(binding as usize) {
if !self.bind_group_masks[bind.group as usize].insert(bind.binding as usize) {
return Err(EntryPointError::BindingCollision(var_handle));
}
}
}
if !ep.function.arguments.is_empty() {
return Err(EntryPointError::UnexpectedArguments);
}
if ep.function.return_type.is_some() {
return Err(EntryPointError::UnexpectedReturnValue);
}
self.validate_function(&ep.function, info, module)?;
Ok(())
}

View File

@@ -30,13 +30,13 @@ fn function_without_identifier() {
#[test]
fn invalid_integer() {
err!(
"[[location(1.)]] var<in> pos : vec2<f32>;",
"fn foo([location(1.)] x: i32) {}",
@r###"
error: expected integer literal, found `1.`
┌─ wgsl:1:12
error: expected identifier, found '['
┌─ wgsl:1:8
1 │ [[location(1.)]] var<in> pos : vec2<f32>;
^^ expected integer
1 │ fn foo([location(1.)] x: i32) {}
│ ^ expected identifier
"###
);

View File

@@ -26,12 +26,10 @@ struct Particles {
[[group(0), binding(1)]] var<storage> particlesSrc : [[access(read)]] Particles;
[[group(0), binding(2)]] var<storage> particlesDst : [[access(read_write)]] Particles;
[[builtin(global_invocation_id)]] var gl_GlobalInvocationID : vec3<u32>;
// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
[[stage(compute), workgroup_size(64)]]
fn main() {
const index : u32 = gl_GlobalInvocationID.x;
fn main([[builtin(global_invocation_id)]] global_invocation_id : vec3<u32>) {
const index : u32 = global_invocation_id.x;
if (index >= NUM_PARTICLES) {
return;
}

View File

@@ -1,6 +1,3 @@
[[builtin(global_invocation_id)]]
var global_id: vec3<u32>;
[[block]]
struct PrimeIndices {
data: [[stride(4)]] array<u32>;
@@ -34,6 +31,6 @@ fn collatz_iterations(n_base: u32) -> u32 {
}
[[stage(compute), workgroup_size(1)]]
fn main() {
fn main([[builtin(global_invocation_id)]] global_id: vec3<u32>) {
v_indices.data[global_id.x] = collatz_iterations(v_indices.data[global_id.x]);
}

View File

@@ -1,28 +1,29 @@
// vertex
const c_scale: f32 = 1.2;
[[location(0)]] var<in> a_pos : vec2<f32>;
[[location(1)]] var<in> a_uv : vec2<f32>;
[[location(0)]] var<out> v_uv : vec2<f32>;
[[builtin(position)]] var<out> o_position : vec4<f32>;
struct VertexOutput {
[[location(0)]] uv : vec2<f32>;
[[builtin(position)]] position : vec4<f32>;
};
[[stage(vertex)]]
fn main() {
v_uv = a_uv;
o_position = vec4<f32>(c_scale * a_pos, 0.0, 1.0);
fn main([[location(0)]] pos : vec2<f32>, [[location(1)]] uv : vec2<f32>) -> VertexOutput {
var out: VertexOutput;
out.uv = uv;
out.position = vec4<f32>(c_scale * pos, 0.0, 1.0);
return out;
}
// fragment
[[location(0)]] var<in> v_uv : vec2<f32>;
[[group(0), binding(0)]] var u_texture : texture_2d<f32>;
[[group(0), binding(1)]] var u_sampler : sampler;
[[location(0)]] var<out> o_color : vec4<f32>;
[[stage(fragment)]]
fn main() {
const color: vec4<f32> = textureSample(u_texture, u_sampler, v_uv);
fn main([[location(0)]] uv : vec2<f32>) -> [[location(0)]] vec4<f32> {
const color: vec4<f32> = textureSample(u_texture, u_sampler, uv);
if (color.a == 0.0) {
discard;
}
const premultiplied: vec4<f32> = color.a * color;
o_color = premultiplied;
return premultiplied;
}

View File

@@ -35,19 +35,15 @@ fn fetch_shadow(light_id: u32, homogeneous_coords: vec4<f32>) -> f32 {
return textureSampleCompare(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z * proj_correction);
}
[[location(0)]]
var<in> in_normal_fs: vec3<f32>;
[[location(1)]]
var<in> in_position_fs: vec4<f32>;
[[location(0)]]
var<out> out_color_fs: vec4<f32>;
const c_ambient: vec3<f32> = vec3<f32>(0.05, 0.05, 0.05);
const c_max_lights: u32 = 10u;
[[stage(fragment)]]
fn fs_main() {
const normal: vec3<f32> = normalize(in_normal_fs);
fn fs_main(
[[location(0)]] raw_normal: vec3<f32>,
[[location(1)]] position: vec4<f32>
) -> [[location(0)]] vec4<f32> {
const normal: vec3<f32> = normalize(raw_normal);
// accumulate color
var color: vec3<f32> = c_ambient;
var i: u32 = 0u;
@@ -56,8 +52,8 @@ fn fs_main() {
break;
}
const light: Light = s_lights.data[i];
const shadow: f32 = fetch_shadow(i, light.proj * in_position_fs);
const light_dir: vec3<f32> = normalize(light.pos.xyz - in_position_fs.xyz);
const shadow: f32 = fetch_shadow(i, light.proj * position);
const light_dir: vec3<f32> = normalize(light.pos.xyz - position.xyz);
const diffuse: f32 = max(0.0, dot(normal, light_dir));
color = color + shadow * diffuse * light.color.xyz;
continuing {
@@ -65,5 +61,5 @@ fn fs_main() {
}
}
// multiply the light by material color
out_color_fs = vec4<f32>(color, 1.0);
return vec4<f32>(color, 1.0);
}

View File

@@ -1,7 +1,7 @@
[[builtin(position)]]
var<out> out_position: vec4<f32>;
[[location(0)]] var<out> out_uv: vec3<f32>;
[[builtin(vertex_index)]] var<in> in_vertex_index: u32;
struct VertexOutput {
[[builtin(position)]] position: vec4<f32>;
[[location(0)]] uv: vec3<f32>;
};
[[block]]
struct Data {
@@ -12,10 +12,10 @@ struct Data {
var r_data: Data;
[[stage(vertex)]]
fn vs_main() {
fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput {
// hacky way to draw a large triangle
var tmp1: i32 = i32(in_vertex_index) / 2;
var tmp2: i32 = i32(in_vertex_index) & 1;
var tmp1: i32 = i32(vertex_index) / 2;
var tmp2: i32 = i32(vertex_index) & 1;
const pos: vec4<f32> = vec4<f32>(
f32(tmp1) * 4.0 - 1.0,
f32(tmp2) * 4.0 - 1.0,
@@ -25,8 +25,10 @@ fn vs_main() {
const inv_model_view: mat3x3<f32> = transpose(mat3x3<f32>(r_data.view.x.xyz, r_data.view.y.xyz, r_data.view.z.xyz));
var unprojected: vec4<f32> = r_data.proj_inv * pos; //TODO: const
out_uv = inv_model_view * unprojected.xyz;
out_position = pos;
var out: VertexOutput;
out.uv = inv_model_view * unprojected.xyz;
out.position = pos;
return out;
}
[[group(0), binding(1)]]
@@ -34,10 +36,7 @@ var r_texture: texture_cube<f32>;
[[group(0), binding(2)]]
var r_sampler: sampler;
[[location(0)]] var<in> in_uv: vec3<f32>;
[[location(0)]] var<out> out_color: vec4<f32>;
[[stage(fragment)]]
fn fs_main() {
out_color = textureSample(r_texture, r_sampler, in_uv);
fn fs_main([[location(0)]] uv: vec3<f32>) -> [[location(0)]] vec4<f32> {
return textureSample(r_texture, r_sampler, uv);
}

View File

@@ -1,4 +1,3 @@
[[location(0)]] var<in> tex_coord: vec2<f32>;
[[group(0), binding(0)]] var texture0: texture_2d<f32>;
[[group(0), binding(1)]] var texture1: texture_2d<f32>;
[[group(0), binding(2)]] var sampler: sampler;
@@ -9,13 +8,11 @@ struct PushConstants {
};
var<push_constant> pc: PushConstants;
[[location(1)]] var<out> color: vec4<f32>;
[[stage(fragment)]]
fn main() {
fn main([[location(0)]] tex_coord: vec2<f32>) -> [[location(1)]] vec4<f32> {
if (pc.index == 0) {
color = textureSample(texture0, sampler, tex_coord);
return textureSample(texture0, sampler, tex_coord);
} else {
color = textureSample(texture1, sampler, tex_coord);
return textureSample(texture1, sampler, tex_coord);
}
}

View File

@@ -45,11 +45,13 @@ constexpr constant unsigned const_1u = 1u;
constexpr constant float const_1f = 1.0;
constexpr constant float const_0_10f = 0.1;
constexpr constant float const_n1f = -1.0;
struct main1Input {
};
kernel void main1(
constant SimParams& params [[buffer(0)]],
constant Particles& particlesSrc [[buffer(1)]],
device Particles& particlesDst [[buffer(2)]],
type4 gl_GlobalInvocationID [[thread_position_in_grid]]
type4 global_invocation_id [[thread_position_in_grid]]
, constant SimParams& params [[buffer(0)]]
, constant Particles& particlesSrc [[buffer(1)]]
, device Particles& particlesDst [[buffer(2)]]
) {
type1 vPos;
type1 vVel;
@@ -61,11 +63,11 @@ kernel void main1(
type1 pos1;
type1 vel1;
type i = const_0u;
if ((gl_GlobalInvocationID.x >= NUM_PARTICLES)) {
return ;
if ((global_invocation_id.x >= NUM_PARTICLES)) {
return;
}
vPos = particlesSrc.particles[gl_GlobalInvocationID.x].pos;
vVel = particlesSrc.particles[gl_GlobalInvocationID.x].vel;
vPos = particlesSrc.particles[global_invocation_id.x].pos;
vVel = particlesSrc.particles[global_invocation_id.x].vel;
cMass = metal::float2(const_0f, const_0f);
cVel = metal::float2(const_0f, const_0f);
colVel = metal::float2(const_0f, const_0f);
@@ -78,7 +80,7 @@ kernel void main1(
if ((i >= NUM_PARTICLES)) {
break;
}
if ((i == gl_GlobalInvocationID.x)) {
if ((i == global_invocation_id.x)) {
continue;
}
pos1 = particlesSrc.particles[i].pos;
@@ -116,8 +118,8 @@ kernel void main1(
if ((vPos.y > const_1f)) {
vPos.y = const_n1f;
}
particlesDst.particles[gl_GlobalInvocationID.x].pos = vPos;
particlesDst.particles[gl_GlobalInvocationID.x].vel = vVel;
return ;
particlesDst.particles[global_invocation_id.x].pos = vPos;
particlesDst.particles[global_invocation_id.x].vel = vVel;
return;
}

View File

@@ -9,8 +9,8 @@ expression: dis
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %41 "main" %25
OpExecutionMode %41 LocalSize 64 1 1
OpEntryPoint GLCompute %43 "main" %40
OpExecutionMode %43 LocalSize 64 1 1
OpSource GLSL 450
OpName %3 "NUM_PARTICLES"
OpName %16 "SimParams"
@@ -29,19 +29,19 @@ OpMemberName %21 0 "pos"
OpMemberName %21 1 "vel"
OpName %18 "particlesSrc"
OpName %24 "particlesDst"
OpName %25 "gl_GlobalInvocationID"
OpName %28 "vPos"
OpName %30 "vVel"
OpName %31 "cMass"
OpName %32 "cVel"
OpName %33 "colVel"
OpName %34 "cMassCount"
OpName %36 "cVelCount"
OpName %37 "pos"
OpName %38 "vel"
OpName %39 "i"
OpName %41 "main"
OpName %41 "main"
OpName %25 "vPos"
OpName %27 "vVel"
OpName %28 "cMass"
OpName %29 "cVel"
OpName %30 "colVel"
OpName %31 "cMassCount"
OpName %33 "cVelCount"
OpName %34 "pos"
OpName %35 "vel"
OpName %36 "i"
OpName %40 "global_invocation_id"
OpName %43 "main"
OpName %43 "main"
OpDecorate %16 Block
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 1 Offset 4
@@ -62,7 +62,7 @@ OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 1
OpDecorate %24 DescriptorSet 0
OpDecorate %24 Binding 2
OpDecorate %25 BuiltIn GlobalInvocationId
OpDecorate %40 BuiltIn GlobalInvocationId
%2 = OpTypeVoid
%4 = OpTypeInt 32 1
%3 = OpConstant %4 1500
@@ -86,13 +86,13 @@ OpDecorate %25 BuiltIn GlobalInvocationId
%23 = OpTypePointer Uniform %19
%18 = OpVariable %23 Uniform
%24 = OpVariable %23 Uniform
%26 = OpTypeVector %9 3
%27 = OpTypePointer Input %26
%25 = OpVariable %27 Input
%29 = OpTypePointer Function %22
%35 = OpTypePointer Function %4
%40 = OpTypePointer Function %9
%42 = OpTypeFunction %2
%26 = OpTypePointer Function %22
%32 = OpTypePointer Function %4
%37 = OpTypePointer Function %9
%39 = OpTypeVector %9 3
%41 = OpTypePointer Input %39
%40 = OpVariable %41 Input
%44 = OpTypeFunction %2
%47 = OpTypeBool
%51 = OpTypePointer Uniform %20
%52 = OpTypePointer Uniform %21
@@ -122,22 +122,22 @@ OpDecorate %25 BuiltIn GlobalInvocationId
%215 = OpConstant %4 0
%218 = OpConstant %4 1
%219 = OpConstant %4 0
%41 = OpFunction %2 None %42
%43 = OpLabel
%39 = OpVariable %40 Function %8
%36 = OpVariable %35 Function %7
%32 = OpVariable %29 Function
%28 = OpVariable %29 Function
%37 = OpVariable %29 Function
%33 = OpVariable %29 Function
%30 = OpVariable %29 Function
%38 = OpVariable %29 Function
%34 = OpVariable %35 Function %7
%31 = OpVariable %29 Function
OpBranch %44
%44 = OpLabel
%45 = OpLoad %26 %25
%46 = OpCompositeExtract %9 %45 0
%43 = OpFunction %2 None %44
%38 = OpLabel
%36 = OpVariable %37 Function %8
%33 = OpVariable %32 Function %7
%29 = OpVariable %26 Function
%25 = OpVariable %26 Function
%34 = OpVariable %26 Function
%30 = OpVariable %26 Function
%27 = OpVariable %26 Function
%35 = OpVariable %26 Function
%31 = OpVariable %32 Function %7
%28 = OpVariable %26 Function
%42 = OpLoad %39 %40
OpBranch %45
%45 = OpLabel
%46 = OpCompositeExtract %9 %42 0
%48 = OpUGreaterThanEqual %47 %46 %3
OpSelectionMerge %49 None
OpBranchConditional %48 %50 %49
@@ -146,45 +146,45 @@ OpReturn
%49 = OpLabel
%56 = OpAccessChain %53 %18 %55 %46 %54
%57 = OpLoad %22 %56
OpStore %28 %57
OpStore %25 %57
%60 = OpAccessChain %53 %18 %59 %46 %58
%61 = OpLoad %22 %60
OpStore %30 %61
OpStore %27 %61
%62 = OpCompositeConstruct %22 %5 %5
OpStore %31 %62
OpStore %28 %62
%63 = OpCompositeConstruct %22 %5 %5
OpStore %32 %63
OpStore %29 %63
%64 = OpCompositeConstruct %22 %5 %5
OpStore %33 %64
OpStore %30 %64
OpBranch %65
%65 = OpLabel
OpLoopMerge %66 %68 None
OpBranch %67
%67 = OpLabel
%69 = OpLoad %9 %39
%69 = OpLoad %9 %36
%70 = OpUGreaterThanEqual %47 %69 %3
OpSelectionMerge %71 None
OpBranchConditional %70 %72 %71
%72 = OpLabel
OpBranch %66
%71 = OpLabel
%73 = OpLoad %9 %39
%73 = OpLoad %9 %36
%74 = OpIEqual %47 %73 %46
OpSelectionMerge %75 None
OpBranchConditional %74 %76 %75
%76 = OpLabel
OpBranch %68
%75 = OpLabel
%77 = OpLoad %9 %39
%77 = OpLoad %9 %36
%80 = OpAccessChain %53 %18 %79 %77 %78
%81 = OpLoad %22 %80
OpStore %37 %81
%82 = OpLoad %9 %39
OpStore %34 %81
%82 = OpLoad %9 %36
%85 = OpAccessChain %53 %18 %84 %82 %83
%86 = OpLoad %22 %85
OpStore %38 %86
%87 = OpLoad %22 %37
%88 = OpLoad %22 %28
OpStore %35 %86
%87 = OpLoad %22 %34
%88 = OpLoad %22 %25
%89 = OpExtInst %6 %1 Distance %87 %88
%92 = OpAccessChain %90 %15 %91
%93 = OpLoad %6 %92
@@ -192,17 +192,17 @@ OpStore %38 %86
OpSelectionMerge %95 None
OpBranchConditional %94 %96 %95
%96 = OpLabel
%97 = OpLoad %22 %31
%98 = OpLoad %22 %37
%97 = OpLoad %22 %28
%98 = OpLoad %22 %34
%99 = OpFAdd %22 %97 %98
OpStore %31 %99
%100 = OpLoad %4 %34
OpStore %28 %99
%100 = OpLoad %4 %31
%101 = OpIAdd %4 %100 %10
OpStore %34 %101
OpStore %31 %101
OpBranch %95
%95 = OpLabel
%102 = OpLoad %22 %37
%103 = OpLoad %22 %28
%102 = OpLoad %22 %34
%103 = OpLoad %22 %25
%104 = OpExtInst %6 %1 Distance %102 %103
%106 = OpAccessChain %90 %15 %105
%107 = OpLoad %6 %106
@@ -210,16 +210,16 @@ OpBranch %95
OpSelectionMerge %109 None
OpBranchConditional %108 %110 %109
%110 = OpLabel
%111 = OpLoad %22 %33
%112 = OpLoad %22 %37
%113 = OpLoad %22 %28
%111 = OpLoad %22 %30
%112 = OpLoad %22 %34
%113 = OpLoad %22 %25
%114 = OpFSub %22 %112 %113
%115 = OpFSub %22 %111 %114
OpStore %33 %115
OpStore %30 %115
OpBranch %109
%109 = OpLabel
%116 = OpLoad %22 %37
%117 = OpLoad %22 %28
%116 = OpLoad %22 %34
%117 = OpLoad %22 %25
%118 = OpExtInst %6 %1 Distance %116 %117
%120 = OpAccessChain %90 %15 %119
%121 = OpLoad %6 %120
@@ -227,125 +227,125 @@ OpBranch %109
OpSelectionMerge %123 None
OpBranchConditional %122 %124 %123
%124 = OpLabel
%125 = OpLoad %22 %32
%126 = OpLoad %22 %38
%125 = OpLoad %22 %29
%126 = OpLoad %22 %35
%127 = OpFAdd %22 %125 %126
OpStore %32 %127
%128 = OpLoad %4 %36
OpStore %29 %127
%128 = OpLoad %4 %33
%129 = OpIAdd %4 %128 %10
OpStore %36 %129
OpStore %33 %129
OpBranch %123
%123 = OpLabel
OpBranch %68
%68 = OpLabel
%130 = OpLoad %9 %39
%130 = OpLoad %9 %36
%131 = OpIAdd %9 %130 %11
OpStore %39 %131
OpStore %36 %131
OpBranch %65
%66 = OpLabel
%132 = OpLoad %4 %34
%132 = OpLoad %4 %31
%133 = OpSGreaterThan %47 %132 %7
OpSelectionMerge %134 None
OpBranchConditional %133 %135 %134
%135 = OpLabel
%136 = OpLoad %22 %31
%137 = OpLoad %4 %34
%136 = OpLoad %22 %28
%137 = OpLoad %4 %31
%138 = OpConvertSToF %6 %137
%139 = OpFDiv %6 %12 %138
%140 = OpVectorTimesScalar %22 %136 %139
%141 = OpLoad %22 %28
%141 = OpLoad %22 %25
%142 = OpFSub %22 %140 %141
OpStore %31 %142
OpStore %28 %142
OpBranch %134
%134 = OpLabel
%143 = OpLoad %4 %36
%143 = OpLoad %4 %33
%144 = OpSGreaterThan %47 %143 %7
OpSelectionMerge %145 None
OpBranchConditional %144 %146 %145
%146 = OpLabel
%147 = OpLoad %22 %32
%148 = OpLoad %4 %36
%147 = OpLoad %22 %29
%148 = OpLoad %4 %33
%149 = OpConvertSToF %6 %148
%150 = OpFDiv %6 %12 %149
%151 = OpVectorTimesScalar %22 %147 %150
OpStore %32 %151
OpStore %29 %151
OpBranch %145
%145 = OpLabel
%152 = OpLoad %22 %30
%153 = OpLoad %22 %31
%152 = OpLoad %22 %27
%153 = OpLoad %22 %28
%155 = OpAccessChain %90 %15 %154
%156 = OpLoad %6 %155
%157 = OpVectorTimesScalar %22 %153 %156
%158 = OpFAdd %22 %152 %157
%159 = OpLoad %22 %33
%159 = OpLoad %22 %30
%161 = OpAccessChain %90 %15 %160
%162 = OpLoad %6 %161
%163 = OpVectorTimesScalar %22 %159 %162
%164 = OpFAdd %22 %158 %163
%165 = OpLoad %22 %32
%165 = OpLoad %22 %29
%167 = OpAccessChain %90 %15 %166
%168 = OpLoad %6 %167
%169 = OpVectorTimesScalar %22 %165 %168
%170 = OpFAdd %22 %164 %169
OpStore %30 %170
%171 = OpLoad %22 %30
OpStore %27 %170
%171 = OpLoad %22 %27
%172 = OpExtInst %22 %1 Normalize %171
%173 = OpLoad %22 %30
%173 = OpLoad %22 %27
%174 = OpExtInst %6 %1 Length %173
%175 = OpExtInst %6 %1 FClamp %174 %5 %13
%176 = OpVectorTimesScalar %22 %172 %175
OpStore %30 %176
%177 = OpLoad %22 %28
%178 = OpLoad %22 %30
OpStore %27 %176
%177 = OpLoad %22 %25
%178 = OpLoad %22 %27
%180 = OpAccessChain %90 %15 %179
%181 = OpLoad %6 %180
%182 = OpVectorTimesScalar %22 %178 %181
%183 = OpFAdd %22 %177 %182
OpStore %28 %183
%184 = OpLoad %22 %28
OpStore %25 %183
%184 = OpLoad %22 %25
%185 = OpCompositeExtract %6 %184 0
%186 = OpFOrdLessThan %47 %185 %14
OpSelectionMerge %187 None
OpBranchConditional %186 %188 %187
%188 = OpLabel
%191 = OpAccessChain %189 %28 %190
%191 = OpAccessChain %189 %25 %190
OpStore %191 %12
OpBranch %187
%187 = OpLabel
%192 = OpLoad %22 %28
%192 = OpLoad %22 %25
%193 = OpCompositeExtract %6 %192 0
%194 = OpFOrdGreaterThan %47 %193 %12
OpSelectionMerge %195 None
OpBranchConditional %194 %196 %195
%196 = OpLabel
%198 = OpAccessChain %189 %28 %197
%198 = OpAccessChain %189 %25 %197
OpStore %198 %14
OpBranch %195
%195 = OpLabel
%199 = OpLoad %22 %28
%199 = OpLoad %22 %25
%200 = OpCompositeExtract %6 %199 1
%201 = OpFOrdLessThan %47 %200 %14
OpSelectionMerge %202 None
OpBranchConditional %201 %203 %202
%203 = OpLabel
%205 = OpAccessChain %189 %28 %204
%205 = OpAccessChain %189 %25 %204
OpStore %205 %12
OpBranch %202
%202 = OpLabel
%206 = OpLoad %22 %28
%206 = OpLoad %22 %25
%207 = OpCompositeExtract %6 %206 1
%208 = OpFOrdGreaterThan %47 %207 %12
OpSelectionMerge %209 None
OpBranchConditional %208 %210 %209
%210 = OpLabel
%212 = OpAccessChain %189 %28 %211
%212 = OpAccessChain %189 %25 %211
OpStore %212 %14
OpBranch %209
%209 = OpLabel
%213 = OpLoad %22 %28
%213 = OpLoad %22 %25
%216 = OpAccessChain %53 %24 %215 %46 %214
OpStore %216 %213
%217 = OpLoad %22 %30
%217 = OpLoad %22 %27
%220 = OpAccessChain %53 %24 %219 %46 %218
OpStore %220 %217
OpReturn

View File

@@ -6,7 +6,7 @@ expression: output
functions: [
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
may_kill: false,
@@ -15,9 +15,6 @@ expression: output
(
bits: 0,
),
(
bits: 0,
),
],
expressions: [
(
@@ -33,20 +30,12 @@ expression: output
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 0,
assignable_global: Some(2),
),
(
uniformity: (
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 7,
@@ -62,7 +51,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 3,
@@ -70,7 +59,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -86,7 +75,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -94,7 +83,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -110,7 +99,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -126,7 +115,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -134,7 +123,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -150,7 +139,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -166,7 +155,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -174,7 +163,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -190,7 +179,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(4),
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
@@ -198,7 +187,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,
@@ -214,7 +203,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,
@@ -222,7 +211,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,
@@ -234,15 +223,12 @@ expression: output
entry_points: [
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
may_kill: false,
sampling_set: [],
global_uses: [
(
bits: 1,
),
(
bits: 3,
),
@@ -262,15 +248,7 @@ expression: output
requirement: None,
),
ref_count: 2,
assignable_global: Some(2),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: Some(2),
assignable_global: None,
),
(
uniformity: (
@@ -278,6 +256,14 @@ expression: output
requirement: None,
),
ref_count: 1,
assignable_global: Some(1),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
@@ -286,23 +272,7 @@ expression: output
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: Some(2),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: Some(2),
assignable_global: Some(1),
),
(
uniformity: (
@@ -310,6 +280,14 @@ expression: output
requirement: None,
),
ref_count: 1,
assignable_global: Some(1),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
@@ -318,19 +296,11 @@ expression: output
requirement: None,
),
ref_count: 1,
assignable_global: None,
assignable_global: Some(1),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: Some(2),
),
(
uniformity: (
non_uniform_result: Some(2),
non_uniform_result: Some(1),
requirement: None,
),
ref_count: 1,
@@ -338,7 +308,7 @@ expression: output
),
(
uniformity: (
non_uniform_result: Some(6),
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,

View File

@@ -5,25 +5,25 @@ expression: msl
#include <metal_stdlib>
#include <simd/simd.h>
typedef metal::uint3 type;
typedef uint type;
typedef uint type1;
typedef type1 type2[1];
typedef type type1[1];
struct PrimeIndices {
type2 data;
type1 data;
};
typedef metal::uint3 type2;
constexpr constant unsigned const_0u = 0u;
constexpr constant unsigned const_1u = 1u;
constexpr constant unsigned const_2u = 2u;
constexpr constant unsigned const_3u = 3u;
type1 collatz_iterations(
type1 n_base
type collatz_iterations(
type n_base
) {
type1 n;
type1 i = const_0u;
type n;
type i = const_0u;
n = n_base;
while(true) {
if ((n <= const_1u)) {
@@ -39,12 +39,14 @@ type1 collatz_iterations(
return i;
}
struct main1Input {
};
kernel void main1(
type global_id [[thread_position_in_grid]],
device PrimeIndices& v_indices [[buffer(0)]]
type2 global_id [[thread_position_in_grid]]
, device PrimeIndices& v_indices [[buffer(0)]]
) {
type1 _expr11 = collatz_iterations(v_indices.data[global_id.x]);
v_indices.data[global_id.x] = _expr11;
return ;
type _expr9 = collatz_iterations(v_indices.data[global_id.x]);
v_indices.data[global_id.x] = _expr9;
return;
}

View File

@@ -4,14 +4,6 @@ expression: output
---
(
types: [
(
name: None,
inner: Vector(
size: Tri,
kind: Uint,
width: 4,
),
),
(
name: None,
inner: Scalar(
@@ -22,7 +14,7 @@ expression: output
(
name: None,
inner: Array(
base: 2,
base: 1,
size: Dynamic,
stride: Some(4),
),
@@ -35,11 +27,20 @@ expression: output
(
name: Some("data"),
span: None,
ty: 3,
ty: 2,
binding: None,
),
],
),
),
(
name: None,
inner: Vector(
size: Tri,
kind: Uint,
width: 4,
),
),
],
constants: [
(
@@ -76,27 +77,15 @@ expression: output
),
],
global_variables: [
(
name: Some("global_id"),
class: Input,
binding: Some(BuiltIn(GlobalInvocationId)),
ty: 1,
init: None,
interpolation: None,
storage_access: (
bits: 0,
),
),
(
name: Some("v_indices"),
class: Storage,
binding: Some(Resource(
binding: Some((
group: 0,
binding: 0,
)),
ty: 4,
ty: 3,
init: None,
interpolation: None,
storage_access: (
bits: 3,
),
@@ -108,176 +97,179 @@ expression: output
arguments: [
(
name: Some("n_base"),
ty: 2,
ty: 1,
binding: None,
),
],
return_type: Some(2),
result: Some((
ty: 1,
binding: None,
)),
local_variables: [
(
name: Some("n"),
ty: 2,
ty: 1,
init: None,
),
(
name: Some("i"),
ty: 2,
ty: 1,
init: Some(1),
),
],
expressions: [
GlobalVariable(1),
GlobalVariable(2),
FunctionArgument(0),
LocalVariable(1),
Constant(1),
LocalVariable(2),
Load(
pointer: 4,
pointer: 3,
),
Constant(2),
Binary(
op: LessEqual,
left: 7,
right: 8,
left: 6,
right: 7,
),
Load(
pointer: 4,
pointer: 3,
),
Constant(3),
Binary(
op: Modulo,
left: 10,
right: 11,
left: 9,
right: 10,
),
Constant(1),
Binary(
op: Equal,
left: 12,
right: 13,
left: 11,
right: 12,
),
Load(
pointer: 4,
pointer: 3,
),
Constant(3),
Binary(
op: Divide,
left: 15,
right: 16,
left: 14,
right: 15,
),
Constant(4),
Load(
pointer: 4,
pointer: 3,
),
Binary(
op: Multiply,
left: 18,
right: 19,
left: 17,
right: 18,
),
Constant(2),
Binary(
op: Add,
left: 20,
right: 21,
left: 19,
right: 20,
),
Load(
pointer: 6,
pointer: 5,
),
Constant(2),
Binary(
op: Add,
left: 23,
right: 24,
left: 22,
right: 23,
),
Load(
pointer: 6,
pointer: 5,
),
],
body: [
Store(
pointer: 4,
value: 3,
pointer: 3,
value: 2,
),
Loop(
body: [
Emit((
start: 6,
end: 7,
start: 5,
end: 6,
)),
Emit((
start: 8,
end: 9,
start: 7,
end: 8,
)),
If(
condition: 9,
condition: 8,
accept: [
Break,
],
reject: [],
),
Emit((
start: 9,
end: 10,
start: 8,
end: 9,
)),
Emit((
start: 11,
end: 12,
start: 10,
end: 11,
)),
Emit((
start: 13,
end: 14,
start: 12,
end: 13,
)),
If(
condition: 14,
condition: 13,
accept: [
Emit((
start: 14,
end: 15,
start: 13,
end: 14,
)),
Emit((
start: 16,
end: 17,
start: 15,
end: 16,
)),
Store(
pointer: 4,
value: 17,
pointer: 3,
value: 16,
),
],
reject: [
Emit((
start: 18,
end: 20,
start: 17,
end: 19,
)),
Emit((
start: 21,
end: 22,
start: 20,
end: 21,
)),
Store(
pointer: 4,
value: 22,
pointer: 3,
value: 21,
),
],
),
Emit((
start: 22,
end: 23,
start: 21,
end: 22,
)),
Emit((
start: 24,
end: 25,
start: 23,
end: 24,
)),
Store(
pointer: 6,
value: 25,
pointer: 5,
value: 24,
),
],
continuing: [],
),
Emit((
start: 25,
end: 26,
start: 24,
end: 25,
)),
Return(
value: Some(26),
value: Some(25),
),
],
),
@@ -290,62 +282,62 @@ expression: output
workgroup_size: (1, 1, 1),
function: (
name: Some("main"),
arguments: [],
return_type: None,
arguments: [
(
name: Some("global_id"),
ty: 4,
binding: Some(BuiltIn(GlobalInvocationId)),
),
],
result: None,
local_variables: [],
expressions: [
GlobalVariable(1),
GlobalVariable(2),
FunctionArgument(0),
AccessIndex(
base: 2,
base: 1,
index: 0,
),
Load(
pointer: 1,
),
AccessIndex(
base: 4,
base: 2,
index: 0,
),
Access(
base: 3,
index: 5,
index: 4,
),
AccessIndex(
base: 1,
index: 0,
),
AccessIndex(
base: 2,
index: 0,
),
Load(
pointer: 1,
),
AccessIndex(
base: 8,
index: 0,
),
Access(
base: 7,
index: 9,
base: 6,
index: 7,
),
Load(
pointer: 10,
pointer: 8,
),
Call(1),
],
body: [
Emit((
start: 2,
end: 11,
end: 9,
)),
Call(
function: 1,
arguments: [
11,
9,
],
result: Some(12),
result: Some(10),
),
Store(
pointer: 6,
value: 12,
pointer: 5,
value: 10,
),
Return(
value: None,

View File

@@ -5,109 +5,108 @@ expression: dis
; SPIR-V
; Version: 1.0
; Generator: rspirv
; Bound: 63
; Bound: 62
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %46 "main" %8
OpExecutionMode %46 LocalSize 1 1 1
OpEntryPoint GLCompute %48 "main" %45
OpExecutionMode %48 LocalSize 1 1 1
OpSource GLSL 450
OpName %8 "global_id"
OpName %12 "PrimeIndices"
OpMemberName %12 0 "data"
OpName %11 "v_indices"
OpName %15 "n"
OpName %17 "i"
OpName %19 "collatz_iterations"
OpName %46 "main"
OpName %46 "main"
OpDecorate %8 BuiltIn GlobalInvocationId
OpDecorate %12 BufferBlock
OpMemberDecorate %12 0 Offset 0
OpDecorate %13 ArrayStride 4
OpDecorate %11 DescriptorSet 0
OpDecorate %11 Binding 0
OpName %9 "PrimeIndices"
OpMemberName %9 0 "data"
OpName %8 "v_indices"
OpName %12 "n"
OpName %14 "i"
OpName %17 "collatz_iterations"
OpName %45 "global_id"
OpName %48 "main"
OpName %48 "main"
OpDecorate %9 BufferBlock
OpMemberDecorate %9 0 Offset 0
OpDecorate %10 ArrayStride 4
OpDecorate %8 DescriptorSet 0
OpDecorate %8 Binding 0
OpDecorate %45 BuiltIn GlobalInvocationId
%2 = OpTypeVoid
%4 = OpTypeInt 32 0
%3 = OpConstant %4 0
%5 = OpConstant %4 1
%6 = OpConstant %4 2
%7 = OpConstant %4 3
%9 = OpTypeVector %4 3
%10 = OpTypePointer Input %9
%8 = OpVariable %10 Input
%13 = OpTypeRuntimeArray %4
%12 = OpTypeStruct %13
%14 = OpTypePointer Uniform %12
%11 = OpVariable %14 Uniform
%16 = OpTypePointer Function %4
%20 = OpTypeFunction %4 %4
%28 = OpTypeBool
%47 = OpTypeFunction %2
%50 = OpTypePointer Uniform %13
%10 = OpTypeRuntimeArray %4
%9 = OpTypeStruct %10
%11 = OpTypePointer Uniform %9
%8 = OpVariable %11 Uniform
%13 = OpTypePointer Function %4
%18 = OpTypeFunction %4 %4
%25 = OpTypeBool
%44 = OpTypeVector %4 3
%46 = OpTypePointer Input %44
%45 = OpVariable %46 Input
%49 = OpTypeFunction %2
%51 = OpTypePointer Uniform %10
%53 = OpTypePointer Uniform %4
%56 = OpTypeInt 32 1
%57 = OpConstant %56 0
%61 = OpConstant %56 0
%19 = OpFunction %4 None %20
%18 = OpFunctionParameter %4
%21 = OpLabel
%15 = OpVariable %16 Function
%17 = OpVariable %16 Function %3
%55 = OpTypeInt 32 1
%56 = OpConstant %55 0
%60 = OpConstant %55 0
%17 = OpFunction %4 None %18
%16 = OpFunctionParameter %4
%15 = OpLabel
%12 = OpVariable %13 Function
%14 = OpVariable %13 Function %3
OpBranch %19
%19 = OpLabel
OpStore %12 %16
OpBranch %20
%20 = OpLabel
OpLoopMerge %21 %23 None
OpBranch %22
%22 = OpLabel
OpStore %15 %18
%24 = OpLoad %4 %12
%26 = OpULessThanEqual %25 %24 %5
OpSelectionMerge %27 None
OpBranchConditional %26 %28 %27
%28 = OpLabel
OpBranch %21
%27 = OpLabel
%29 = OpLoad %4 %12
%30 = OpUMod %4 %29 %6
%31 = OpIEqual %25 %30 %3
OpSelectionMerge %32 None
OpBranchConditional %31 %33 %34
%33 = OpLabel
%35 = OpLoad %4 %12
%36 = OpUDiv %4 %35 %6
OpStore %12 %36
OpBranch %32
%34 = OpLabel
%37 = OpLoad %4 %12
%38 = OpIMul %4 %7 %37
%39 = OpIAdd %4 %38 %5
OpStore %12 %39
OpBranch %32
%32 = OpLabel
%40 = OpLoad %4 %14
%41 = OpIAdd %4 %40 %5
OpStore %14 %41
OpBranch %23
%23 = OpLabel
OpLoopMerge %24 %26 None
OpBranch %25
%25 = OpLabel
%27 = OpLoad %4 %15
%29 = OpULessThanEqual %28 %27 %5
OpSelectionMerge %30 None
OpBranchConditional %29 %31 %30
%31 = OpLabel
OpBranch %24
%30 = OpLabel
%32 = OpLoad %4 %15
%33 = OpUMod %4 %32 %6
%34 = OpIEqual %28 %33 %3
OpSelectionMerge %35 None
OpBranchConditional %34 %36 %37
%36 = OpLabel
%38 = OpLoad %4 %15
%39 = OpUDiv %4 %38 %6
OpStore %15 %39
OpBranch %35
%37 = OpLabel
%40 = OpLoad %4 %15
%41 = OpIMul %4 %7 %40
%42 = OpIAdd %4 %41 %5
OpStore %15 %42
OpBranch %35
%35 = OpLabel
%43 = OpLoad %4 %17
%44 = OpIAdd %4 %43 %5
OpStore %17 %44
OpBranch %26
%26 = OpLabel
OpBranch %23
%24 = OpLabel
%45 = OpLoad %4 %17
OpReturnValue %45
OpBranch %20
%21 = OpLabel
%42 = OpLoad %4 %14
OpReturnValue %42
OpFunctionEnd
%46 = OpFunction %2 None %47
%48 = OpLabel
OpBranch %49
%49 = OpLabel
%51 = OpLoad %9 %8
%52 = OpCompositeExtract %4 %51 0
%54 = OpLoad %9 %8
%55 = OpCompositeExtract %4 %54 0
%58 = OpAccessChain %53 %11 %57 %55
%59 = OpLoad %4 %58
%60 = OpFunctionCall %4 %19 %59
%62 = OpAccessChain %53 %11 %61 %52
OpStore %62 %60
%48 = OpFunction %2 None %49
%43 = OpLabel
%47 = OpLoad %44 %45
OpBranch %50
%50 = OpLabel
%52 = OpCompositeExtract %4 %47 0
%54 = OpCompositeExtract %4 %47 0
%57 = OpAccessChain %53 %8 %56 %54
%58 = OpLoad %4 %57
%59 = OpFunctionCall %4 %17 %58
%61 = OpAccessChain %53 %8 %60 %52
OpStore %61 %59
OpReturn
OpFunctionEnd

View File

@@ -8,7 +8,9 @@ precision highp float;
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
return;
}

View File

@@ -7,6 +7,6 @@ expression: msl
kernel void main1(
) {
return ;
return;
}

View File

@@ -9,15 +9,15 @@ expression: dis
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %3 "main"
OpExecutionMode %3 LocalSize 1 1 1
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource GLSL 450
OpName %3 "main"
OpName %3 "main"
OpName %4 "main"
OpName %4 "main"
%2 = OpTypeVoid
%4 = OpTypeFunction %2
%3 = OpFunction %2 None %4
%5 = OpLabel
%5 = OpTypeFunction %2
%4 = OpFunction %2 None %5
%3 = OpLabel
OpBranch %6
%6 = OpLabel
OpReturn

View File

@@ -6,18 +6,23 @@ expression: string
precision highp float;
in vec2 _location_0_vs;
struct VertexOutput {
vec2 uv;
vec4 position;
};
uniform highp sampler2D _group_0_binding_0;
out vec4 _location_0;
in vec2 _in_location_0;
out vec4 _out_location_0;
void main() {
vec4 _expr9 = texture(_group_0_binding_0, vec2(_location_0_vs));
if((_expr9[3] == 0.0)) {
vec2 uv2 = _in_location_0;
vec4 _expr4 = texture(_group_0_binding_0, vec2(uv2));
if((_expr4[3] == 0.0)) {
discard;
}
_location_0 = (_expr9[3] * _expr9);
_out_location_0 = (_expr4[3] * _expr4);
return;
}

View File

@@ -6,14 +6,24 @@ expression: string
precision highp float;
in vec2 _location_0;
struct VertexOutput {
vec2 uv;
vec4 position;
};
in vec2 _location_1;
out vec2 _location_0_vs;
in vec2 _in_location_0;
in vec2 _in_location_1;
out vec2 _out_location_0;
void main() {
_location_0_vs = _location_1;
gl_Position = vec4((1.2 * _location_0), 0.0, 1.0);
vec2 pos = _in_location_0;
vec2 uv1 = _in_location_1;
VertexOutput out1;
out1.uv = uv1;
out1.position = vec4((1.2 * pos), 0.0, 1.0);
_out_location_0 = out1.uv;
gl_Position = out1.position;
return;
}

View File

@@ -5,95 +5,81 @@ expression: string
digraph Module {
subgraph cluster_globals {
label="Globals"
g0 [ shape=hexagon label="[1] Input/'a_pos'" ]
g1 [ shape=hexagon label="[2] Input/'a_uv'" ]
g2 [ shape=hexagon label="[3] Output/'v_uv'" ]
g3 [ shape=hexagon label="[4] Output/'o_position'" ]
g4 [ shape=hexagon label="[5] Input/'v_uv'" ]
g5 [ shape=hexagon label="[6] Handle/'u_texture'" ]
g6 [ shape=hexagon label="[7] Handle/'u_sampler'" ]
g7 [ shape=hexagon label="[8] Output/'o_color'" ]
g0 [ shape=hexagon label="[1] Handle/'u_texture'" ]
g1 [ shape=hexagon label="[2] Handle/'u_sampler'" ]
}
subgraph cluster_ep0 {
label="Vertex/'main'"
node [ style=filled ]
ep0_l0 [ shape=hexagon label="[1] 'out'" ]
ep0_e0 [ color="#ffffb3" label="[1] Constant" ]
ep0_e1 [ color="#ffffb3" label="[2] Global" ]
g0 -> ep0_e1 [color=gray]
ep0_e2 [ color="#ffffb3" label="[3] Global" ]
g2 -> ep0_e2 [color=gray]
ep0_e3 [ color="#ffffb3" label="[4] Global" ]
g3 -> ep0_e3 [color=gray]
ep0_e4 [ color="#ffffb3" label="[5] Global" ]
g1 -> ep0_e4 [color=gray]
ep0_e5 [ color="#fb8072" label="[6] Load" ]
ep0_e4 -> ep0_e5 [ label="pointer" ]
ep0_e6 [ color="#fb8072" label="[7] Load" ]
ep0_e1 -> ep0_e6 [ label="pointer" ]
ep0_e7 [ color="#fdb462" label="[8] Multiply" ]
ep0_e6 -> ep0_e7 [ label="right" ]
ep0_e0 -> ep0_e7 [ label="left" ]
ep0_e1 [ color="#8dd3c7" label="[2] Argument[0]" ]
ep0_e2 [ color="#8dd3c7" label="[3] Argument[1]" ]
ep0_e3 [ color="#8dd3c7" label="[4] Local" ]
ep0_l0 -> ep0_e3
ep0_e4 [ color="#8dd3c7" label="[5] AccessIndex[0]" ]
ep0_e3 -> ep0_e4 [ label="base" ]
ep0_e5 [ color="#8dd3c7" label="[6] AccessIndex[1]" ]
ep0_e3 -> ep0_e5 [ label="base" ]
ep0_e6 [ color="#fdb462" label="[7] Multiply" ]
ep0_e1 -> ep0_e6 [ label="right" ]
ep0_e0 -> ep0_e6 [ label="left" ]
ep0_e7 [ color="#ffffb3" label="[8] Constant" ]
ep0_e8 [ color="#ffffb3" label="[9] Constant" ]
ep0_e9 [ color="#ffffb3" label="[10] Constant" ]
ep0_e10 [ color="#bebada" label="[11] Compose" ]
{ ep0_e7 ep0_e8 ep0_e9 } -> ep0_e10
ep0_e9 [ color="#bebada" label="[10] Compose" ]
{ ep0_e6 ep0_e7 ep0_e8 } -> ep0_e9
ep0_e10 [ color="#fb8072" label="[11] Load" ]
ep0_e3 -> ep0_e10 [ label="pointer" ]
ep0_s0 [ shape=square label="Root" ]
ep0_s1 [ shape=square label="Emit" ]
ep0_s2 [ shape=square label="Store" ]
ep0_s3 [ shape=square label="Emit" ]
ep0_s4 [ shape=square label="Emit" ]
ep0_s5 [ shape=square label="Store" ]
ep0_s6 [ shape=square label="Return" ]
ep0_s6 [ shape=square label="Emit" ]
ep0_s7 [ shape=square label="Return" ]
ep0_s0 -> ep0_s1 [ arrowhead=tee label="" ]
ep0_s1 -> ep0_s2 [ arrowhead=tee label="" ]
ep0_s2 -> ep0_s3 [ arrowhead=tee label="" ]
ep0_s3 -> ep0_s4 [ arrowhead=tee label="" ]
ep0_s4 -> ep0_s5 [ arrowhead=tee label="" ]
ep0_s5 -> ep0_s6 [ arrowhead=tee label="" ]
ep0_e5 -> ep0_s2 [ label="value" ]
ep0_e10 -> ep0_s5 [ label="value" ]
ep0_s1 -> ep0_e5 [ style=dotted ]
ep0_s2 -> ep0_e2 [ style=dotted ]
ep0_s6 -> ep0_s7 [ arrowhead=tee label="" ]
ep0_e2 -> ep0_s2 [ label="value" ]
ep0_e9 -> ep0_s5 [ label="value" ]
ep0_e10 -> ep0_s7 [ label="value" ]
ep0_s1 -> ep0_e4 [ style=dotted ]
ep0_s2 -> ep0_e4 [ style=dotted ]
ep0_s3 -> ep0_e5 [ style=dotted ]
ep0_s3 -> ep0_e6 [ style=dotted ]
ep0_s3 -> ep0_e7 [ style=dotted ]
ep0_s4 -> ep0_e10 [ style=dotted ]
ep0_s5 -> ep0_e3 [ style=dotted ]
ep0_s4 -> ep0_e9 [ style=dotted ]
ep0_s5 -> ep0_e5 [ style=dotted ]
ep0_s6 -> ep0_e10 [ style=dotted ]
}
subgraph cluster_ep1 {
label="Fragment/'main'"
node [ style=filled ]
ep1_e0 [ color="#ffffb3" label="[1] Global" ]
g3 -> ep1_e0 [color=gray]
ep1_e0 [ color="#ffffb3" label="[1] Constant" ]
ep1_e1 [ color="#ffffb3" label="[2] Global" ]
g6 -> ep1_e1 [color=gray]
g1 -> ep1_e1 [color=gray]
ep1_e2 [ color="#ffffb3" label="[3] Global" ]
g5 -> ep1_e2 [color=gray]
ep1_e3 [ color="#ffffb3" label="[4] Constant" ]
ep1_e4 [ color="#ffffb3" label="[5] Global" ]
g0 -> ep1_e4 [color=gray]
ep1_e5 [ color="#ffffb3" label="[6] Global" ]
g4 -> ep1_e5 [color=gray]
ep1_e6 [ color="#ffffb3" label="[7] Global" ]
g1 -> ep1_e6 [color=gray]
ep1_e7 [ color="#ffffb3" label="[8] Global" ]
g7 -> ep1_e7 [color=gray]
ep1_e8 [ color="#fb8072" label="[9] Load" ]
ep1_e5 -> ep1_e8 [ label="pointer" ]
ep1_e9 [ color="#80b1d3" label="[10] ImageSample" ]
ep1_e1 -> ep1_e9 [ label="sampler" ]
ep1_e2 -> ep1_e9 [ label="image" ]
ep1_e8 -> ep1_e9 [ label="coordinate" ]
ep1_e10 [ color="#8dd3c7" label="[11] AccessIndex[3]" ]
ep1_e9 -> ep1_e10 [ label="base" ]
ep1_e11 [ color="#ffffb3" label="[12] Constant" ]
ep1_e12 [ color="#fdb462" label="[13] Equal" ]
ep1_e11 -> ep1_e12 [ label="right" ]
ep1_e10 -> ep1_e12 [ label="left" ]
ep1_e13 [ color="#8dd3c7" label="[14] AccessIndex[3]" ]
ep1_e9 -> ep1_e13 [ label="base" ]
ep1_e14 [ color="#fdb462" label="[15] Multiply" ]
ep1_e9 -> ep1_e14 [ label="right" ]
ep1_e13 -> ep1_e14 [ label="left" ]
g0 -> ep1_e2 [color=gray]
ep1_e3 [ color="#8dd3c7" label="[4] Argument[0]" ]
ep1_e4 [ color="#80b1d3" label="[5] ImageSample" ]
ep1_e1 -> ep1_e4 [ label="sampler" ]
ep1_e2 -> ep1_e4 [ label="image" ]
ep1_e3 -> ep1_e4 [ label="coordinate" ]
ep1_e5 [ color="#8dd3c7" label="[6] AccessIndex[3]" ]
ep1_e4 -> ep1_e5 [ label="base" ]
ep1_e6 [ color="#ffffb3" label="[7] Constant" ]
ep1_e7 [ color="#fdb462" label="[8] Equal" ]
ep1_e6 -> ep1_e7 [ label="right" ]
ep1_e5 -> ep1_e7 [ label="left" ]
ep1_e8 [ color="#8dd3c7" label="[9] AccessIndex[3]" ]
ep1_e4 -> ep1_e8 [ label="base" ]
ep1_e9 [ color="#fdb462" label="[10] Multiply" ]
ep1_e4 -> ep1_e9 [ label="right" ]
ep1_e8 -> ep1_e9 [ label="left" ]
ep1_s0 [ shape=square label="Root" ]
ep1_s1 [ shape=square label="Emit" ]
ep1_s2 [ shape=square label="Emit" ]
@@ -103,8 +89,7 @@ digraph Module {
ep1_s6 [ shape=square label="Kill" ]
ep1_s7 [ shape=square label="Node" ]
ep1_s8 [ shape=square label="Emit" ]
ep1_s9 [ shape=square label="Store" ]
ep1_s10 [ shape=square label="Return" ]
ep1_s9 [ shape=square label="Return" ]
ep1_s0 -> ep1_s1 [ arrowhead=tee label="" ]
ep1_s1 -> ep1_s2 [ arrowhead=tee label="" ]
ep1_s2 -> ep1_s3 [ arrowhead=tee label="" ]
@@ -114,16 +99,13 @@ digraph Module {
ep1_s4 -> ep1_s7 [ arrowhead=tee label="reject" ]
ep1_s7 -> ep1_s8 [ arrowhead=tee label="" ]
ep1_s8 -> ep1_s9 [ arrowhead=tee label="" ]
ep1_s9 -> ep1_s10 [ arrowhead=tee label="" ]
ep1_e12 -> ep1_s4 [ label="condition" ]
ep1_e14 -> ep1_s9 [ label="value" ]
ep1_s1 -> ep1_e8 [ style=dotted ]
ep1_s1 -> ep1_e9 [ style=dotted ]
ep1_s2 -> ep1_e10 [ style=dotted ]
ep1_s3 -> ep1_e12 [ style=dotted ]
ep1_s8 -> ep1_e13 [ style=dotted ]
ep1_s8 -> ep1_e14 [ style=dotted ]
ep1_s9 -> ep1_e7 [ style=dotted ]
ep1_e7 -> ep1_s4 [ label="condition" ]
ep1_e9 -> ep1_s9 [ label="value" ]
ep1_s1 -> ep1_e4 [ style=dotted ]
ep1_s2 -> ep1_e5 [ style=dotted ]
ep1_s3 -> ep1_e7 [ style=dotted ]
ep1_s8 -> ep1_e8 [ style=dotted ]
ep1_s8 -> ep1_e9 [ style=dotted ]
}
}

View File

@@ -11,6 +11,11 @@ typedef metal::float2 type1;
typedef metal::float4 type2;
struct VertexOutput {
type1 uv;
type2 position;
};
typedef metal::texture2d<float, metal::access::sample> type3;
typedef metal::sampler type4;
@@ -19,43 +24,41 @@ constexpr constant float c_scale = 1.2;
constexpr constant float const_0f = 0.0;
constexpr constant float const_1f = 1.0;
struct main1Input {
type1 a_pos [[attribute(0)]];
type1 a_uv [[attribute(1)]];
type1 pos [[attribute(0)]];
type1 uv1 [[attribute(1)]];
};
struct main1Output {
type1 v_uv [[user(loc0)]];
type2 o_position [[position]];
type1 uv [[user(loc0)]];
type2 position [[position]];
};
vertex main1Output main1(
main1Input input [[stage_in]]
main1Input varyings [[stage_in]]
) {
main1Output output;
output.v_uv = input.a_uv;
output.o_position = metal::float4((c_scale * input.a_pos), const_0f, const_1f);
return output;
const auto pos = varyings.pos;
const auto uv1 = varyings.uv1;
VertexOutput out;
out.uv = uv1;
out.position = metal::float4((c_scale * pos), const_0f, const_1f);
const auto _tmp = out;
return main1Output { _tmp.uv, _tmp.position };
}
struct main2Input {
type1 v_uv1 [[user(loc0)]];
type1 uv2 [[user(loc0)]];
};
struct main2Output {
type2 o_color [[color(0)]];
type2 member1 [[color(0)]];
};
fragment main2Output main2(
main2Input input [[stage_in]],
type3 u_texture [[texture(0)]],
type4 u_sampler [[sampler(0)]]
main2Input varyings1 [[stage_in]]
, type3 u_texture [[texture(0)]]
, type4 u_sampler [[sampler(0)]]
) {
main2Output output;
metal::float4 _expr9 = u_texture.sample(u_sampler, input.v_uv1);
if ((_expr9.w == const_0f)) {
const auto uv2 = varyings1.uv2;
metal::float4 _expr4 = u_texture.sample(u_sampler, uv2);
if ((_expr4.w == const_0f)) {
metal::discard_fragment();
}
output.o_color = (_expr9.w * _expr9);
return output;
return main2Output { (_expr4.w * _expr4) };
}

View File

@@ -5,92 +5,108 @@ expression: dis
; SPIR-V
; Version: 1.0
; Generator: rspirv
; Bound: 48
; Bound: 61
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %24 "main" %7 %10 %11 %13
OpEntryPoint Fragment %32 "main" %16 %23
OpExecutionMode %32 OriginUpperLeft
OpEntryPoint Vertex %28 "main" %19 %22 %24 %26
OpEntryPoint Fragment %47 "main" %44 %46
OpExecutionMode %47 OriginUpperLeft
OpSource GLSL 450
OpName %3 "c_scale"
OpName %7 "a_pos"
OpName %10 "a_uv"
OpName %11 "v_uv"
OpName %13 "o_position"
OpName %16 "v_uv"
OpName %17 "u_texture"
OpName %20 "u_sampler"
OpName %23 "o_color"
OpName %24 "main"
OpName %24 "main"
OpName %32 "main"
OpName %32 "main"
OpDecorate %7 Location 0
OpDecorate %10 Location 1
OpDecorate %11 Location 0
OpDecorate %13 BuiltIn Position
OpDecorate %16 Location 0
OpDecorate %17 DescriptorSet 0
OpDecorate %17 Binding 0
OpDecorate %20 DescriptorSet 0
OpDecorate %20 Binding 1
OpDecorate %23 Location 0
OpName %7 "u_texture"
OpName %10 "u_sampler"
OpName %13 "out"
OpName %14 "VertexOutput"
OpName %19 "pos"
OpName %22 "uv"
OpName %24 "uv"
OpName %26 "position"
OpName %28 "main"
OpName %28 "main"
OpName %44 "uv"
OpName %47 "main"
OpName %47 "main"
OpDecorate %7 DescriptorSet 0
OpDecorate %7 Binding 0
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 1
OpDecorate %19 Location 0
OpDecorate %22 Location 1
OpDecorate %24 Location 0
OpDecorate %26 BuiltIn Position
OpDecorate %44 Location 0
OpDecorate %46 Location 0
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%3 = OpConstant %4 1.2
%5 = OpConstant %4 0.0
%6 = OpConstant %4 1.0
%8 = OpTypeVector %4 2
%9 = OpTypePointer Input %8
%7 = OpVariable %9 Input
%10 = OpVariable %9 Input
%12 = OpTypePointer Output %8
%11 = OpVariable %12 Output
%14 = OpTypeVector %4 4
%15 = OpTypePointer Output %14
%13 = OpVariable %15 Output
%16 = OpVariable %9 Input
%18 = OpTypeImage %4 2D 0 0 0 1 Unknown
%19 = OpTypePointer UniformConstant %18
%17 = OpVariable %19 UniformConstant
%21 = OpTypeSampler
%22 = OpTypePointer UniformConstant %21
%20 = OpVariable %22 UniformConstant
%23 = OpVariable %15 Output
%25 = OpTypeFunction %2
%38 = OpTypeSampledImage %18
%42 = OpTypeBool
%24 = OpFunction %2 None %25
%26 = OpLabel
OpBranch %27
%27 = OpLabel
%28 = OpLoad %8 %10
OpStore %11 %28
%29 = OpLoad %8 %7
%30 = OpVectorTimesScalar %8 %29 %3
%31 = OpCompositeConstruct %14 %30 %5 %6
OpStore %13 %31
%8 = OpTypeImage %4 2D 0 0 0 1 Unknown
%9 = OpTypePointer UniformConstant %8
%7 = OpVariable %9 UniformConstant
%11 = OpTypeSampler
%12 = OpTypePointer UniformConstant %11
%10 = OpVariable %12 UniformConstant
%15 = OpTypeVector %4 2
%16 = OpTypeVector %4 4
%14 = OpTypeStruct %15 %16
%17 = OpTypePointer Function %14
%20 = OpTypePointer Input %15
%19 = OpVariable %20 Input
%22 = OpVariable %20 Input
%25 = OpTypePointer Output %15
%24 = OpVariable %25 Output
%27 = OpTypePointer Output %16
%26 = OpVariable %27 Output
%29 = OpTypeFunction %2
%31 = OpTypePointer Function %15
%32 = OpTypeInt 32 1
%33 = OpConstant %32 0
%35 = OpTypePointer Function %16
%38 = OpConstant %32 1
%44 = OpVariable %20 Input
%46 = OpVariable %27 Output
%51 = OpTypeSampledImage %8
%55 = OpTypeBool
%28 = OpFunction %2 None %29
%18 = OpLabel
%13 = OpVariable %17 Function
%21 = OpLoad %15 %19
%23 = OpLoad %15 %22
OpBranch %30
%30 = OpLabel
%34 = OpAccessChain %31 %13 %33
OpStore %34 %23
%36 = OpVectorTimesScalar %15 %21 %3
%37 = OpCompositeConstruct %16 %36 %5 %6
%39 = OpAccessChain %35 %13 %38
OpStore %39 %37
%40 = OpLoad %14 %13
%41 = OpCompositeExtract %15 %40 0
OpStore %24 %41
%42 = OpCompositeExtract %16 %40 1
OpStore %26 %42
OpReturn
OpFunctionEnd
%32 = OpFunction %2 None %25
%33 = OpLabel
%34 = OpLoad %18 %17
%35 = OpLoad %21 %20
OpBranch %36
%36 = OpLabel
%37 = OpLoad %8 %16
%39 = OpSampledImage %38 %34 %35
%40 = OpImageSampleImplicitLod %14 %39 %37
%41 = OpCompositeExtract %4 %40 3
%43 = OpFOrdEqual %42 %41 %5
OpSelectionMerge %44 None
OpBranchConditional %43 %45 %44
%45 = OpLabel
%47 = OpFunction %2 None %29
%43 = OpLabel
%45 = OpLoad %15 %44
%48 = OpLoad %8 %7
%49 = OpLoad %11 %10
OpBranch %50
%50 = OpLabel
%52 = OpSampledImage %51 %48 %49
%53 = OpImageSampleImplicitLod %16 %52 %45
%54 = OpCompositeExtract %4 %53 3
%56 = OpFOrdEqual %55 %54 %5
OpSelectionMerge %57 None
OpBranchConditional %56 %58 %57
%58 = OpLabel
OpKill
%44 = OpLabel
%46 = OpCompositeExtract %4 %40 3
%47 = OpVectorTimesScalar %14 %40 %46
OpStore %23 %47
%57 = OpLabel
%59 = OpCompositeExtract %4 %53 3
%60 = OpVectorTimesScalar %16 %53 %59
OpStore %46 %60
OpReturn
OpFunctionEnd

View File

@@ -22,11 +22,9 @@ readonly buffer Lights_block_1 {
uniform highp sampler2DArrayShadow _group_0_binding_2;
in vec3 _location_0_vs;
in vec4 _location_1_vs;
out vec4 _location_0;
in vec3 _in_location_0;
in vec4 _in_location_1;
out vec4 _out_location_0;
float fetch_shadow(uint light_id, vec4 homogeneous_coords) {
if((homogeneous_coords[3] <= 0.0)) {
@@ -38,19 +36,20 @@ float fetch_shadow(uint light_id, vec4 homogeneous_coords) {
}
void main() {
vec3 raw_normal = _in_location_0;
vec4 position = _in_location_1;
vec3 color1 = vec3(0.05, 0.05, 0.05);
uint i = 0u;
while(true) {
if((i >= min(_group_0_binding_0.num_lights[0], 10u))) {
break;
}
Light _expr23 = _group_0_binding_1.data[i];
float _expr28 = fetch_shadow(i, (_expr23.proj * _location_1_vs));
vec4 _expr34 = _location_1_vs;
color1 = (color1 + ((_expr28 * max(0.0, dot(normalize(_location_0_vs), normalize((vec3(_expr23.pos[0], _expr23.pos[1], _expr23.pos[2]) - vec3(_expr34[0], _expr34[1], _expr34[2])))))) * vec3(_expr23.color[0], _expr23.color[1], _expr23.color[2])));
Light _expr21 = _group_0_binding_1.data[i];
float _expr25 = fetch_shadow(i, (_expr21.proj * position));
color1 = (color1 + ((_expr25 * max(0.0, dot(normalize(raw_normal), normalize((vec3(_expr21.pos[0], _expr21.pos[1], _expr21.pos[2]) - vec3(position[0], position[1], position[2])))))) * vec3(_expr21.color[0], _expr21.color[1], _expr21.color[2])));
i = (i + 1u);
}
_location_0 = vec4(color1, 1.0);
_out_location_0 = vec4(color1, 1.0);
return;
}

View File

@@ -610,8 +610,6 @@ expression: output
),
],
),
],
entry_points: [
(
uniformity: (
non_uniform_result: Some(44),
@@ -1595,4 +1593,92 @@ expression: output
],
),
],
entry_points: [
(
uniformity: (
non_uniform_result: Some(44),
requirement: None,
),
may_kill: false,
sampling_set: [
(
image: 1,
sampler: 2,
),
],
global_uses: [
(
bits: 1,
),
(
bits: 1,
),
(
bits: 1,
),
(
bits: 1,
),
(
bits: 3,
),
(
bits: 3,
),
(
bits: 3,
),
],
expressions: [
(
uniformity: (
non_uniform_result: Some(1),
requirement: None,
),
ref_count: 1,
assignable_global: Some(6),
),
(
uniformity: (
non_uniform_result: Some(2),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
uniformity: (
non_uniform_result: Some(3),
requirement: None,
),
ref_count: 1,
assignable_global: Some(5),
),
(
uniformity: (
non_uniform_result: Some(4),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
(
uniformity: (
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,
assignable_global: Some(7),
),
(
uniformity: (
non_uniform_result: Some(5),
requirement: None,
),
ref_count: 1,
assignable_global: None,
),
],
),
],
)

View File

@@ -63,22 +63,21 @@ type7 fetch_shadow(
}
struct fs_mainInput {
type9 in_normal_fs [[user(loc0)]];
type2 in_position_fs [[user(loc1)]];
type9 raw_normal [[user(loc0)]];
type2 position [[user(loc1)]];
};
struct fs_mainOutput {
type2 out_color_fs [[color(0)]];
type2 member [[color(0)]];
};
fragment fs_mainOutput fs_main(
fs_mainInput input [[stage_in]],
constant Globals& u_globals [[buffer(0)]],
constant Lights& s_lights [[buffer(1)]],
type4 t_shadow [[texture(0)]],
type5 sampler_shadow [[sampler(0)]]
fs_mainInput varyings [[stage_in]]
, constant Globals& u_globals [[buffer(0)]]
, constant Lights& s_lights [[buffer(1)]]
, type4 t_shadow [[texture(0)]]
, type5 sampler_shadow [[sampler(0)]]
) {
fs_mainOutput output;
const auto raw_normal = varyings.raw_normal;
const auto position = varyings.position;
type9 color1 = c_ambient;
type6 i = const_0u;
bool loop_init = true;
@@ -90,12 +89,10 @@ fragment fs_mainOutput fs_main(
if ((i >= metal::min(u_globals.num_lights.x, c_max_lights))) {
break;
}
Light _expr23 = s_lights.data[i];
type7 _expr28 = fetch_shadow(i, (_expr23.proj * input.in_position_fs), t_shadow, sampler_shadow);
type2 _expr34 = input.in_position_fs;
color1 = (color1 + ((_expr28 * metal::max(const_0f, metal::dot(metal::normalize(input.in_normal_fs), metal::normalize((metal::float3(_expr23.pos.x, _expr23.pos.y, _expr23.pos.z) - metal::float3(_expr34.x, _expr34.y, _expr34.z)))))) * metal::float3(_expr23.color.x, _expr23.color.y, _expr23.color.z)));
Light _expr21 = s_lights.data[i];
type7 _expr25 = fetch_shadow(i, (_expr21.proj * position), t_shadow, sampler_shadow);
color1 = (color1 + ((_expr25 * metal::max(const_0f, metal::dot(metal::normalize(raw_normal), metal::normalize((metal::float3(_expr21.pos.x, _expr21.pos.y, _expr21.pos.z) - metal::float3(position.x, position.y, position.z)))))) * metal::float3(_expr21.color.x, _expr21.color.y, _expr21.color.z)));
}
output.out_color_fs = metal::float4(color1, const_1f);
return output;
return fs_mainOutput { metal::float4(color1, const_1f) };
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,12 +5,12 @@ expression: dis
; SPIR-V
; Version: 1.2
; Generator: rspirv
; Bound: 138
; Bound: 137
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %78 "fs_main" %32 %34 %36
OpExecutionMode %78 OriginUpperLeft
OpEntryPoint Fragment %81 "fs_main" %73 %76 %79
OpExecutionMode %81 OriginUpperLeft
OpSource GLSL 450
OpName %9 "c_ambient"
OpName %11 "c_max_lights"
@@ -26,14 +26,13 @@ OpMemberName %22 2 "color"
OpName %19 "s_lights"
OpName %26 "t_shadow"
OpName %29 "sampler_shadow"
OpName %32 "in_normal_fs"
OpName %34 "in_position_fs"
OpName %36 "out_color_fs"
OpName %40 "fetch_shadow"
OpName %74 "color"
OpName %76 "i"
OpName %78 "fs_main"
OpName %78 "fs_main"
OpName %35 "fetch_shadow"
OpName %68 "color"
OpName %70 "i"
OpName %73 "raw_normal"
OpName %76 "position"
OpName %81 "fs_main"
OpName %81 "fs_main"
OpDecorate %16 Block
OpMemberDecorate %16 0 Offset 0
OpDecorate %15 DescriptorSet 0
@@ -53,9 +52,9 @@ OpDecorate %26 DescriptorSet 0
OpDecorate %26 Binding 2
OpDecorate %29 DescriptorSet 0
OpDecorate %29 Binding 3
OpDecorate %32 Location 0
OpDecorate %34 Location 1
OpDecorate %36 Location 0
OpDecorate %73 Location 0
OpDecorate %76 Location 1
OpDecorate %79 Location 0
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%3 = OpConstant %4 0.0
@@ -86,129 +85,128 @@ OpDecorate %36 Location 0
%30 = OpTypeSampler
%31 = OpTypePointer UniformConstant %30
%29 = OpVariable %31 UniformConstant
%33 = OpTypePointer Input %10
%32 = OpVariable %33 Input
%35 = OpTypePointer Input %24
%34 = OpVariable %35 Input
%37 = OpTypePointer Output %24
%36 = OpVariable %37 Output
%41 = OpTypeFunction %4 %12 %24
%47 = OpTypeBool
%51 = OpTypeVector %4 2
%62 = OpTypeInt 32 1
%66 = OpTypeSampledImage %27
%73 = OpConstant %4 0.0
%75 = OpTypePointer Function %10
%77 = OpTypePointer Function %12
%79 = OpTypeFunction %2
%91 = OpTypePointer Uniform %17
%92 = OpConstant %62 0
%100 = OpTypePointer Uniform %21
%102 = OpTypePointer Uniform %22
%103 = OpConstant %62 0
%40 = OpFunction %4 None %41
%38 = OpFunctionParameter %12
%39 = OpFunctionParameter %24
%42 = OpLabel
%43 = OpLoad %27 %26
%44 = OpLoad %30 %29
OpBranch %45
%45 = OpLabel
%46 = OpCompositeExtract %4 %39 3
%48 = OpFOrdLessThanEqual %47 %46 %3
OpSelectionMerge %49 None
OpBranchConditional %48 %50 %49
%50 = OpLabel
%36 = OpTypeFunction %4 %12 %24
%41 = OpTypeBool
%45 = OpTypeVector %4 2
%56 = OpTypeInt 32 1
%60 = OpTypeSampledImage %27
%67 = OpConstant %4 0.0
%69 = OpTypePointer Function %10
%71 = OpTypePointer Function %12
%74 = OpTypePointer Input %10
%73 = OpVariable %74 Input
%77 = OpTypePointer Input %24
%76 = OpVariable %77 Input
%80 = OpTypePointer Output %24
%79 = OpVariable %80 Output
%82 = OpTypeFunction %2
%92 = OpTypePointer Uniform %17
%93 = OpConstant %56 0
%101 = OpTypePointer Uniform %21
%103 = OpTypePointer Uniform %22
%104 = OpConstant %56 0
%35 = OpFunction %4 None %36
%33 = OpFunctionParameter %12
%34 = OpFunctionParameter %24
%32 = OpLabel
%37 = OpLoad %27 %26
%38 = OpLoad %30 %29
OpBranch %39
%39 = OpLabel
%40 = OpCompositeExtract %4 %34 3
%42 = OpFOrdLessThanEqual %41 %40 %3
OpSelectionMerge %43 None
OpBranchConditional %42 %44 %43
%44 = OpLabel
OpReturnValue %5
%49 = OpLabel
%52 = OpCompositeConstruct %51 %6 %7
%53 = OpCompositeExtract %4 %39 3
%54 = OpFDiv %4 %5 %53
%55 = OpCompositeExtract %4 %39 0
%56 = OpCompositeExtract %4 %39 1
%57 = OpCompositeConstruct %51 %55 %56
%58 = OpFMul %51 %57 %52
%59 = OpVectorTimesScalar %51 %58 %54
%60 = OpCompositeConstruct %51 %6 %6
%61 = OpFAdd %51 %59 %60
%63 = OpBitcast %62 %38
%64 = OpCompositeExtract %4 %39 2
%65 = OpFMul %4 %64 %54
%67 = OpCompositeExtract %4 %61 0
%68 = OpCompositeExtract %4 %61 1
%69 = OpConvertUToF %4 %63
%70 = OpCompositeConstruct %10 %67 %68 %69
%71 = OpSampledImage %66 %43 %44
%72 = OpImageSampleDrefExplicitLod %4 %71 %70 %65 Lod %73
OpReturnValue %72
%43 = OpLabel
%46 = OpCompositeConstruct %45 %6 %7
%47 = OpCompositeExtract %4 %34 3
%48 = OpFDiv %4 %5 %47
%49 = OpCompositeExtract %4 %34 0
%50 = OpCompositeExtract %4 %34 1
%51 = OpCompositeConstruct %45 %49 %50
%52 = OpFMul %45 %51 %46
%53 = OpVectorTimesScalar %45 %52 %48
%54 = OpCompositeConstruct %45 %6 %6
%55 = OpFAdd %45 %53 %54
%57 = OpBitcast %56 %33
%58 = OpCompositeExtract %4 %34 2
%59 = OpFMul %4 %58 %48
%61 = OpCompositeExtract %4 %55 0
%62 = OpCompositeExtract %4 %55 1
%63 = OpConvertUToF %4 %57
%64 = OpCompositeConstruct %10 %61 %62 %63
%65 = OpSampledImage %60 %37 %38
%66 = OpImageSampleDrefExplicitLod %4 %65 %64 %59 Lod %67
OpReturnValue %66
OpFunctionEnd
%78 = OpFunction %2 None %79
%80 = OpLabel
%74 = OpVariable %75 Function %9
%76 = OpVariable %77 Function %13
%81 = OpLoad %27 %26
%82 = OpLoad %30 %29
OpBranch %83
%83 = OpLabel
%84 = OpLoad %10 %32
%85 = OpExtInst %10 %1 Normalize %84
OpBranch %86
%86 = OpLabel
OpLoopMerge %87 %89 None
OpBranch %88
%88 = OpLabel
%90 = OpLoad %12 %76
%93 = OpAccessChain %91 %15 %92
%94 = OpLoad %17 %93
%95 = OpCompositeExtract %12 %94 0
%96 = OpExtInst %12 %1 UMin %95 %11
%97 = OpUGreaterThanEqual %47 %90 %96
OpSelectionMerge %98 None
OpBranchConditional %97 %99 %98
%99 = OpLabel
%81 = OpFunction %2 None %82
%72 = OpLabel
%68 = OpVariable %69 Function %9
%70 = OpVariable %71 Function %13
%75 = OpLoad %10 %73
%78 = OpLoad %24 %76
%83 = OpLoad %27 %26
%84 = OpLoad %30 %29
OpBranch %85
%85 = OpLabel
%86 = OpExtInst %10 %1 Normalize %75
OpBranch %87
%98 = OpLabel
%101 = OpLoad %12 %76
%104 = OpAccessChain %102 %19 %103 %101
%105 = OpLoad %22 %104
%106 = OpLoad %12 %76
%107 = OpCompositeExtract %23 %105 0
%108 = OpLoad %24 %34
%109 = OpMatrixTimesVector %24 %107 %108
%110 = OpFunctionCall %4 %40 %106 %109
%111 = OpCompositeExtract %24 %105 1
%87 = OpLabel
OpLoopMerge %88 %90 None
OpBranch %89
%89 = OpLabel
%91 = OpLoad %12 %70
%94 = OpAccessChain %92 %15 %93
%95 = OpLoad %17 %94
%96 = OpCompositeExtract %12 %95 0
%97 = OpExtInst %12 %1 UMin %96 %11
%98 = OpUGreaterThanEqual %41 %91 %97
OpSelectionMerge %99 None
OpBranchConditional %98 %100 %99
%100 = OpLabel
OpBranch %88
%99 = OpLabel
%102 = OpLoad %12 %70
%105 = OpAccessChain %103 %19 %104 %102
%106 = OpLoad %22 %105
%107 = OpLoad %12 %70
%108 = OpCompositeExtract %23 %106 0
%109 = OpMatrixTimesVector %24 %108 %78
%110 = OpFunctionCall %4 %35 %107 %109
%111 = OpCompositeExtract %24 %106 1
%112 = OpCompositeExtract %4 %111 0
%113 = OpCompositeExtract %4 %111 1
%114 = OpCompositeExtract %4 %111 2
%115 = OpCompositeConstruct %10 %112 %113 %114
%116 = OpLoad %24 %34
%117 = OpCompositeExtract %4 %116 0
%118 = OpCompositeExtract %4 %116 1
%119 = OpCompositeExtract %4 %116 2
%120 = OpCompositeConstruct %10 %117 %118 %119
%121 = OpFSub %10 %115 %120
%122 = OpExtInst %10 %1 Normalize %121
%123 = OpDot %4 %85 %122
%124 = OpExtInst %4 %1 FMax %3 %123
%125 = OpLoad %10 %74
%126 = OpFMul %4 %110 %124
%127 = OpCompositeExtract %24 %105 2
%128 = OpCompositeExtract %4 %127 0
%129 = OpCompositeExtract %4 %127 1
%130 = OpCompositeExtract %4 %127 2
%131 = OpCompositeConstruct %10 %128 %129 %130
%132 = OpVectorTimesScalar %10 %131 %126
%133 = OpFAdd %10 %125 %132
OpStore %74 %133
OpBranch %89
%89 = OpLabel
%134 = OpLoad %12 %76
%135 = OpIAdd %12 %134 %14
OpStore %76 %135
OpBranch %86
%87 = OpLabel
%136 = OpLoad %10 %74
%137 = OpCompositeConstruct %24 %136 %5
OpStore %36 %137
%116 = OpCompositeExtract %4 %78 0
%117 = OpCompositeExtract %4 %78 1
%118 = OpCompositeExtract %4 %78 2
%119 = OpCompositeConstruct %10 %116 %117 %118
%120 = OpFSub %10 %115 %119
%121 = OpExtInst %10 %1 Normalize %120
%122 = OpDot %4 %86 %121
%123 = OpExtInst %4 %1 FMax %3 %122
%124 = OpLoad %10 %68
%125 = OpFMul %4 %110 %123
%126 = OpCompositeExtract %24 %106 2
%127 = OpCompositeExtract %4 %126 0
%128 = OpCompositeExtract %4 %126 1
%129 = OpCompositeExtract %4 %126 2
%130 = OpCompositeConstruct %10 %127 %128 %129
%131 = OpVectorTimesScalar %10 %130 %125
%132 = OpFAdd %10 %124 %131
OpStore %68 %132
OpBranch %90
%90 = OpLabel
%133 = OpLoad %12 %70
%134 = OpIAdd %12 %133 %14
OpStore %70 %134
OpBranch %87
%88 = OpLabel
%135 = OpLoad %10 %68
%136 = OpCompositeConstruct %24 %135 %5
OpStore %79 %136
OpReturn
OpFunctionEnd

View File

@@ -6,15 +6,20 @@ expression: string
precision highp float;
struct VertexOutput {
vec4 position;
vec3 uv;
};
uniform highp samplerCube _group_0_binding_1;
in vec3 _location_0_vs;
out vec4 _location_0;
in vec3 _in_location_0;
out vec4 _out_location_0;
void main() {
vec4 _expr9 = texture(_group_0_binding_1, vec3(_location_0_vs));
_location_0 = _expr9;
vec3 uv1 = _in_location_0;
vec4 _expr4 = texture(_group_0_binding_1, vec3(uv1));
_out_location_0 = _expr4;
return;
}

View File

@@ -6,23 +6,34 @@ expression: string
precision highp float;
out vec3 _location_0_vs;
struct VertexOutput {
vec4 position;
vec3 uv;
};
uniform Data_block_0 {
mat4x4 proj_inv;
mat4x4 view;
} _group_0_binding_0;
out vec3 _out_location_0;
void main() {
uint vertex_index = uint(gl_VertexID);
int tmp1_;
int tmp2_;
vec4 unprojected;
tmp1_ = (int(gl_VertexID) / 2);
tmp2_ = (int(gl_VertexID) & 1);
vec4 _expr28 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0);
unprojected = (_group_0_binding_0.proj_inv * _expr28);
vec4 _expr56 = unprojected;
_location_0_vs = (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr56[0], _expr56[1], _expr56[2]));
gl_Position = _expr28;
VertexOutput out1;
tmp1_ = (int(vertex_index) / 2);
tmp2_ = (int(vertex_index) & 1);
vec4 _expr24 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0);
unprojected = (_group_0_binding_0.proj_inv * _expr24);
vec4 _expr54 = unprojected;
out1.uv = (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr54[0], _expr54[1], _expr54[2]));
out1.position = _expr24;
gl_Position = out1.position;
_out_location_0 = out1.uv;
return;
}

View File

@@ -9,15 +9,20 @@ typedef metal::float4 type;
typedef metal::float3 type1;
typedef uint type2;
struct VertexOutput {
type position;
type1 uv;
};
typedef metal::float4x4 type3;
typedef metal::float4x4 type2;
struct Data {
type3 proj_inv;
type3 view;
type2 proj_inv;
type2 view;
};
typedef uint type3;
typedef int type4;
typedef metal::float3x3 type5;
@@ -33,47 +38,42 @@ constexpr constant float const_1f = 1.0;
constexpr constant float const_0f = 0.0;
struct vs_mainInput {
};
struct vs_mainOutput {
type out_position [[position]];
type1 out_uv [[user(loc0)]];
type position [[position]];
type1 uv [[user(loc0)]];
};
vertex vs_mainOutput vs_main(
vs_mainInput input [[stage_in]],
type2 in_vertex_index [[vertex_id]],
constant Data& r_data [[buffer(0)]]
type3 vertex_index [[vertex_id]]
, constant Data& r_data [[buffer(0)]]
) {
vs_mainOutput output;
type4 tmp1_;
type4 tmp2_;
type unprojected;
tmp1_ = (static_cast<int>(in_vertex_index) / const_2i);
tmp2_ = (static_cast<int>(in_vertex_index) & const_1i);
type _expr28 = metal::float4(((static_cast<float>(tmp1_) * const_4f) - const_1f), ((static_cast<float>(tmp2_) * const_4f) - const_1f), const_0f, const_1f);
unprojected = (r_data.proj_inv * _expr28);
type _expr56 = unprojected;
output.out_uv = (metal::transpose(metal::float3x3(metal::float3(r_data.view[0].x, r_data.view[0].y, r_data.view[0].z), metal::float3(r_data.view[1].x, r_data.view[1].y, r_data.view[1].z), metal::float3(r_data.view[2].x, r_data.view[2].y, r_data.view[2].z))) * metal::float3(_expr56.x, _expr56.y, _expr56.z));
output.out_position = _expr28;
return output;
VertexOutput out;
tmp1_ = (static_cast<int>(vertex_index) / const_2i);
tmp2_ = (static_cast<int>(vertex_index) & const_1i);
type _expr24 = metal::float4(((static_cast<float>(tmp1_) * const_4f) - const_1f), ((static_cast<float>(tmp2_) * const_4f) - const_1f), const_0f, const_1f);
unprojected = (r_data.proj_inv * _expr24);
type _expr54 = unprojected;
out.uv = (metal::transpose(metal::float3x3(metal::float3(r_data.view[0].x, r_data.view[0].y, r_data.view[0].z), metal::float3(r_data.view[1].x, r_data.view[1].y, r_data.view[1].z), metal::float3(r_data.view[2].x, r_data.view[2].y, r_data.view[2].z))) * metal::float3(_expr54.x, _expr54.y, _expr54.z));
out.position = _expr24;
const auto _tmp = out;
return vs_mainOutput { _tmp.position, _tmp.uv };
}
struct fs_mainInput {
type1 in_uv [[user(loc0)]];
type1 uv1 [[user(loc0)]];
};
struct fs_mainOutput {
type out_color [[color(0)]];
type member1 [[color(0)]];
};
fragment fs_mainOutput fs_main(
fs_mainInput input [[stage_in]],
type6 r_texture [[texture(0)]],
type7 r_sampler [[sampler(1)]]
fs_mainInput varyings1 [[stage_in]]
, type6 r_texture [[texture(0)]]
, type7 r_sampler [[sampler(1)]]
) {
fs_mainOutput output;
metal::float4 _expr9 = r_texture.sample(r_sampler, input.in_uv);
output.out_color = _expr9;
return output;
const auto uv1 = varyings1.uv1;
metal::float4 _expr4 = r_texture.sample(r_sampler, uv1);
return fs_mainOutput { _expr4 };
}

View File

@@ -5,50 +5,51 @@ expression: dis
; SPIR-V
; Version: 1.0
; Generator: rspirv
; Bound: 103
; Bound: 113
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %37 "vs_main" %10 %13 %16
OpEntryPoint Fragment %94 "fs_main" %29 %31
OpExecutionMode %94 OriginUpperLeft
OpEntryPoint Vertex %39 "vs_main" %32 %35 %37
OpEntryPoint Fragment %106 "fs_main" %102 %105
OpExecutionMode %106 OriginUpperLeft
OpSource GLSL 450
OpName %10 "out_position"
OpName %13 "out_uv"
OpName %16 "in_vertex_index"
OpName %20 "Data"
OpMemberName %20 0 "proj_inv"
OpMemberName %20 1 "view"
OpName %19 "r_data"
OpName %23 "r_texture"
OpName %26 "r_sampler"
OpName %29 "in_uv"
OpName %31 "out_color"
OpName %32 "tmp1"
OpName %34 "tmp2"
OpName %35 "unprojected"
OpName %37 "vs_main"
OpName %37 "vs_main"
OpName %94 "fs_main"
OpName %94 "fs_main"
OpDecorate %10 BuiltIn Position
OpDecorate %13 Location 0
OpDecorate %16 BuiltIn VertexIndex
OpDecorate %20 Block
OpMemberDecorate %20 0 Offset 0
OpMemberDecorate %20 0 ColMajor
OpMemberDecorate %20 0 MatrixStride 16
OpMemberDecorate %20 1 Offset 64
OpMemberDecorate %20 1 ColMajor
OpMemberDecorate %20 1 MatrixStride 16
OpDecorate %19 DescriptorSet 0
OpDecorate %19 Binding 0
OpDecorate %23 DescriptorSet 0
OpDecorate %23 Binding 1
OpDecorate %26 DescriptorSet 0
OpDecorate %26 Binding 2
OpDecorate %29 Location 0
OpDecorate %31 Location 0
OpName %11 "Data"
OpMemberName %11 0 "proj_inv"
OpMemberName %11 1 "view"
OpName %10 "r_data"
OpName %15 "r_texture"
OpName %18 "r_sampler"
OpName %21 "tmp1"
OpName %23 "tmp2"
OpName %24 "unprojected"
OpName %26 "out"
OpName %27 "VertexOutput"
OpName %32 "vertex_index"
OpName %35 "position"
OpName %37 "uv"
OpName %39 "vs_main"
OpName %39 "vs_main"
OpName %102 "uv"
OpName %106 "fs_main"
OpName %106 "fs_main"
OpDecorate %11 Block
OpMemberDecorate %11 0 Offset 0
OpMemberDecorate %11 0 ColMajor
OpMemberDecorate %11 0 MatrixStride 16
OpMemberDecorate %11 1 Offset 64
OpMemberDecorate %11 1 ColMajor
OpMemberDecorate %11 1 MatrixStride 16
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 0
OpDecorate %15 DescriptorSet 0
OpDecorate %15 Binding 1
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 2
OpDecorate %32 BuiltIn VertexIndex
OpDecorate %35 BuiltIn Position
OpDecorate %37 Location 0
OpDecorate %102 Location 0
OpDecorate %105 Location 0
%2 = OpTypeVoid
%4 = OpTypeInt 32 1
%3 = OpConstant %4 2
@@ -57,108 +58,120 @@ OpDecorate %31 Location 0
%6 = OpConstant %7 4.0
%8 = OpConstant %7 1.0
%9 = OpConstant %7 0.0
%11 = OpTypeVector %7 4
%12 = OpTypePointer Output %11
%10 = OpVariable %12 Output
%14 = OpTypeVector %7 3
%15 = OpTypePointer Output %14
%13 = OpVariable %15 Output
%17 = OpTypeInt 32 0
%18 = OpTypePointer Input %17
%16 = OpVariable %18 Input
%21 = OpTypeMatrix %11 4
%20 = OpTypeStruct %21 %21
%22 = OpTypePointer Uniform %20
%19 = OpVariable %22 Uniform
%24 = OpTypeImage %7 Cube 0 0 0 1 Unknown
%25 = OpTypePointer UniformConstant %24
%23 = OpVariable %25 UniformConstant
%27 = OpTypeSampler
%28 = OpTypePointer UniformConstant %27
%26 = OpVariable %28 UniformConstant
%30 = OpTypePointer Input %14
%29 = OpVariable %30 Input
%31 = OpVariable %12 Output
%33 = OpTypePointer Function %4
%36 = OpTypePointer Function %11
%38 = OpTypeFunction %2
%56 = OpTypePointer Uniform %21
%57 = OpConstant %4 1
%65 = OpConstant %4 1
%73 = OpConstant %4 1
%81 = OpTypeMatrix %14 3
%84 = OpConstant %4 0
%100 = OpTypeSampledImage %24
%37 = OpFunction %2 None %38
%39 = OpLabel
%32 = OpVariable %33 Function
%34 = OpVariable %33 Function
%35 = OpVariable %36 Function
OpBranch %40
%40 = OpLabel
%41 = OpLoad %17 %16
%42 = OpBitcast %4 %41
%13 = OpTypeVector %7 4
%12 = OpTypeMatrix %13 4
%11 = OpTypeStruct %12 %12
%14 = OpTypePointer Uniform %11
%10 = OpVariable %14 Uniform
%16 = OpTypeImage %7 Cube 0 0 0 1 Unknown
%17 = OpTypePointer UniformConstant %16
%15 = OpVariable %17 UniformConstant
%19 = OpTypeSampler
%20 = OpTypePointer UniformConstant %19
%18 = OpVariable %20 UniformConstant
%22 = OpTypePointer Function %4
%25 = OpTypePointer Function %13
%28 = OpTypeVector %7 3
%27 = OpTypeStruct %13 %28
%29 = OpTypePointer Function %27
%31 = OpTypeInt 32 0
%33 = OpTypePointer Input %31
%32 = OpVariable %33 Input
%36 = OpTypePointer Output %13
%35 = OpVariable %36 Output
%38 = OpTypePointer Output %28
%37 = OpVariable %38 Output
%40 = OpTypeFunction %2
%55 = OpTypePointer Uniform %12
%56 = OpConstant %4 1
%64 = OpConstant %4 1
%72 = OpConstant %4 1
%80 = OpTypeMatrix %28 3
%83 = OpConstant %4 0
%87 = OpTypePointer Function %28
%94 = OpConstant %4 1
%96 = OpConstant %4 0
%103 = OpTypePointer Input %28
%102 = OpVariable %103 Input
%105 = OpVariable %36 Output
%110 = OpTypeSampledImage %16
%39 = OpFunction %2 None %40
%30 = OpLabel
%23 = OpVariable %22 Function
%26 = OpVariable %29 Function
%21 = OpVariable %22 Function
%24 = OpVariable %25 Function
%34 = OpLoad %31 %32
OpBranch %41
%41 = OpLabel
%42 = OpBitcast %4 %34
%43 = OpSDiv %4 %42 %3
OpStore %32 %43
%44 = OpLoad %17 %16
%45 = OpBitcast %4 %44
%46 = OpBitwiseAnd %4 %45 %5
OpStore %34 %46
%47 = OpLoad %4 %32
%48 = OpConvertSToF %7 %47
%49 = OpFMul %7 %48 %6
%50 = OpFSub %7 %49 %8
%51 = OpLoad %4 %34
%52 = OpConvertSToF %7 %51
%53 = OpFMul %7 %52 %6
%54 = OpFSub %7 %53 %8
%55 = OpCompositeConstruct %11 %50 %54 %9 %8
%58 = OpAccessChain %56 %19 %57
%59 = OpLoad %21 %58
%60 = OpCompositeExtract %11 %59 0
%61 = OpCompositeExtract %7 %60 0
%62 = OpCompositeExtract %7 %60 1
%63 = OpCompositeExtract %7 %60 2
%64 = OpCompositeConstruct %14 %61 %62 %63
%66 = OpAccessChain %56 %19 %65
%67 = OpLoad %21 %66
%68 = OpCompositeExtract %11 %67 1
%69 = OpCompositeExtract %7 %68 0
%70 = OpCompositeExtract %7 %68 1
%71 = OpCompositeExtract %7 %68 2
%72 = OpCompositeConstruct %14 %69 %70 %71
%74 = OpAccessChain %56 %19 %73
%75 = OpLoad %21 %74
%76 = OpCompositeExtract %11 %75 2
%77 = OpCompositeExtract %7 %76 0
%78 = OpCompositeExtract %7 %76 1
%79 = OpCompositeExtract %7 %76 2
%80 = OpCompositeConstruct %14 %77 %78 %79
%82 = OpCompositeConstruct %81 %64 %72 %80
%83 = OpTranspose %81 %82
%85 = OpAccessChain %56 %19 %84
%86 = OpLoad %21 %85
%87 = OpMatrixTimesVector %11 %86 %55
OpStore %35 %87
%88 = OpLoad %11 %35
OpStore %21 %43
%44 = OpBitcast %4 %34
%45 = OpBitwiseAnd %4 %44 %5
OpStore %23 %45
%46 = OpLoad %4 %21
%47 = OpConvertSToF %7 %46
%48 = OpFMul %7 %47 %6
%49 = OpFSub %7 %48 %8
%50 = OpLoad %4 %23
%51 = OpConvertSToF %7 %50
%52 = OpFMul %7 %51 %6
%53 = OpFSub %7 %52 %8
%54 = OpCompositeConstruct %13 %49 %53 %9 %8
%57 = OpAccessChain %55 %10 %56
%58 = OpLoad %12 %57
%59 = OpCompositeExtract %13 %58 0
%60 = OpCompositeExtract %7 %59 0
%61 = OpCompositeExtract %7 %59 1
%62 = OpCompositeExtract %7 %59 2
%63 = OpCompositeConstruct %28 %60 %61 %62
%65 = OpAccessChain %55 %10 %64
%66 = OpLoad %12 %65
%67 = OpCompositeExtract %13 %66 1
%68 = OpCompositeExtract %7 %67 0
%69 = OpCompositeExtract %7 %67 1
%70 = OpCompositeExtract %7 %67 2
%71 = OpCompositeConstruct %28 %68 %69 %70
%73 = OpAccessChain %55 %10 %72
%74 = OpLoad %12 %73
%75 = OpCompositeExtract %13 %74 2
%76 = OpCompositeExtract %7 %75 0
%77 = OpCompositeExtract %7 %75 1
%78 = OpCompositeExtract %7 %75 2
%79 = OpCompositeConstruct %28 %76 %77 %78
%81 = OpCompositeConstruct %80 %63 %71 %79
%82 = OpTranspose %80 %81
%84 = OpAccessChain %55 %10 %83
%85 = OpLoad %12 %84
%86 = OpMatrixTimesVector %13 %85 %54
OpStore %24 %86
%88 = OpLoad %13 %24
%89 = OpCompositeExtract %7 %88 0
%90 = OpCompositeExtract %7 %88 1
%91 = OpCompositeExtract %7 %88 2
%92 = OpCompositeConstruct %14 %89 %90 %91
%93 = OpMatrixTimesVector %14 %83 %92
OpStore %13 %93
OpStore %10 %55
%92 = OpCompositeConstruct %28 %89 %90 %91
%93 = OpMatrixTimesVector %28 %82 %92
%95 = OpAccessChain %87 %26 %94
OpStore %95 %93
%97 = OpAccessChain %25 %26 %96
OpStore %97 %54
%98 = OpLoad %27 %26
%99 = OpCompositeExtract %13 %98 0
OpStore %35 %99
%100 = OpCompositeExtract %28 %98 1
OpStore %37 %100
OpReturn
OpFunctionEnd
%94 = OpFunction %2 None %38
%95 = OpLabel
%96 = OpLoad %24 %23
%97 = OpLoad %27 %26
OpBranch %98
%98 = OpLabel
%99 = OpLoad %14 %29
%101 = OpSampledImage %100 %96 %97
%102 = OpImageSampleImplicitLod %11 %101 %99
OpStore %31 %102
%106 = OpFunction %2 None %40
%101 = OpLabel
%104 = OpLoad %28 %102
%107 = OpLoad %16 %15
%108 = OpLoad %19 %18
OpBranch %109
%109 = OpLabel
%111 = OpSampledImage %110 %107 %108
%112 = OpImageSampleImplicitLod %13 %111 %104
OpStore %105 %112
OpReturn
OpFunctionEnd

View File

@@ -5,83 +5,81 @@ expression: dis
; SPIR-V
; Version: 1.5
; Generator: rspirv
; Bound: 46
; Bound: 45
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %23 "main" %5 %20
OpExecutionMode %23 OriginUpperLeft
OpEntryPoint Fragment %25 "main" %19 %23
OpExecutionMode %25 OriginUpperLeft
OpSource GLSL 450
OpName %5 "tex_coord"
OpName %9 "texture0"
OpName %12 "texture1"
OpName %13 "sampler"
OpName %17 "PushConstants"
OpMemberName %17 0 "index"
OpName %16 "pc"
OpName %20 "color"
OpName %23 "main"
OpName %23 "main"
OpDecorate %5 Location 0
OpName %5 "texture0"
OpName %9 "texture1"
OpName %10 "sampler"
OpName %14 "PushConstants"
OpMemberName %14 0 "index"
OpName %13 "pc"
OpName %19 "tex_coord"
OpName %25 "main"
OpName %25 "main"
OpDecorate %5 DescriptorSet 0
OpDecorate %5 Binding 0
OpDecorate %9 DescriptorSet 0
OpDecorate %9 Binding 0
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 1
OpDecorate %13 DescriptorSet 0
OpDecorate %13 Binding 2
OpDecorate %17 Block
OpMemberDecorate %17 0 Offset 0
OpDecorate %20 Location 1
OpDecorate %9 Binding 1
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 2
OpDecorate %14 Block
OpMemberDecorate %14 0 Offset 0
OpDecorate %19 Location 0
OpDecorate %23 Location 1
%2 = OpTypeVoid
%4 = OpTypeInt 32 1
%3 = OpConstant %4 0
%7 = OpTypeFloat 32
%6 = OpTypeVector %7 2
%8 = OpTypePointer Input %6
%5 = OpVariable %8 Input
%10 = OpTypeImage %7 2D 0 0 0 1 Unknown
%11 = OpTypePointer UniformConstant %10
%9 = OpVariable %11 UniformConstant
%12 = OpVariable %11 UniformConstant
%14 = OpTypeSampler
%15 = OpTypePointer UniformConstant %14
%13 = OpVariable %15 UniformConstant
%18 = OpTypeInt 32 0
%17 = OpTypeStruct %18
%19 = OpTypePointer PushConstant %17
%16 = OpVariable %19 PushConstant
%21 = OpTypeVector %7 4
%22 = OpTypePointer Output %21
%20 = OpVariable %22 Output
%24 = OpTypeFunction %2
%30 = OpTypePointer PushConstant %18
%31 = OpConstant %4 0
%34 = OpTypeBool
%40 = OpTypeSampledImage %10
%23 = OpFunction %2 None %24
%25 = OpLabel
%26 = OpLoad %10 %9
%27 = OpLoad %10 %12
%28 = OpLoad %14 %13
OpBranch %29
%29 = OpLabel
%32 = OpAccessChain %30 %16 %31
%33 = OpLoad %18 %32
%35 = OpIEqual %34 %33 %3
OpSelectionMerge %36 None
OpBranchConditional %35 %37 %38
%37 = OpLabel
%39 = OpLoad %6 %5
%41 = OpSampledImage %40 %26 %28
%42 = OpImageSampleImplicitLod %21 %41 %39
OpStore %20 %42
OpReturn
%6 = OpTypeImage %7 2D 0 0 0 1 Unknown
%8 = OpTypePointer UniformConstant %6
%5 = OpVariable %8 UniformConstant
%9 = OpVariable %8 UniformConstant
%11 = OpTypeSampler
%12 = OpTypePointer UniformConstant %11
%10 = OpVariable %12 UniformConstant
%15 = OpTypeInt 32 0
%14 = OpTypeStruct %15
%16 = OpTypePointer PushConstant %14
%13 = OpVariable %16 PushConstant
%18 = OpTypeVector %7 2
%20 = OpTypePointer Input %18
%19 = OpVariable %20 Input
%22 = OpTypeVector %7 4
%24 = OpTypePointer Output %22
%23 = OpVariable %24 Output
%26 = OpTypeFunction %2
%31 = OpTypePointer PushConstant %15
%32 = OpConstant %4 0
%35 = OpTypeBool
%40 = OpTypeSampledImage %6
%25 = OpFunction %2 None %26
%17 = OpLabel
%21 = OpLoad %18 %19
%27 = OpLoad %6 %5
%28 = OpLoad %6 %9
%29 = OpLoad %11 %10
OpBranch %30
%30 = OpLabel
%33 = OpAccessChain %31 %13 %32
%34 = OpLoad %15 %33
%36 = OpIEqual %35 %34 %3
OpSelectionMerge %37 None
OpBranchConditional %36 %38 %39
%38 = OpLabel
%43 = OpLoad %6 %5
%44 = OpSampledImage %40 %27 %28
%45 = OpImageSampleImplicitLod %21 %44 %43
OpStore %20 %45
%41 = OpSampledImage %40 %27 %29
%42 = OpImageSampleImplicitLod %22 %41 %21
OpStore %23 %42
OpReturn
%36 = OpLabel
%39 = OpLabel
%43 = OpSampledImage %40 %28 %29
%44 = OpImageSampleImplicitLod %22 %43 %21
OpStore %23 %44
OpReturn
%37 = OpLabel
OpReturn
OpFunctionEnd

View File

@@ -1,7 +1,7 @@
//TODO: consider converting this to snapshots?
#[cfg(feature = "glsl-in")]
fn check_glsl(name: &str) {
fn _check_glsl(name: &str) {
let path = std::path::PathBuf::from("tests/cases").join(name);
let input = std::fs::read_to_string(path).unwrap();
let stage = if name.ends_with(".vert") {
@@ -37,6 +37,6 @@ fn check_glsl(name: &str) {
fn parse_glsl() {
//check_glsl("glsl_constant_expression.vert"); //TODO
//check_glsl("glsl_if_preprocessor.vert");
check_glsl("glsl_preprocessor_abuse.vert");
//check_glsl("glsl_preprocessor_abuse.vert");
//check_glsl("glsl_vertex_test_shader.vert"); //TODO
}