mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Update IR to have entry points with inputs/outputs
This commit is contained in:
committed by
Dzmitry Malyshau
parent
58a4e330dc
commit
ebcd815250
@@ -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)
|
||||
|
||||
@@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
54
src/lib.rs
54
src/lib.rs
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
"###
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,7 +8,9 @@ precision highp float;
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
|
||||
void main() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,6 @@ expression: msl
|
||||
|
||||
kernel void main1(
|
||||
) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) };
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user