mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Refactor entry point IR
This commit is contained in:
committed by
Dzmitry Malyshau
parent
74c4a3ce18
commit
2ebaadaf0c
@@ -3,7 +3,7 @@ use std::{env, fs, path::Path};
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct BindSource {
|
||||
set: u32,
|
||||
group: u32,
|
||||
binding: u32,
|
||||
}
|
||||
|
||||
@@ -54,26 +54,14 @@ fn main() {
|
||||
#[cfg(feature = "glsl-in")]
|
||||
"frag" => {
|
||||
let input = fs::read_to_string(&args[1]).unwrap();
|
||||
naga::front::glsl::parse_str(
|
||||
&input,
|
||||
"main".to_string(),
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
naga::front::glsl::parse_str(&input, "main".to_string(), naga::ShaderStage::Fragment)
|
||||
.unwrap()
|
||||
}
|
||||
#[cfg(feature = "glsl-in")]
|
||||
"comp" => {
|
||||
let input = fs::read_to_string(&args[1]).unwrap();
|
||||
naga::front::glsl::parse_str(
|
||||
&input,
|
||||
"main".to_string(),
|
||||
naga::ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
naga::front::glsl::parse_str(&input, "main".to_string(), naga::ShaderStage::Compute)
|
||||
.unwrap()
|
||||
}
|
||||
#[cfg(feature = "deserialize")]
|
||||
"ron" => {
|
||||
@@ -113,7 +101,7 @@ fn main() {
|
||||
for (key, value) in params.metal_bindings {
|
||||
binding_map.insert(
|
||||
msl::BindSource {
|
||||
set: key.set,
|
||||
group: key.group,
|
||||
binding: key.binding,
|
||||
},
|
||||
msl::BindTarget {
|
||||
@@ -170,17 +158,13 @@ fn main() {
|
||||
let options = Options {
|
||||
version: Version::Embedded(310),
|
||||
entry_point: (
|
||||
String::from("main"),
|
||||
match stage {
|
||||
"vert" => ShaderStage::Vertex,
|
||||
"frag" => ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
"comp" => ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
},
|
||||
"frag" => ShaderStage::Fragment,
|
||||
"comp" => ShaderStage::Compute,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
String::from("main"),
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ impl fmt::Display for Version {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Options {
|
||||
pub version: Version,
|
||||
pub entry_point: (String, ShaderStage),
|
||||
pub entry_point: (ShaderStage, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -141,12 +141,12 @@ pub fn write<'a>(
|
||||
|
||||
let entry_point = module
|
||||
.entry_points
|
||||
.iter()
|
||||
.find(|entry| entry.name == options.entry_point.0 && entry.stage == options.entry_point.1)
|
||||
.get(&options.entry_point)
|
||||
.ok_or_else(|| Error::Custom(String::from("Entry point not found")))?;
|
||||
let func = &module.functions[entry_point.function];
|
||||
let func = &entry_point.function;
|
||||
let stage = options.entry_point.0;
|
||||
|
||||
if let ShaderStage::Compute { .. } = entry_point.stage {
|
||||
if let ShaderStage::Compute = stage {
|
||||
if (es && version < 310) || (!es && version < 430) {
|
||||
return Err(Error::Custom(format!(
|
||||
"Version {} doesn't support compute shaders",
|
||||
@@ -233,21 +233,7 @@ pub fn write<'a>(
|
||||
let mut functions = FastHashMap::default();
|
||||
|
||||
for (handle, func) in module.functions.iter() {
|
||||
// Discard all entry points
|
||||
if entry_point.function != handle
|
||||
&& module
|
||||
.entry_points
|
||||
.iter()
|
||||
.any(|entry| entry.function == handle)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = if entry_point.function != handle {
|
||||
namer(func.name.as_ref())
|
||||
} else {
|
||||
String::from("main")
|
||||
};
|
||||
let name = namer(func.name.as_ref());
|
||||
|
||||
writeln!(
|
||||
out,
|
||||
@@ -406,8 +392,8 @@ pub fn write<'a>(
|
||||
}
|
||||
|
||||
if let Some(interpolation) = global.interpolation {
|
||||
match (entry_point.stage, global.class) {
|
||||
(ShaderStage::Fragment { .. }, StorageClass::Input)
|
||||
match (stage, global.class) {
|
||||
(ShaderStage::Fragment, StorageClass::Input)
|
||||
| (ShaderStage::Vertex, StorageClass::Output) => {
|
||||
write!(out, "{} ", write_interpolation(interpolation)?)?;
|
||||
}
|
||||
@@ -1449,7 +1435,7 @@ fn write_format_glsl(format: StorageFormat) -> &'static str {
|
||||
|
||||
struct TextureMappingVisitor<'a> {
|
||||
expressions: &'a Arena<Expression>,
|
||||
map: FastHashMap<Handle<GlobalVariable>, Option<Handle<GlobalVariable>>>,
|
||||
map: &'a mut FastHashMap<Handle<GlobalVariable>, Option<Handle<GlobalVariable>>>,
|
||||
error: Option<Error>,
|
||||
}
|
||||
|
||||
@@ -1503,19 +1489,15 @@ fn collect_texture_mapping(
|
||||
for function in functions.keys() {
|
||||
let func = &module.functions[*function];
|
||||
|
||||
let mut visitor = TextureMappingVisitor {
|
||||
expressions: &func.expressions,
|
||||
map: FastHashMap::default(),
|
||||
error: None,
|
||||
};
|
||||
|
||||
let mut interface = Interface {
|
||||
expressions: &func.expressions,
|
||||
visitor: &mut visitor,
|
||||
visitor: TextureMappingVisitor {
|
||||
expressions: &func.expressions,
|
||||
map: &mut mappings,
|
||||
error: None,
|
||||
},
|
||||
};
|
||||
interface.traverse(&func.body);
|
||||
|
||||
mappings.extend(visitor.map);
|
||||
}
|
||||
|
||||
Ok(mappings)
|
||||
|
||||
393
src/back/msl.rs
393
src/back/msl.rs
@@ -31,7 +31,7 @@ pub struct BindTarget {
|
||||
|
||||
#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct BindSource {
|
||||
pub set: u32,
|
||||
pub group: u32,
|
||||
pub binding: u32,
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ pub enum Error {
|
||||
Format(FmtError),
|
||||
Type(ResolveError),
|
||||
UnexpectedLocation,
|
||||
MixedExecutionModels(Handle<crate::Function>),
|
||||
MissingBinding(Handle<crate::GlobalVariable>),
|
||||
MissingBindTarget(BindSource),
|
||||
InvalidImageAccess(crate::StorageAccess),
|
||||
@@ -125,8 +124,8 @@ impl Options<'_> {
|
||||
}),
|
||||
LocationMode::Uniform => Err(Error::UnexpectedLocation),
|
||||
},
|
||||
crate::Binding::Descriptor { set, binding } => {
|
||||
let source = BindSource { set, binding };
|
||||
crate::Binding::Resource { group, binding } => {
|
||||
let source = BindSource { group, binding };
|
||||
self.binding_map
|
||||
.get(&source)
|
||||
.cloned()
|
||||
@@ -182,22 +181,6 @@ impl Indexed for ParameterIndex {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
struct InputStructIndex(Handle<crate::Function>);
|
||||
impl Indexed for InputStructIndex {
|
||||
const CLASS: &'static str = "Input";
|
||||
const PREFIX: bool = true;
|
||||
fn id(&self) -> usize {
|
||||
self.0.index()
|
||||
}
|
||||
}
|
||||
struct OutputStructIndex(Handle<crate::Function>);
|
||||
impl Indexed for OutputStructIndex {
|
||||
const CLASS: &'static str = "Output";
|
||||
const PREFIX: bool = true;
|
||||
fn id(&self) -> usize {
|
||||
self.0.index()
|
||||
}
|
||||
}
|
||||
|
||||
enum NameSource<'a> {
|
||||
Custom { name: &'a str, prefix: bool },
|
||||
@@ -924,8 +907,55 @@ impl<W: Write> Writer<W> {
|
||||
)?;
|
||||
|
||||
let fun_name = fun.name.or_index(fun_handle);
|
||||
let result_type_handle = fun.return_type.unwrap();
|
||||
let result_type_name = module.types[result_type_handle]
|
||||
.name
|
||||
.or_index(result_type_handle);
|
||||
writeln!(self.out, "{} {}(", result_type_name, fun_name)?;
|
||||
|
||||
for (index, &ty) in fun.parameter_types.iter().enumerate() {
|
||||
let name = Name::from(ParameterIndex(index));
|
||||
let member_type_name = module.types[ty].name.or_index(ty);
|
||||
let separator = separate(index + 1 == fun.parameter_types.len());
|
||||
writeln!(self.out, "\t{} {}{}", member_type_name, name, separator)?;
|
||||
}
|
||||
writeln!(self.out, ") {{")?;
|
||||
|
||||
for (local_handle, local) in fun.local_variables.iter() {
|
||||
let ty_name = module.types[local.ty].name.or_index(local.ty);
|
||||
write!(
|
||||
self.out,
|
||||
"\t{} {}",
|
||||
ty_name,
|
||||
local.name.or_index(local_handle)
|
||||
)?;
|
||||
if let Some(value) = local.init {
|
||||
write!(self.out, " = ")?;
|
||||
self.put_expression(value, fun, module)?;
|
||||
}
|
||||
writeln!(self.out, ";")?;
|
||||
}
|
||||
for statement in fun.body.iter() {
|
||||
self.put_statement(Level(1), statement, fun, false, module)?;
|
||||
}
|
||||
writeln!(self.out, "}}")?;
|
||||
}
|
||||
|
||||
for (&(stage, ref name), ep) in module.entry_points.iter() {
|
||||
let fun = &ep.function;
|
||||
self.typifier.resolve_all(
|
||||
&fun.expressions,
|
||||
&module.types,
|
||||
&ResolveContext {
|
||||
constants: &module.constants,
|
||||
global_vars: &module.global_variables,
|
||||
local_vars: &fun.local_variables,
|
||||
functions: &module.functions,
|
||||
parameter_types: &fun.parameter_types,
|
||||
},
|
||||
)?;
|
||||
|
||||
// find the entry point(s) and inputs/outputs
|
||||
let mut shader_stage = None;
|
||||
let mut last_used_global = None;
|
||||
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
|
||||
match var.class {
|
||||
@@ -941,206 +971,177 @@ impl<W: Write> Writer<W> {
|
||||
last_used_global = Some(handle);
|
||||
}
|
||||
}
|
||||
for ep in module.entry_points.iter() {
|
||||
if ep.function == fun_handle {
|
||||
if shader_stage.is_some() {
|
||||
if shader_stage != Some(ep.stage) {
|
||||
return Err(Error::MixedExecutionModels(fun_handle));
|
||||
}
|
||||
} else {
|
||||
shader_stage = Some(ep.stage);
|
||||
}
|
||||
|
||||
let output_name = Name {
|
||||
class: "Output",
|
||||
source: NameSource::Custom { name, prefix: true },
|
||||
};
|
||||
|
||||
let (em_str, in_mode, out_mode) = match stage {
|
||||
crate::ShaderStage::Vertex => (
|
||||
"vertex",
|
||||
LocationMode::VertexInput,
|
||||
LocationMode::Intermediate,
|
||||
),
|
||||
crate::ShaderStage::Fragment { .. } => (
|
||||
"fragment",
|
||||
LocationMode::Intermediate,
|
||||
LocationMode::FragmentOutput,
|
||||
),
|
||||
crate::ShaderStage::Compute { .. } => {
|
||||
("kernel", LocationMode::Uniform, LocationMode::Uniform)
|
||||
}
|
||||
}
|
||||
let output_name = fun.name.or_index(OutputStructIndex(fun_handle));
|
||||
};
|
||||
let location_input_name = Name {
|
||||
class: "Input",
|
||||
source: NameSource::Custom { name, prefix: true },
|
||||
};
|
||||
|
||||
// make dedicated input/output structs
|
||||
if let Some(stage) = shader_stage {
|
||||
assert_eq!(fun.return_type, None);
|
||||
let (em_str, in_mode, out_mode) = match stage {
|
||||
crate::ShaderStage::Vertex => (
|
||||
"vertex",
|
||||
LocationMode::VertexInput,
|
||||
LocationMode::Intermediate,
|
||||
),
|
||||
crate::ShaderStage::Fragment { .. } => (
|
||||
"fragment",
|
||||
LocationMode::Intermediate,
|
||||
LocationMode::FragmentOutput,
|
||||
),
|
||||
crate::ShaderStage::Compute { .. } => {
|
||||
("kernel", LocationMode::Uniform, LocationMode::Uniform)
|
||||
}
|
||||
};
|
||||
let location_input_name = fun.name.or_index(InputStructIndex(fun_handle));
|
||||
match stage {
|
||||
crate::ShaderStage::Vertex | crate::ShaderStage::Fragment => {
|
||||
// make dedicated input/output structs
|
||||
writeln!(self.out, "struct {} {{", location_input_name)?;
|
||||
|
||||
match stage {
|
||||
crate::ShaderStage::Compute { .. } => {
|
||||
writeln!(self.out, "struct {} {{", location_input_name)?;
|
||||
for ((handle, var), &usage) in
|
||||
module.global_variables.iter().zip(&fun.global_usage)
|
||||
for ((handle, var), &usage) in
|
||||
module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
if var.class != crate::StorageClass::Input
|
||||
|| !usage.contains(crate::GlobalUse::LOAD)
|
||||
{
|
||||
if var.class != crate::StorageClass::Input
|
||||
|| !usage.contains(crate::GlobalUse::LOAD)
|
||||
{
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
// if it's a struct, lift all the built-in contents up to the root
|
||||
let ty_handle = var.ty;
|
||||
if let crate::TypeInner::Struct { ref members } =
|
||||
module.types[ty_handle].inner
|
||||
{
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
if let crate::MemberOrigin::BuiltIn(built_in) = member.origin {
|
||||
let name = member.name.or_index(MemberIndex(index));
|
||||
let ty_name = module.types[member.ty].name.or_index(member.ty);
|
||||
write!(self.out, "\t{} {}", ty_name, name)?;
|
||||
ResolvedBinding::BuiltIn(built_in)
|
||||
.try_fmt_decorated(&mut self.out, ";\n")?;
|
||||
}
|
||||
}
|
||||
// if it's a struct, lift all the built-in contents up to the root
|
||||
let ty_handle = var.ty;
|
||||
if let crate::TypeInner::Struct { ref members } =
|
||||
module.types[ty_handle].inner
|
||||
{
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
if let crate::MemberOrigin::BuiltIn(built_in) = member.origin {
|
||||
let name = member.name.or_index(MemberIndex(index));
|
||||
let ty_name =
|
||||
module.types[member.ty].name.or_index(member.ty);
|
||||
} else if let Some(ref binding @ crate::Binding::Location(_)) = var.binding
|
||||
{
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage: crate::GlobalUse::empty(),
|
||||
};
|
||||
let resolved = options.resolve_binding(binding, in_mode)?;
|
||||
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
resolved.try_fmt_decorated(&mut self.out, ";\n")?;
|
||||
}
|
||||
}
|
||||
writeln!(self.out, "}};")?;
|
||||
|
||||
writeln!(self.out, "struct {} {{", output_name)?;
|
||||
for ((handle, var), &usage) in
|
||||
module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
if var.class != crate::StorageClass::Output
|
||||
|| !usage.contains(crate::GlobalUse::STORE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// if it's a struct, lift all the built-in contents up to the root
|
||||
let ty_handle = var.ty;
|
||||
if let crate::TypeInner::Struct { ref members } =
|
||||
module.types[ty_handle].inner
|
||||
{
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
let name = member.name.or_index(MemberIndex(index));
|
||||
let ty_name = module.types[member.ty].name.or_index(member.ty);
|
||||
match member.origin {
|
||||
crate::MemberOrigin::Empty => {}
|
||||
crate::MemberOrigin::BuiltIn(built_in) => {
|
||||
write!(self.out, "\t{} {}", ty_name, name)?;
|
||||
ResolvedBinding::BuiltIn(built_in)
|
||||
.try_fmt_decorated(&mut self.out, ";\n")?;
|
||||
}
|
||||
}
|
||||
} else if let Some(ref binding @ crate::Binding::Location(_)) =
|
||||
var.binding
|
||||
{
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage: crate::GlobalUse::empty(),
|
||||
};
|
||||
let resolved = options.resolve_binding(binding, in_mode)?;
|
||||
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
resolved.try_fmt_decorated(&mut self.out, ";\n")?;
|
||||
}
|
||||
}
|
||||
writeln!(self.out, "}};")?;
|
||||
writeln!(self.out, "struct {} {{", output_name)?;
|
||||
for ((handle, var), &usage) in
|
||||
module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
if var.class != crate::StorageClass::Output
|
||||
|| !usage.contains(crate::GlobalUse::STORE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// if it's a struct, lift all the built-in contents up to the root
|
||||
let ty_handle = var.ty;
|
||||
if let crate::TypeInner::Struct { ref members } =
|
||||
module.types[ty_handle].inner
|
||||
{
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
let name = member.name.or_index(MemberIndex(index));
|
||||
let ty_name = module.types[member.ty].name.or_index(member.ty);
|
||||
match member.origin {
|
||||
crate::MemberOrigin::Empty => {}
|
||||
crate::MemberOrigin::BuiltIn(built_in) => {
|
||||
write!(self.out, "\t{} {}", ty_name, name)?;
|
||||
ResolvedBinding::BuiltIn(built_in)
|
||||
.try_fmt_decorated(&mut self.out, ";\n")?;
|
||||
}
|
||||
crate::MemberOrigin::Offset(_) => {
|
||||
//TODO
|
||||
}
|
||||
crate::MemberOrigin::Offset(_) => {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage: crate::GlobalUse::empty(),
|
||||
};
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
if let Some(ref binding) = var.binding {
|
||||
let resolved = options.resolve_binding(binding, out_mode)?;
|
||||
resolved.try_fmt_decorated(&mut self.out, "")?;
|
||||
}
|
||||
writeln!(self.out, ";")?;
|
||||
}
|
||||
} else {
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage: crate::GlobalUse::empty(),
|
||||
};
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
if let Some(ref binding) = var.binding {
|
||||
let resolved = options.resolve_binding(binding, out_mode)?;
|
||||
resolved.try_fmt_decorated(&mut 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,
|
||||
"\t{} {} [[stage_in]]{}",
|
||||
location_input_name, LOCATION_INPUT_STRUCT_NAME, separator
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
writeln!(self.out, "{} void {}(", em_str, fun_name)?;
|
||||
}
|
||||
};
|
||||
writeln!(self.out, "}};")?;
|
||||
|
||||
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
if usage.is_empty() || var.class == crate::StorageClass::Output {
|
||||
writeln!(self.out, "{} {} {}(", em_str, output_name, name)?;
|
||||
let separator = separate(last_used_global.is_none());
|
||||
writeln!(
|
||||
self.out,
|
||||
"\t{} {} [[stage_in]]{}",
|
||||
location_input_name, LOCATION_INPUT_STRUCT_NAME, separator
|
||||
)?;
|
||||
}
|
||||
crate::ShaderStage::Compute => {
|
||||
writeln!(self.out, "{} void {}(", em_str, name)?;
|
||||
}
|
||||
};
|
||||
|
||||
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) {
|
||||
if usage.is_empty() || var.class == crate::StorageClass::Output {
|
||||
continue;
|
||||
}
|
||||
if var.class == crate::StorageClass::Input {
|
||||
if let Some(crate::Binding::Location(_)) = var.binding {
|
||||
// location inputs are put into a separate struct
|
||||
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 (stage, var.class) {
|
||||
(crate::ShaderStage::Vertex, crate::StorageClass::Input) => {
|
||||
LocationMode::VertexInput
|
||||
}
|
||||
let loc_mode = match (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 resolved =
|
||||
options.resolve_binding(var.binding.as_ref().unwrap(), loc_mode)?;
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage,
|
||||
};
|
||||
let separator = separate(last_used_global == Some(handle));
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
resolved.try_fmt_decorated(&mut self.out, separator)?;
|
||||
writeln!(self.out)?;
|
||||
}
|
||||
} else {
|
||||
let result_type_name = match fun.return_type {
|
||||
Some(type_id) => module.types[type_id].name.or_index(type_id),
|
||||
None => Name {
|
||||
class: "",
|
||||
source: NameSource::Custom {
|
||||
name: "void",
|
||||
prefix: false,
|
||||
},
|
||||
},
|
||||
(crate::ShaderStage::Vertex, crate::StorageClass::Output)
|
||||
| (crate::ShaderStage::Fragment { .. }, crate::StorageClass::Input) => {
|
||||
LocationMode::Intermediate
|
||||
}
|
||||
(crate::ShaderStage::Fragment { .. }, crate::StorageClass::Output) => {
|
||||
LocationMode::FragmentOutput
|
||||
}
|
||||
_ => LocationMode::Uniform,
|
||||
};
|
||||
writeln!(self.out, "{} {}(", result_type_name, fun_name)?;
|
||||
for (index, &ty) in fun.parameter_types.iter().enumerate() {
|
||||
let name = Name::from(ParameterIndex(index));
|
||||
let member_type_name = module.types[ty].name.or_index(ty);
|
||||
let separator = separate(
|
||||
index + 1 == fun.parameter_types.len() && last_used_global.is_none(),
|
||||
);
|
||||
writeln!(self.out, "\t{} {}{}", member_type_name, name, separator)?;
|
||||
}
|
||||
let resolved = options.resolve_binding(var.binding.as_ref().unwrap(), loc_mode)?;
|
||||
let tyvar = TypedGlobalVariable {
|
||||
module,
|
||||
handle,
|
||||
usage,
|
||||
};
|
||||
let separator = separate(last_used_global == Some(handle));
|
||||
write!(self.out, "\t")?;
|
||||
tyvar.try_fmt(&mut self.out)?;
|
||||
resolved.try_fmt_decorated(&mut self.out, separator)?;
|
||||
writeln!(self.out)?;
|
||||
}
|
||||
writeln!(self.out, ") {{")?;
|
||||
|
||||
// write down function body
|
||||
let has_output = match shader_stage {
|
||||
Some(crate::ShaderStage::Vertex) | Some(crate::ShaderStage::Fragment { .. }) => {
|
||||
let has_output = match stage {
|
||||
crate::ShaderStage::Vertex | crate::ShaderStage::Fragment => {
|
||||
writeln!(self.out, "\t{} {};", output_name, OUTPUT_STRUCT_NAME)?;
|
||||
true
|
||||
}
|
||||
Some(crate::ShaderStage::Compute { .. }) | None => false,
|
||||
crate::ShaderStage::Compute => false,
|
||||
};
|
||||
for (local_handle, local) in fun.local_variables.iter() {
|
||||
let ty_name = module.types[local.ty].name.or_index(local.ty);
|
||||
|
||||
@@ -248,26 +248,121 @@ impl Writer {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_function(
|
||||
&mut self,
|
||||
ir_function: &crate::Function,
|
||||
ir_module: &crate::Module,
|
||||
) -> spirv::Word {
|
||||
let mut function = Function::new();
|
||||
|
||||
for (_, variable) in ir_function.local_variables.iter() {
|
||||
let id = self.generate_id();
|
||||
|
||||
let init_word = match variable.init {
|
||||
Some(exp) => match &ir_function.expressions[exp] {
|
||||
crate::Expression::Constant(handle) => {
|
||||
Some(self.get_constant_id(*handle, ir_module))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let pointer_id =
|
||||
self.get_pointer_id(&ir_module.types, variable.ty, spirv::StorageClass::Function);
|
||||
function.variables.push(LocalVariable {
|
||||
id,
|
||||
name: variable.name.clone(),
|
||||
instruction: super::instructions::instruction_variable(
|
||||
pointer_id,
|
||||
id,
|
||||
spirv::StorageClass::Function,
|
||||
init_word,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
let return_type_id =
|
||||
self.get_function_return_type(ir_function.return_type, &ir_module.types);
|
||||
let mut parameter_type_ids = Vec::with_capacity(ir_function.parameter_types.len());
|
||||
|
||||
let mut function_parameter_pointer_ids = vec![];
|
||||
|
||||
for parameter_type in ir_function.parameter_types.iter() {
|
||||
let id = self.generate_id();
|
||||
let pointer_id = self.get_pointer_id(
|
||||
&ir_module.types,
|
||||
*parameter_type,
|
||||
spirv::StorageClass::Function,
|
||||
);
|
||||
|
||||
function_parameter_pointer_ids.push(pointer_id);
|
||||
parameter_type_ids
|
||||
.push(self.get_type_id(&ir_module.types, LookupType::Handle(*parameter_type)));
|
||||
function
|
||||
.parameters
|
||||
.push(super::instructions::instruction_function_parameter(
|
||||
pointer_id, id,
|
||||
));
|
||||
}
|
||||
|
||||
let lookup_function_type = LookupFunctionType {
|
||||
return_type_id,
|
||||
parameter_type_ids,
|
||||
};
|
||||
|
||||
let id = self.generate_id();
|
||||
let function_type =
|
||||
self.get_function_type(lookup_function_type, function_parameter_pointer_ids);
|
||||
function.signature = Some(super::instructions::instruction_function(
|
||||
return_type_id,
|
||||
id,
|
||||
spirv::FunctionControl::empty(),
|
||||
function_type,
|
||||
));
|
||||
|
||||
let mut block = Block::new();
|
||||
let id = self.generate_id();
|
||||
block.label = Some(super::instructions::instruction_label(id));
|
||||
for statement in ir_function.body.iter() {
|
||||
self.write_function_statement(
|
||||
ir_module,
|
||||
ir_function,
|
||||
&statement,
|
||||
&mut block,
|
||||
&mut function,
|
||||
);
|
||||
}
|
||||
function.blocks.push(block);
|
||||
|
||||
function.to_words(&mut self.logical_layout.function_definitions);
|
||||
super::instructions::instruction_function_end()
|
||||
.to_words(&mut self.logical_layout.function_definitions);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
// TODO Move to instructions module
|
||||
fn write_entry_point(
|
||||
&mut self,
|
||||
entry_point: &crate::EntryPoint,
|
||||
stage: crate::ShaderStage,
|
||||
name: &str,
|
||||
ir_module: &crate::Module,
|
||||
) -> Instruction {
|
||||
let function_id = *self.lookup_function.get(&entry_point.function).unwrap();
|
||||
let function_id = self.write_function(&entry_point.function, ir_module);
|
||||
|
||||
let exec_model = match entry_point.stage {
|
||||
let exec_model = match stage {
|
||||
crate::ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
|
||||
crate::ShaderStage::Fragment { .. } => spirv::ExecutionModel::Fragment,
|
||||
crate::ShaderStage::Compute { .. } => spirv::ExecutionModel::GLCompute,
|
||||
};
|
||||
|
||||
let mut interface_ids = vec![];
|
||||
let function = &ir_module.functions[entry_point.function];
|
||||
for ((handle, _), &usage) in ir_module
|
||||
.global_variables
|
||||
.iter()
|
||||
.zip(&function.global_usage)
|
||||
.zip(&entry_point.function.global_usage)
|
||||
{
|
||||
if usage.contains(crate::GlobalUse::STORE) || usage.contains(crate::GlobalUse::LOAD) {
|
||||
let id = self.get_global_variable_id(
|
||||
@@ -280,28 +375,26 @@ impl Writer {
|
||||
}
|
||||
|
||||
self.try_add_capabilities(exec_model.required_capabilities());
|
||||
match entry_point.stage {
|
||||
match stage {
|
||||
crate::ShaderStage::Vertex => {}
|
||||
crate::ShaderStage::Fragment { .. } => {
|
||||
crate::ShaderStage::Fragment => {
|
||||
let execution_mode = spirv::ExecutionMode::OriginUpperLeft;
|
||||
self.try_add_capabilities(execution_mode.required_capabilities());
|
||||
super::instructions::instruction_execution_mode(function_id, execution_mode)
|
||||
.to_words(&mut self.logical_layout.execution_modes);
|
||||
}
|
||||
crate::ShaderStage::Compute { .. } => {}
|
||||
crate::ShaderStage::Compute => {}
|
||||
}
|
||||
|
||||
if self.writer_flags.contains(WriterFlags::DEBUG) {
|
||||
self.debugs.push(super::instructions::instruction_name(
|
||||
function_id,
|
||||
entry_point.name.as_str(),
|
||||
));
|
||||
self.debugs
|
||||
.push(super::instructions::instruction_name(function_id, name));
|
||||
}
|
||||
|
||||
super::instructions::instruction_entry_point(
|
||||
exec_model,
|
||||
function_id,
|
||||
entry_point.name.as_str(),
|
||||
name,
|
||||
interface_ids.as_slice(),
|
||||
)
|
||||
}
|
||||
@@ -604,27 +697,27 @@ impl Writer {
|
||||
}
|
||||
}
|
||||
|
||||
match global_variable.binding.as_ref().unwrap() {
|
||||
match *global_variable.binding.as_ref().unwrap() {
|
||||
crate::Binding::Location(location) => {
|
||||
self.annotations
|
||||
.push(super::instructions::instruction_decorate(
|
||||
id,
|
||||
spirv::Decoration::Location,
|
||||
&[*location],
|
||||
&[location],
|
||||
));
|
||||
}
|
||||
crate::Binding::Descriptor { set, binding } => {
|
||||
crate::Binding::Resource { group, binding } => {
|
||||
self.annotations
|
||||
.push(super::instructions::instruction_decorate(
|
||||
id,
|
||||
spirv::Decoration::DescriptorSet,
|
||||
&[*set],
|
||||
&[group],
|
||||
));
|
||||
self.annotations
|
||||
.push(super::instructions::instruction_decorate(
|
||||
id,
|
||||
spirv::Decoration::Binding,
|
||||
&[*binding],
|
||||
&[binding],
|
||||
));
|
||||
}
|
||||
crate::Binding::BuiltIn(built_in) => {
|
||||
@@ -1000,100 +1093,12 @@ impl Writer {
|
||||
}
|
||||
|
||||
for (handle, ir_function) in ir_module.functions.iter() {
|
||||
let mut function = Function::new();
|
||||
|
||||
for (_, variable) in ir_function.local_variables.iter() {
|
||||
let id = self.generate_id();
|
||||
|
||||
let init_word = match variable.init {
|
||||
Some(exp) => match &ir_function.expressions[exp] {
|
||||
crate::Expression::Constant(handle) => {
|
||||
Some(self.get_constant_id(*handle, ir_module))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let pointer_id = self.get_pointer_id(
|
||||
&ir_module.types,
|
||||
variable.ty,
|
||||
spirv::StorageClass::Function,
|
||||
);
|
||||
function.variables.push(LocalVariable {
|
||||
id,
|
||||
name: variable.name.clone(),
|
||||
instruction: super::instructions::instruction_variable(
|
||||
pointer_id,
|
||||
id,
|
||||
spirv::StorageClass::Function,
|
||||
init_word,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
let return_type_id =
|
||||
self.get_function_return_type(ir_function.return_type, &ir_module.types);
|
||||
let mut parameter_type_ids = Vec::with_capacity(ir_function.parameter_types.len());
|
||||
|
||||
let mut function_parameter_pointer_ids = vec![];
|
||||
|
||||
for parameter_type in ir_function.parameter_types.iter() {
|
||||
let id = self.generate_id();
|
||||
let pointer_id = self.get_pointer_id(
|
||||
&ir_module.types,
|
||||
*parameter_type,
|
||||
spirv::StorageClass::Function,
|
||||
);
|
||||
|
||||
function_parameter_pointer_ids.push(pointer_id);
|
||||
parameter_type_ids
|
||||
.push(self.get_type_id(&ir_module.types, LookupType::Handle(*parameter_type)));
|
||||
function
|
||||
.parameters
|
||||
.push(super::instructions::instruction_function_parameter(
|
||||
pointer_id, id,
|
||||
));
|
||||
}
|
||||
|
||||
let lookup_function_type = LookupFunctionType {
|
||||
return_type_id,
|
||||
parameter_type_ids,
|
||||
};
|
||||
|
||||
let id = self.generate_id();
|
||||
let function_type =
|
||||
self.get_function_type(lookup_function_type, function_parameter_pointer_ids);
|
||||
function.signature = Some(super::instructions::instruction_function(
|
||||
return_type_id,
|
||||
id,
|
||||
spirv::FunctionControl::empty(),
|
||||
function_type,
|
||||
));
|
||||
|
||||
let id = self.write_function(ir_function, ir_module);
|
||||
self.lookup_function.insert(handle, id);
|
||||
|
||||
let mut block = Block::new();
|
||||
let id = self.generate_id();
|
||||
block.label = Some(super::instructions::instruction_label(id));
|
||||
for statement in ir_function.body.iter() {
|
||||
self.write_function_statement(
|
||||
ir_module,
|
||||
ir_function,
|
||||
&statement,
|
||||
&mut block,
|
||||
&mut function,
|
||||
);
|
||||
}
|
||||
function.blocks.push(block);
|
||||
|
||||
function.to_words(&mut self.logical_layout.function_definitions);
|
||||
super::instructions::instruction_function_end()
|
||||
.to_words(&mut self.logical_layout.function_definitions);
|
||||
}
|
||||
|
||||
for entry_point in ir_module.entry_points.iter() {
|
||||
let entry_point_instruction = self.write_entry_point(entry_point, ir_module);
|
||||
for (&(stage, ref name), ir_ep) in ir_module.entry_points.iter() {
|
||||
let entry_point_instruction = self.write_entry_point(ir_ep, stage, name, ir_module);
|
||||
entry_point_instruction.to_words(&mut self.logical_layout.entry_points);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap, Function, GlobalVariable,
|
||||
Handle, Interpolation, LocalVariable, ShaderStage, Statement, StorageClass, Type,
|
||||
Arena, BinaryOperator, Binding, Expression, FastHashMap, Function, GlobalVariable, Handle,
|
||||
Interpolation, LocalVariable, Module, ShaderStage, Statement, StorageClass, Type,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -8,28 +8,23 @@ pub struct Program {
|
||||
pub version: u16,
|
||||
pub profile: Profile,
|
||||
pub shader_stage: ShaderStage,
|
||||
pub entry: Option<String>,
|
||||
pub lookup_function: FastHashMap<String, Handle<Function>>,
|
||||
pub functions: Arena<Function>,
|
||||
pub lookup_type: FastHashMap<String, Handle<Type>>,
|
||||
pub types: Arena<Type>,
|
||||
pub constants: Arena<Constant>,
|
||||
pub global_variables: Arena<GlobalVariable>,
|
||||
pub lookup_global_variables: FastHashMap<String, Handle<GlobalVariable>>,
|
||||
pub context: Context,
|
||||
pub module: Module,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn new(shader_stage: ShaderStage) -> Program {
|
||||
pub fn new(shader_stage: ShaderStage, entry: String) -> Program {
|
||||
Program {
|
||||
version: 0,
|
||||
profile: Profile::Core,
|
||||
shader_stage,
|
||||
entry: Some(entry),
|
||||
lookup_function: FastHashMap::default(),
|
||||
functions: Arena::<Function>::new(),
|
||||
lookup_type: FastHashMap::default(),
|
||||
types: Arena::<Type>::new(),
|
||||
constants: Arena::<Constant>::new(),
|
||||
global_variables: Arena::<GlobalVariable>::new(),
|
||||
lookup_global_variables: FastHashMap::default(),
|
||||
context: Context {
|
||||
expressions: Arena::<Expression>::new(),
|
||||
@@ -37,6 +32,7 @@ impl Program {
|
||||
scopes: vec![FastHashMap::default()],
|
||||
lookup_global_var_exps: FastHashMap::default(),
|
||||
},
|
||||
module: Module::generate_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{EntryPoint, Module, ShaderStage};
|
||||
use crate::{Module, ShaderStage};
|
||||
|
||||
mod lex;
|
||||
#[cfg(test)]
|
||||
@@ -23,7 +23,7 @@ mod rosetta_tests;
|
||||
pub fn parse_str(source: &str, entry: String, stage: ShaderStage) -> Result<Module, ParseError> {
|
||||
log::debug!("------ GLSL-pomelo ------");
|
||||
|
||||
let mut program = Program::new(stage);
|
||||
let mut program = Program::new(stage, entry);
|
||||
let lex = Lexer::new(source);
|
||||
let mut parser = parser::Parser::new(&mut program);
|
||||
|
||||
@@ -32,20 +32,5 @@ pub fn parse_str(source: &str, entry: String, stage: ShaderStage) -> Result<Modu
|
||||
}
|
||||
parser.end_of_input()?;
|
||||
|
||||
let mut module = Module::generate_empty();
|
||||
module.functions = program.functions;
|
||||
module.types = program.types;
|
||||
module.constants = program.constants;
|
||||
module.global_variables = program.global_variables;
|
||||
|
||||
// find entry point
|
||||
if let Some(entry_handle) = program.lookup_function.get(&entry) {
|
||||
module.entry_points.push(EntryPoint {
|
||||
stage,
|
||||
name: entry,
|
||||
function: *entry_handle,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(module)
|
||||
Ok(program.module)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ pomelo! {
|
||||
//%verbose;
|
||||
%include {
|
||||
use super::super::{error::ErrorKind, token::*, ast::*};
|
||||
use crate::{Arena, BinaryOperator, Binding, Block, Constant, ConstantInner, Expression,
|
||||
use crate::{Arena, BinaryOperator, Binding, Block, Constant, ConstantInner, EntryPoint, Expression,
|
||||
Function, GlobalVariable, Handle, LocalVariable, MemberOrigin, ScalarKind,
|
||||
Statement, StorageAccess, StorageClass, StructMember, Type, TypeInner,
|
||||
Interpolation};
|
||||
@@ -152,14 +152,14 @@ pomelo! {
|
||||
|
||||
primary_expression ::= variable_identifier;
|
||||
primary_expression ::= IntConstant(i) {
|
||||
let ty = extra.types.fetch_or_append(Type {
|
||||
let ty = extra.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 4,
|
||||
}
|
||||
});
|
||||
let ch = extra.constants.fetch_or_append(Constant {
|
||||
let ch = extra.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
ty,
|
||||
@@ -171,14 +171,14 @@ pomelo! {
|
||||
}
|
||||
// primary_expression ::= UintConstant;
|
||||
primary_expression ::= FloatConstant(f) {
|
||||
let ty = extra.types.fetch_or_append(Type {
|
||||
let ty = extra.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
}
|
||||
});
|
||||
let ch = extra.constants.fetch_or_append(Constant {
|
||||
let ch = extra.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
ty,
|
||||
@@ -189,14 +189,14 @@ pomelo! {
|
||||
)
|
||||
}
|
||||
primary_expression ::= BoolConstant(b) {
|
||||
let ty = extra.types.fetch_or_append(Type {
|
||||
let ty = extra.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Bool,
|
||||
width: 4,
|
||||
}
|
||||
});
|
||||
let ch = extra.constants.fetch_or_append(Constant {
|
||||
let ch = extra.module.constants.fetch_or_append(Constant {
|
||||
name: None,
|
||||
specialization: None,
|
||||
ty,
|
||||
@@ -464,7 +464,7 @@ pomelo! {
|
||||
VarDeclaration{
|
||||
type_qualifiers: t,
|
||||
ids_initializers: vec![],
|
||||
ty: extra.types.fetch_or_append(Type{
|
||||
ty: extra.module.types.fetch_or_append(Type{
|
||||
name: Some(i.1),
|
||||
inner: TypeInner::Struct {
|
||||
members: sdl
|
||||
@@ -478,7 +478,7 @@ pomelo! {
|
||||
VarDeclaration{
|
||||
type_qualifiers: t,
|
||||
ids_initializers: vec![(i2.1, None)],
|
||||
ty: extra.types.fetch_or_append(Type{
|
||||
ty: extra.module.types.fetch_or_append(Type{
|
||||
name: Some(i1.1),
|
||||
inner: TypeInner::Struct {
|
||||
members: sdl
|
||||
@@ -544,15 +544,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") {
|
||||
Binding::Location(*loc)
|
||||
} else if let Some((_, binding)) = l.iter().find(|&q| q.0.as_str() == "binding") {
|
||||
let set = if let Some((_, set)) = l.iter().find(|&q| q.0.as_str() == "set") {
|
||||
*set
|
||||
if let Some(&(_, loc)) = l.iter().find(|&q| q.0.as_str() == "location") {
|
||||
Binding::Location(loc)
|
||||
} 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
|
||||
};
|
||||
Binding::Descriptor{set, binding: *binding}
|
||||
Binding::Resource{ group, binding }
|
||||
} else {
|
||||
return Err(ErrorKind::NotImplemented("unsupported layout qualifier(s)"));
|
||||
}
|
||||
@@ -617,7 +617,7 @@ pomelo! {
|
||||
type_specifier ::= type_specifier_nonarray(t) {
|
||||
t.map(|t| {
|
||||
let name = t.name.clone();
|
||||
let handle = extra.types.fetch_or_append(t);
|
||||
let handle = extra.module.types.fetch_or_append(t);
|
||||
if let Some(name) = name {
|
||||
extra.lookup_type.insert(name, handle);
|
||||
}
|
||||
@@ -776,7 +776,7 @@ pomelo! {
|
||||
// function
|
||||
function_prototype ::= function_declarator(f) RightParen {
|
||||
// prelude, add global var expressions
|
||||
for (var_handle, var) in extra.global_variables.iter() {
|
||||
for (var_handle, var) in extra.module.global_variables.iter() {
|
||||
if let Some(name) = var.name.as_ref() {
|
||||
let exp = extra.context.expressions.append(
|
||||
Expression::GlobalVariable(var_handle)
|
||||
@@ -828,9 +828,19 @@ pomelo! {
|
||||
translation_unit ::= translation_unit external_declaration;
|
||||
|
||||
external_declaration ::= function_definition(f) {
|
||||
let name = f.name.clone();
|
||||
let handle = extra.functions.append(f);
|
||||
if let Some(name) = name {
|
||||
if f.name == extra.entry {
|
||||
let name = extra.entry.take().unwrap();
|
||||
extra.module.entry_points.insert(
|
||||
(extra.shader_stage, name),
|
||||
EntryPoint {
|
||||
early_depth_test: None,
|
||||
workgroup_size: [1; 3], //TODO
|
||||
function: f,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let name = f.name.clone().unwrap();
|
||||
let handle = extra.module.functions.append(f);
|
||||
extra.lookup_function.insert(name, handle);
|
||||
}
|
||||
}
|
||||
@@ -848,7 +858,7 @@ pomelo! {
|
||||
});
|
||||
|
||||
for (id, initializer) in d.ids_initializers {
|
||||
let h = extra.global_variables.fetch_or_append(
|
||||
let h = extra.module.global_variables.fetch_or_append(
|
||||
GlobalVariable {
|
||||
name: Some(id.clone()),
|
||||
class,
|
||||
@@ -868,7 +878,7 @@ pomelo! {
|
||||
extra.context.clear_scopes();
|
||||
extra.context.lookup_global_var_exps.clear();
|
||||
f.body = cs;
|
||||
f.global_usage = crate::GlobalUse::scan(&f.expressions, &f.body, &extra.global_variables);
|
||||
f.fill_global_use(&extra.module.global_variables);
|
||||
f
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::parser;
|
||||
use crate::ShaderStage;
|
||||
|
||||
fn parse_program(source: &str, stage: ShaderStage) -> Result<Program, ErrorKind> {
|
||||
let mut program = Program::new(stage);
|
||||
let mut program = Program::new(stage, "".to_string());
|
||||
let lex = Lexer::new(source);
|
||||
let mut parser = parser::Parser::new(&mut program);
|
||||
|
||||
|
||||
@@ -18,25 +18,28 @@ impl Program {
|
||||
return Err(ErrorKind::VariableNotAvailable(name.into()));
|
||||
}
|
||||
};
|
||||
let h = self.global_variables.fetch_or_append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: if self.shader_stage == ShaderStage::Vertex {
|
||||
StorageClass::Output
|
||||
} else {
|
||||
StorageClass::Input
|
||||
},
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
|
||||
ty: self.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
let h = self
|
||||
.module
|
||||
.global_variables
|
||||
.fetch_or_append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: if self.shader_stage == ShaderStage::Vertex {
|
||||
StorageClass::Output
|
||||
} else {
|
||||
StorageClass::Input
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
storage_access: StorageAccess::empty(),
|
||||
});
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
|
||||
ty: self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
storage_access: StorageAccess::empty(),
|
||||
});
|
||||
self.lookup_global_variables.insert(name.into(), h);
|
||||
let exp = self
|
||||
.context
|
||||
@@ -54,20 +57,23 @@ impl Program {
|
||||
return Err(ErrorKind::VariableNotAvailable(name.into()));
|
||||
}
|
||||
};
|
||||
let h = self.global_variables.fetch_or_append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Input,
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::VertexIndex)),
|
||||
ty: self.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
storage_access: StorageAccess::empty(),
|
||||
});
|
||||
let h = self
|
||||
.module
|
||||
.global_variables
|
||||
.fetch_or_append(GlobalVariable {
|
||||
name: Some(name.into()),
|
||||
class: StorageClass::Input,
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::VertexIndex)),
|
||||
ty: self.module.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
storage_access: StorageAccess::empty(),
|
||||
});
|
||||
self.lookup_global_variables.insert(name.into(), h);
|
||||
let exp = self
|
||||
.context
|
||||
|
||||
@@ -19,7 +19,7 @@ impl crate::Module {
|
||||
constants: Arena::new(),
|
||||
global_variables: Arena::new(),
|
||||
functions: Arena::new(),
|
||||
entry_points: Vec::new(),
|
||||
entry_points: crate::FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,123 +49,142 @@ pub enum Terminator {
|
||||
Unreachable,
|
||||
}
|
||||
|
||||
pub fn parse_function<I: Iterator<Item = u32>>(
|
||||
parser: &mut super::Parser<I>,
|
||||
inst: Instruction,
|
||||
module: &mut crate::Module,
|
||||
) -> Result<(), Error> {
|
||||
parser.switch(ModuleState::Function, inst.op)?;
|
||||
inst.expect(5)?;
|
||||
let result_type = parser.next()?;
|
||||
let fun_id = parser.next()?;
|
||||
let _fun_control = parser.next()?;
|
||||
let fun_type = parser.next()?;
|
||||
let mut fun = {
|
||||
let ft = parser.lookup_function_type.lookup(fun_type)?;
|
||||
if ft.return_type_id != result_type {
|
||||
return Err(Error::WrongFunctionResultType(result_type));
|
||||
}
|
||||
crate::Function {
|
||||
name: parser.future_decor.remove(&fun_id).and_then(|dec| dec.name),
|
||||
parameter_types: Vec::with_capacity(ft.parameter_type_ids.len()),
|
||||
return_type: if parser.lookup_void_type.contains(&result_type) {
|
||||
None
|
||||
} else {
|
||||
Some(parser.lookup_type.lookup(result_type)?.handle)
|
||||
},
|
||||
global_usage: Vec::new(),
|
||||
local_variables: Arena::new(),
|
||||
expressions: parser.make_expression_storage(),
|
||||
body: Vec::new(),
|
||||
}
|
||||
};
|
||||
impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
pub fn parse_function(
|
||||
&mut self,
|
||||
inst: Instruction,
|
||||
module: &mut crate::Module,
|
||||
) -> Result<(), Error> {
|
||||
self.switch(ModuleState::Function, inst.op)?;
|
||||
inst.expect(5)?;
|
||||
let result_type = self.next()?;
|
||||
let fun_id = self.next()?;
|
||||
let _fun_control = self.next()?;
|
||||
let fun_type = self.next()?;
|
||||
|
||||
// read parameters
|
||||
for i in 0..fun.parameter_types.capacity() {
|
||||
match parser.next_inst()? {
|
||||
Instruction {
|
||||
op: spirv::Op::FunctionParameter,
|
||||
wc: 3,
|
||||
} => {
|
||||
let type_id = parser.next()?;
|
||||
let id = parser.next()?;
|
||||
let handle = fun
|
||||
.expressions
|
||||
.append(crate::Expression::FunctionParameter(i as u32));
|
||||
parser
|
||||
.lookup_expression
|
||||
.insert(id, LookupExpression { type_id, handle });
|
||||
//Note: we redo the lookup in order to work around `parser` borrowing
|
||||
let mut fun = {
|
||||
let ft = self.lookup_function_type.lookup(fun_type)?;
|
||||
if ft.return_type_id != result_type {
|
||||
return Err(Error::WrongFunctionResultType(result_type));
|
||||
}
|
||||
crate::Function {
|
||||
name: self.future_decor.remove(&fun_id).and_then(|dec| dec.name),
|
||||
parameter_types: Vec::with_capacity(ft.parameter_type_ids.len()),
|
||||
return_type: if self.lookup_void_type.contains(&result_type) {
|
||||
None
|
||||
} else {
|
||||
Some(self.lookup_type.lookup(result_type)?.handle)
|
||||
},
|
||||
global_usage: Vec::new(),
|
||||
local_variables: Arena::new(),
|
||||
expressions: self.make_expression_storage(),
|
||||
body: Vec::new(),
|
||||
}
|
||||
};
|
||||
|
||||
if type_id
|
||||
!= parser
|
||||
.lookup_function_type
|
||||
.lookup(fun_type)?
|
||||
.parameter_type_ids[i]
|
||||
{
|
||||
return Err(Error::WrongFunctionParameterType(type_id));
|
||||
// read parameters
|
||||
for i in 0..fun.parameter_types.capacity() {
|
||||
match self.next_inst()? {
|
||||
Instruction {
|
||||
op: spirv::Op::FunctionParameter,
|
||||
wc: 3,
|
||||
} => {
|
||||
let type_id = self.next()?;
|
||||
let id = self.next()?;
|
||||
let handle = fun
|
||||
.expressions
|
||||
.append(crate::Expression::FunctionParameter(i as u32));
|
||||
self.lookup_expression
|
||||
.insert(id, LookupExpression { type_id, handle });
|
||||
//Note: we redo the lookup in order to work around `self` borrowing
|
||||
|
||||
if type_id
|
||||
!= self
|
||||
.lookup_function_type
|
||||
.lookup(fun_type)?
|
||||
.parameter_type_ids[i]
|
||||
{
|
||||
return Err(Error::WrongFunctionParameterType(type_id));
|
||||
}
|
||||
let ty = self.lookup_type.lookup(type_id)?.handle;
|
||||
fun.parameter_types.push(ty);
|
||||
}
|
||||
let ty = parser.lookup_type.lookup(type_id)?.handle;
|
||||
fun.parameter_types.push(ty);
|
||||
}
|
||||
Instruction { op, .. } => return Err(Error::InvalidParameter(op)),
|
||||
}
|
||||
}
|
||||
|
||||
// Read body
|
||||
let mut local_function_calls = FastHashMap::default();
|
||||
let mut flow_graph = FlowGraph::new();
|
||||
|
||||
// Scan the blocks and add them as nodes
|
||||
loop {
|
||||
let fun_inst = parser.next_inst()?;
|
||||
log::debug!("{:?}", fun_inst.op);
|
||||
match fun_inst.op {
|
||||
spirv::Op::Label => {
|
||||
// Read the label ID
|
||||
fun_inst.expect(2)?;
|
||||
let block_id = parser.next()?;
|
||||
|
||||
let node = parser.next_block(
|
||||
block_id,
|
||||
&mut fun.expressions,
|
||||
&mut fun.local_variables,
|
||||
&module.types,
|
||||
&module.constants,
|
||||
&module.global_variables,
|
||||
&mut local_function_calls,
|
||||
)?;
|
||||
|
||||
flow_graph.add_node(node);
|
||||
}
|
||||
spirv::Op::FunctionEnd => {
|
||||
fun_inst.expect(1)?;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedInstruction(parser.state, fun_inst.op));
|
||||
Instruction { op, .. } => return Err(Error::InvalidParameter(op)),
|
||||
}
|
||||
}
|
||||
|
||||
// Read body
|
||||
let mut local_function_calls = FastHashMap::default();
|
||||
let mut flow_graph = FlowGraph::new();
|
||||
|
||||
// Scan the blocks and add them as nodes
|
||||
loop {
|
||||
let fun_inst = self.next_inst()?;
|
||||
log::debug!("{:?}", fun_inst.op);
|
||||
match fun_inst.op {
|
||||
spirv::Op::Label => {
|
||||
// Read the label ID
|
||||
fun_inst.expect(2)?;
|
||||
let block_id = self.next()?;
|
||||
|
||||
let node = self.next_block(
|
||||
block_id,
|
||||
&mut fun.expressions,
|
||||
&mut fun.local_variables,
|
||||
&module.types,
|
||||
&module.constants,
|
||||
&module.global_variables,
|
||||
&mut local_function_calls,
|
||||
)?;
|
||||
|
||||
flow_graph.add_node(node);
|
||||
}
|
||||
spirv::Op::FunctionEnd => {
|
||||
fun_inst.expect(1)?;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedInstruction(self.state, fun_inst.op));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flow_graph.classify();
|
||||
flow_graph.remove_phi_instructions(&self.lookup_expression);
|
||||
fun.body = flow_graph.to_naga()?;
|
||||
|
||||
// done
|
||||
fun.fill_global_use(&module.global_variables);
|
||||
|
||||
let source = match self.lookup_entry_point.remove(&fun_id) {
|
||||
Some(ep) => {
|
||||
module.entry_points.insert(
|
||||
(ep.stage, ep.name.clone()),
|
||||
crate::EntryPoint {
|
||||
early_depth_test: ep.early_depth_test,
|
||||
workgroup_size: ep.workgroup_size,
|
||||
function: fun,
|
||||
},
|
||||
);
|
||||
DeferredSource::EntryPoint(ep.stage, ep.name)
|
||||
}
|
||||
None => {
|
||||
let handle = module.functions.append(fun);
|
||||
self.lookup_function.insert(fun_id, handle);
|
||||
DeferredSource::Function(handle)
|
||||
}
|
||||
};
|
||||
|
||||
for (expr_handle, dst_id) in local_function_calls {
|
||||
self.deferred_function_calls.push(DeferredFunctionCall {
|
||||
source: source.clone(),
|
||||
expr_handle,
|
||||
dst_id,
|
||||
});
|
||||
}
|
||||
|
||||
self.lookup_expression.clear();
|
||||
self.lookup_sampled_image.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
flow_graph.classify();
|
||||
flow_graph.remove_phi_instructions(&parser.lookup_expression);
|
||||
fun.body = flow_graph.to_naga()?;
|
||||
|
||||
// done
|
||||
fun.global_usage =
|
||||
crate::GlobalUse::scan(&fun.expressions, &fun.body, &module.global_variables);
|
||||
let handle = module.functions.append(fun);
|
||||
for (expr_handle, dst_id) in local_function_calls {
|
||||
parser.deferred_function_calls.push(DeferredFunctionCall {
|
||||
source_handle: handle,
|
||||
expr_handle,
|
||||
dst_id,
|
||||
});
|
||||
}
|
||||
|
||||
parser.lookup_function.insert(fun_id, handle);
|
||||
parser.lookup_expression.clear();
|
||||
parser.lookup_sampled_image.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -197,10 +197,10 @@ impl Decoration {
|
||||
Decoration {
|
||||
built_in: None,
|
||||
location: None,
|
||||
desc_set: Some(set),
|
||||
desc_set: Some(group),
|
||||
desc_index: Some(binding),
|
||||
..
|
||||
} => Some(crate::Binding::Descriptor { set, binding }),
|
||||
} => Some(crate::Binding::Resource { group, binding }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -252,6 +252,8 @@ struct LookupFunctionType {
|
||||
struct EntryPoint {
|
||||
stage: crate::ShaderStage,
|
||||
name: String,
|
||||
early_depth_test: Option<crate::EarlyDepthTest>,
|
||||
workgroup_size: [u32; 3],
|
||||
function_id: spirv::Word,
|
||||
variable_ids: Vec<spirv::Word>,
|
||||
}
|
||||
@@ -285,8 +287,13 @@ struct LookupSampledImage {
|
||||
image: Handle<crate::Expression>,
|
||||
sampler: Handle<crate::Expression>,
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
enum DeferredSource {
|
||||
EntryPoint(crate::ShaderStage, String),
|
||||
Function(Handle<crate::Function>),
|
||||
}
|
||||
struct DeferredFunctionCall {
|
||||
source_handle: Handle<crate::Function>,
|
||||
source: DeferredSource,
|
||||
expr_handle: Handle<crate::Expression>,
|
||||
dst_id: spirv::Word,
|
||||
}
|
||||
@@ -1444,7 +1451,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module),
|
||||
Op::ConstantComposite => self.parse_composite_constant(inst, &mut module),
|
||||
Op::Variable => self.parse_global_variable(inst, &mut module),
|
||||
Op::Function => parse_function(&mut self, inst, &mut module),
|
||||
Op::Function => self.parse_function(inst, &mut module),
|
||||
_ => Err(Error::UnsupportedInstruction(self.state, inst.op)), //TODO
|
||||
}?;
|
||||
}
|
||||
@@ -1476,12 +1483,17 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
|
||||
for dfc in self.deferred_function_calls.drain(..) {
|
||||
let dst_handle = *self.lookup_function.lookup(dfc.dst_id)?;
|
||||
match *module
|
||||
.functions
|
||||
.get_mut(dfc.source_handle)
|
||||
.expressions
|
||||
.get_mut(dfc.expr_handle)
|
||||
{
|
||||
let fun = match dfc.source {
|
||||
DeferredSource::Function(fun_handle) => module.functions.get_mut(fun_handle),
|
||||
DeferredSource::EntryPoint(stage, name) => {
|
||||
&mut module
|
||||
.entry_points
|
||||
.get_mut(&(stage, name))
|
||||
.unwrap()
|
||||
.function
|
||||
}
|
||||
};
|
||||
match *fun.expressions.get_mut(dfc.expr_handle) {
|
||||
crate::Expression::Call {
|
||||
ref mut origin,
|
||||
arguments: _,
|
||||
@@ -1499,15 +1511,6 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
self.future_member_decor.clear();
|
||||
}
|
||||
|
||||
module.entry_points.reserve(self.lookup_entry_point.len());
|
||||
for raw in self.lookup_entry_point.values() {
|
||||
module.entry_points.push(crate::EntryPoint {
|
||||
stage: raw.stage,
|
||||
name: raw.name.clone(),
|
||||
function: *self.lookup_function.lookup(raw.function_id)?,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
@@ -1570,15 +1573,13 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let ep = EntryPoint {
|
||||
stage: match exec_model {
|
||||
spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex,
|
||||
spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
},
|
||||
spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment,
|
||||
spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute,
|
||||
_ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)),
|
||||
},
|
||||
name,
|
||||
early_depth_test: None,
|
||||
workgroup_size: [0; 3],
|
||||
function_id,
|
||||
variable_ids: self.data.by_ref().take(left as usize).collect(),
|
||||
};
|
||||
@@ -1587,7 +1588,6 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
}
|
||||
|
||||
fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> {
|
||||
use crate::ShaderStage;
|
||||
use spirv::ExecutionMode;
|
||||
|
||||
self.switch(ModuleState::ExecutionMode, inst.op)?;
|
||||
@@ -1597,63 +1597,47 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let mode_id = self.next()?;
|
||||
let args: Vec<spirv::Word> = self.data.by_ref().take(inst.wc as usize - 3).collect();
|
||||
|
||||
let ep: &mut EntryPoint = self
|
||||
let ep = self
|
||||
.lookup_entry_point
|
||||
.get_mut(&ep_id)
|
||||
.ok_or(Error::InvalidId(ep_id))?;
|
||||
let mode = spirv::ExecutionMode::from_u32(mode_id)
|
||||
.ok_or(Error::UnsupportedExecutionMode(mode_id))?;
|
||||
|
||||
match ep.stage {
|
||||
ShaderStage::Fragment {
|
||||
ref mut early_depth_test,
|
||||
} => {
|
||||
match mode {
|
||||
ExecutionMode::EarlyFragmentTests => {
|
||||
if early_depth_test.is_none() {
|
||||
*early_depth_test = Some(crate::EarlyDepthTest { conservative: None });
|
||||
}
|
||||
}
|
||||
ExecutionMode::DepthUnchanged => {
|
||||
*early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::Unchanged),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthGreater => {
|
||||
*early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::GreaterEqual),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthLess => {
|
||||
*early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::LessEqual),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthReplacing => {
|
||||
// Ignored because it can be deduced from the IR.
|
||||
}
|
||||
ExecutionMode::OriginUpperLeft => {
|
||||
// Ignored because the other option (OriginLowerLeft) is not valid in Vulkan mode.
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedExecutionMode(mode_id));
|
||||
}
|
||||
};
|
||||
match mode {
|
||||
ExecutionMode::EarlyFragmentTests => {
|
||||
if ep.early_depth_test.is_none() {
|
||||
ep.early_depth_test = Some(crate::EarlyDepthTest { conservative: None });
|
||||
}
|
||||
}
|
||||
ShaderStage::Compute { ref mut local_size } => {
|
||||
match mode {
|
||||
ExecutionMode::LocalSize => {
|
||||
*local_size = (args[0], args[1], args[2]);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedExecutionMode(mode_id));
|
||||
}
|
||||
};
|
||||
ExecutionMode::DepthUnchanged => {
|
||||
ep.early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::Unchanged),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthGreater => {
|
||||
ep.early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::GreaterEqual),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthLess => {
|
||||
ep.early_depth_test = Some(crate::EarlyDepthTest {
|
||||
conservative: Some(crate::ConservativeDepth::LessEqual),
|
||||
});
|
||||
}
|
||||
ExecutionMode::DepthReplacing => {
|
||||
// Ignored because it can be deduced from the IR.
|
||||
}
|
||||
ExecutionMode::OriginUpperLeft => {
|
||||
// Ignored because the other option (OriginLowerLeft) is not valid in Vulkan mode.
|
||||
}
|
||||
ExecutionMode::LocalSize => {
|
||||
ep.workgroup_size = [args[0], args[1], args[2]];
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedExecutionMode(mode_id));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -320,12 +320,8 @@ impl Parser {
|
||||
fn get_shader_stage(word: &str) -> Result<crate::ShaderStage, Error<'_>> {
|
||||
match word {
|
||||
"vertex" => Ok(crate::ShaderStage::Vertex),
|
||||
"fragment" => Ok(crate::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
}),
|
||||
"compute" => Ok(crate::ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
}),
|
||||
"fragment" => Ok(crate::ShaderStage::Fragment),
|
||||
"compute" => Ok(crate::ShaderStage::Compute),
|
||||
_ => Err(Error::UnknownShaderStage(word)),
|
||||
}
|
||||
}
|
||||
@@ -563,7 +559,6 @@ impl Parser {
|
||||
Token::Separator('.') => {
|
||||
let _ = lexer.next();
|
||||
let name = lexer.next_ident()?;
|
||||
println!("Resolving '{}' for {:?}", name, ctx.resolve_type(handle)); //TEMP
|
||||
let expression = match *ctx.resolve_type(handle)? {
|
||||
crate::TypeInner::Struct { ref members } => {
|
||||
let index = members
|
||||
@@ -918,7 +913,9 @@ impl Parser {
|
||||
ready = true;
|
||||
}
|
||||
Token::Word("offset") if ready => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
offset = lexer.next_uint_literal()?;
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
ready = false;
|
||||
}
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
@@ -1288,7 +1285,7 @@ impl Parser {
|
||||
lexer: &mut Lexer<'a>,
|
||||
module: &mut crate::Module,
|
||||
lookup_global_expression: &FastHashMap<&'a str, crate::Expression>,
|
||||
) -> Result<Handle<crate::Function>, Error<'a>> {
|
||||
) -> Result<(crate::Function, &'a str), Error<'a>> {
|
||||
self.scopes.push(Scope::FunctionDecl);
|
||||
// read function name
|
||||
let mut lookup_ident = FastHashMap::default();
|
||||
@@ -1322,7 +1319,7 @@ impl Parser {
|
||||
Some(self.parse_type_decl(lexer, None, &mut module.types)?.0)
|
||||
};
|
||||
|
||||
let fun_handle = module.functions.append(crate::Function {
|
||||
let mut fun = crate::Function {
|
||||
name: Some(fun_name.to_string()),
|
||||
parameter_types,
|
||||
return_type,
|
||||
@@ -1330,15 +1327,7 @@ impl Parser {
|
||||
local_variables: Arena::new(),
|
||||
expressions,
|
||||
body: Vec::new(),
|
||||
});
|
||||
if self
|
||||
.function_lookup
|
||||
.insert(fun_name.to_string(), fun_handle)
|
||||
.is_some()
|
||||
{
|
||||
return Err(Error::FunctionRedefinition(fun_name));
|
||||
}
|
||||
let fun = module.functions.get_mut(fun_handle);
|
||||
};
|
||||
|
||||
// read body
|
||||
let mut typifier = Typifier::new();
|
||||
@@ -1356,11 +1345,10 @@ impl Parser {
|
||||
},
|
||||
)?;
|
||||
// done
|
||||
fun.global_usage =
|
||||
crate::GlobalUse::scan(&fun.expressions, &fun.body, &module.global_variables);
|
||||
fun.fill_global_use(&module.global_variables);
|
||||
self.scopes.pop();
|
||||
|
||||
Ok(fun_handle)
|
||||
Ok((fun, fun_name))
|
||||
}
|
||||
|
||||
fn parse_global_decl<'a>(
|
||||
@@ -1373,30 +1361,56 @@ impl Parser {
|
||||
let mut binding = None;
|
||||
// Perspective is the default qualifier.
|
||||
let mut interpolation = None;
|
||||
let mut stage = None;
|
||||
let mut workgroup_size = [1u32; 3];
|
||||
|
||||
if lexer.skip(Token::DoubleParen('[')) {
|
||||
let (mut bind_index, mut bind_set) = (None, None);
|
||||
let (mut bind_index, mut bind_group) = (None, None);
|
||||
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 = Self::get_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()?);
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
"set" => {
|
||||
bind_set = Some(lexer.next_uint_literal()?);
|
||||
"group" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
bind_group = Some(lexer.next_uint_literal()?);
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
"interpolate" => {
|
||||
if interpolation.is_some() {
|
||||
return Err(Error::UnknownDecoration(lexer.next_ident()?));
|
||||
}
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
interpolation = Some(Self::get_interpolation(lexer.next_ident()?)?);
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
"stage" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
stage = Some(Self::get_shader_stage(lexer.next_ident()?)?);
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
"workgroup_size" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
for (i, size) in workgroup_size.iter_mut().enumerate() {
|
||||
*size = lexer.next_uint_literal()?;
|
||||
match lexer.next() {
|
||||
Token::Paren(')') => break,
|
||||
Token::Separator(',') if i != 2 => (),
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
word => return Err(Error::UnknownDecoration(word)),
|
||||
}
|
||||
@@ -1408,15 +1422,11 @@ impl Parser {
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
}
|
||||
}
|
||||
match (bind_set, bind_index) {
|
||||
(Some(set), Some(index)) if binding.is_none() => {
|
||||
binding = Some(crate::Binding::Descriptor {
|
||||
set,
|
||||
binding: index,
|
||||
});
|
||||
}
|
||||
_ if binding.is_none() => return Err(Error::Other),
|
||||
_ => {}
|
||||
if let (Some(group), Some(index)) = (bind_group, bind_index) {
|
||||
binding = Some(crate::Binding::Resource {
|
||||
group,
|
||||
binding: index,
|
||||
});
|
||||
}
|
||||
self.scopes.pop();
|
||||
}
|
||||
@@ -1494,31 +1504,30 @@ impl Parser {
|
||||
.insert(pvar.name, crate::Expression::GlobalVariable(var_handle));
|
||||
}
|
||||
Token::Word("fn") => {
|
||||
self.parse_function_decl(lexer, module, &lookup_global_expression)?;
|
||||
}
|
||||
Token::Word("entry_point") => {
|
||||
let stage = Self::get_shader_stage(lexer.next_ident()?)?;
|
||||
let export_name = if lexer.skip(Token::Word("as")) {
|
||||
match lexer.next() {
|
||||
Token::String(name) => Some(name),
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
let (function, name) =
|
||||
self.parse_function_decl(lexer, module, &lookup_global_expression)?;
|
||||
let already_declared = match stage {
|
||||
Some(stage) => module
|
||||
.entry_points
|
||||
.insert(
|
||||
(stage, name.to_string()),
|
||||
crate::EntryPoint {
|
||||
early_depth_test: None,
|
||||
workgroup_size,
|
||||
function,
|
||||
},
|
||||
)
|
||||
.is_some(),
|
||||
None => {
|
||||
let fun_handle = module.functions.append(function);
|
||||
self.function_lookup
|
||||
.insert(name.to_string(), fun_handle)
|
||||
.is_some()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lexer.expect(Token::Operation('='))?;
|
||||
let fun_ident = lexer.next_ident()?;
|
||||
lexer.expect(Token::Separator(';'))?;
|
||||
let (fun_handle, _) = module
|
||||
.functions
|
||||
.iter()
|
||||
.find(|(_, fun)| fun.name.as_deref() == Some(fun_ident))
|
||||
.ok_or(Error::UnknownFunction(fun_ident))?;
|
||||
module.entry_points.push(crate::EntryPoint {
|
||||
stage,
|
||||
name: export_name.unwrap_or(fun_ident).to_owned(),
|
||||
function: fun_handle,
|
||||
});
|
||||
if already_declared {
|
||||
return Err(Error::FunctionRedefinition(name));
|
||||
}
|
||||
}
|
||||
Token::End => return Ok(false),
|
||||
token => return Err(Error::Unexpected(token)),
|
||||
|
||||
32
src/lib.rs
32
src/lib.rs
@@ -88,18 +88,14 @@ pub enum ConservativeDepth {
|
||||
}
|
||||
|
||||
/// Stage of the programmable pipeline.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
#[allow(missing_docs)] // The names are self evident
|
||||
pub enum ShaderStage {
|
||||
Vertex,
|
||||
Fragment {
|
||||
early_depth_test: Option<EarlyDepthTest>,
|
||||
},
|
||||
Compute {
|
||||
local_size: (u32, u32, u32),
|
||||
},
|
||||
Fragment,
|
||||
Compute,
|
||||
}
|
||||
|
||||
/// Class of storage for variables.
|
||||
@@ -416,8 +412,8 @@ pub enum Binding {
|
||||
BuiltIn(BuiltIn),
|
||||
/// Indexed location.
|
||||
Location(u32),
|
||||
/// Binding within a descriptor set.
|
||||
Descriptor { set: u32, binding: u32 },
|
||||
/// Binding within a resource group.
|
||||
Resource { group: u32, binding: u32 },
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
@@ -635,7 +631,7 @@ pub enum Expression {
|
||||
origin: FunctionOrigin,
|
||||
arguments: Vec<Handle<Expression>>,
|
||||
},
|
||||
/// Get dynamic array length.
|
||||
/// Get the length of an array.
|
||||
ArrayLength(Handle<Expression>),
|
||||
}
|
||||
|
||||
@@ -718,12 +714,12 @@ pub struct Function {
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct EntryPoint {
|
||||
/// The stage in the programmable pipeline this entry point is for.
|
||||
pub stage: ShaderStage,
|
||||
/// Name identifying this entry point.
|
||||
pub name: String,
|
||||
/// The function to be used.
|
||||
pub function: Handle<Function>,
|
||||
/// Early depth test for fragment stages.
|
||||
pub early_depth_test: Option<EarlyDepthTest>,
|
||||
/// Workgroup size for compute stages
|
||||
pub workgroup_size: [u32; 3],
|
||||
/// The entrance function.
|
||||
pub function: Function,
|
||||
}
|
||||
|
||||
/// Shader module.
|
||||
@@ -751,6 +747,6 @@ pub struct Module {
|
||||
pub global_variables: Arena<GlobalVariable>,
|
||||
/// Storage for the functions defined in this module.
|
||||
pub functions: Arena<Function>,
|
||||
/// Vector of exported entry points.
|
||||
pub entry_points: Vec<EntryPoint>,
|
||||
/// Exported entry points.
|
||||
pub entry_points: FastHashMap<(ShaderStage, String), EntryPoint>,
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ use crate::arena::{Arena, Handle};
|
||||
|
||||
pub struct Interface<'a, T> {
|
||||
pub expressions: &'a Arena<crate::Expression>,
|
||||
pub visitor: &'a mut T,
|
||||
pub visitor: T,
|
||||
}
|
||||
|
||||
pub trait Visitor {
|
||||
fn visit_expr(&mut self, _: &crate::Expression) {}
|
||||
fn visit_lhs_expr(&mut self, _: &crate::Expression) {}
|
||||
fn visit_fun(&mut self, _: Handle<crate::Function>) {}
|
||||
}
|
||||
|
||||
impl<'a, T> Interface<'a, T>
|
||||
@@ -95,10 +96,16 @@ where
|
||||
E::Derivative { expr, .. } => {
|
||||
self.traverse_expr(expr);
|
||||
}
|
||||
E::Call { ref arguments, .. } => {
|
||||
E::Call {
|
||||
ref origin,
|
||||
ref arguments,
|
||||
} => {
|
||||
for &argument in arguments {
|
||||
self.traverse_expr(argument);
|
||||
}
|
||||
if let crate::FunctionOrigin::Local(fun) = *origin {
|
||||
self.visitor.visit_fun(fun);
|
||||
}
|
||||
}
|
||||
E::ArrayLength(expr) => {
|
||||
self.traverse_expr(expr);
|
||||
@@ -168,9 +175,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct GlobalUseVisitor(Vec<crate::GlobalUse>);
|
||||
struct GlobalUseVisitor<'a>(&'a mut [crate::GlobalUse]);
|
||||
|
||||
impl Visitor for GlobalUseVisitor {
|
||||
impl Visitor for GlobalUseVisitor<'_> {
|
||||
fn visit_expr(&mut self, expr: &crate::Expression) {
|
||||
if let crate::Expression::GlobalVariable(handle) = expr {
|
||||
self.0[handle.index()] |= crate::GlobalUse::LOAD;
|
||||
@@ -184,20 +191,17 @@ impl Visitor for GlobalUseVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::GlobalUse {
|
||||
pub fn scan(
|
||||
expressions: &Arena<crate::Expression>,
|
||||
body: &[crate::Statement],
|
||||
globals: &Arena<crate::GlobalVariable>,
|
||||
) -> Vec<Self> {
|
||||
let mut visitor = GlobalUseVisitor(vec![crate::GlobalUse::empty(); globals.len()]);
|
||||
impl crate::Function {
|
||||
pub fn fill_global_use(&mut self, globals: &Arena<crate::GlobalVariable>) {
|
||||
self.global_usage.clear();
|
||||
self.global_usage
|
||||
.resize(globals.len(), crate::GlobalUse::empty());
|
||||
|
||||
let mut io = Interface {
|
||||
expressions,
|
||||
visitor: &mut visitor,
|
||||
expressions: &self.expressions,
|
||||
visitor: GlobalUseVisitor(&mut self.global_usage),
|
||||
};
|
||||
io.traverse(body);
|
||||
visitor.0
|
||||
io.traverse(&self.body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,14 +252,25 @@ mod tests {
|
||||
},
|
||||
];
|
||||
|
||||
let mut function = crate::Function {
|
||||
name: None,
|
||||
parameter_types: Vec::new(),
|
||||
return_type: None,
|
||||
local_variables: Arena::new(),
|
||||
expressions,
|
||||
global_usage: Vec::new(),
|
||||
body: test_body,
|
||||
};
|
||||
function.fill_global_use(&test_globals);
|
||||
|
||||
assert_eq!(
|
||||
GlobalUse::scan(&expressions, &test_body, &test_globals),
|
||||
vec![
|
||||
&function.global_usage,
|
||||
&[
|
||||
GlobalUse::LOAD,
|
||||
GlobalUse::STORE,
|
||||
GlobalUse::STORE,
|
||||
GlobalUse::LOAD,
|
||||
]
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(
|
||||
metal_bindings: {
|
||||
(set: 0, binding: 0): (buffer: Some(0), texture: None, sampler: None, mutable: false),
|
||||
(set: 0, binding: 1): (buffer: Some(1), texture: None, sampler: None, mutable: true),
|
||||
(set: 0, binding: 2): (buffer: Some(2), texture: None, sampler: None, mutable: true),
|
||||
(group: 0, binding: 0): (buffer: Some(0), texture: None, sampler: None, mutable: false),
|
||||
(group: 0, binding: 1): (buffer: Some(1), texture: None, sampler: None, mutable: true),
|
||||
(group: 0, binding: 2): (buffer: Some(2), texture: None, sampler: None, mutable: true),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -16,12 +16,13 @@ import "GLSL.std.450" as std;
|
||||
|
||||
# vertex shader
|
||||
|
||||
[[location 0]] var<in> a_particlePos : vec2<f32>;
|
||||
[[location 1]] var<in> a_particleVel : vec2<f32>;
|
||||
[[location 2]] var<in> a_pos : vec2<f32>;
|
||||
[[builtin position]] var gl_Position : vec4<f32>;
|
||||
[[location(0)]] var<in> a_particlePos : vec2<f32>;
|
||||
[[location(1)]] var<in> a_particleVel : vec2<f32>;
|
||||
[[location(2)]] var<in> a_pos : vec2<f32>;
|
||||
[[builtin(position)]] var gl_Position : vec4<f32>;
|
||||
|
||||
fn vtx_main() -> void {
|
||||
[[stage(vertex)]]
|
||||
fn main() -> void {
|
||||
var angle : f32 = -std::atan2(a_particleVel.x, a_particleVel.y);
|
||||
var pos : vec2<f32> = vec2<f32>(
|
||||
(a_pos.x * std::cos(angle)) - (a_pos.y * std::sin(angle)),
|
||||
@@ -29,45 +30,45 @@ fn vtx_main() -> void {
|
||||
gl_Position = vec4<f32>(pos + a_particlePos, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
entry_point vertex as "main" = vtx_main;
|
||||
|
||||
# fragment shader
|
||||
[[location 0]] var<out> fragColor : vec4<f32>;
|
||||
[[location(0)]] var<out> fragColor : vec4<f32>;
|
||||
|
||||
fn frag_main() -> void {
|
||||
[[stage(fragment)]]
|
||||
fn main() -> void {
|
||||
fragColor = vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
return;
|
||||
}
|
||||
entry_point fragment as "main" = frag_main;
|
||||
|
||||
# compute shader
|
||||
type Particle = struct {
|
||||
[[offset 0]] pos : vec2<f32>;
|
||||
[[offset 8]] vel : vec2<f32>;
|
||||
[[offset(0)]] pos : vec2<f32>;
|
||||
[[offset(8)]] vel : vec2<f32>;
|
||||
};
|
||||
|
||||
type SimParams = struct {
|
||||
[[offset 0]] deltaT : f32;
|
||||
[[offset 4]] rule1Distance : f32;
|
||||
[[offset 8]] rule2Distance : f32;
|
||||
[[offset 12]] rule3Distance : f32;
|
||||
[[offset 16]] rule1Scale : f32;
|
||||
[[offset 20]] rule2Scale : f32;
|
||||
[[offset 24]] rule3Scale : f32;
|
||||
[[offset(0)]] deltaT : f32;
|
||||
[[offset(4)]] rule1Distance : f32;
|
||||
[[offset(8)]] rule2Distance : f32;
|
||||
[[offset(12)]] rule3Distance : f32;
|
||||
[[offset(16)]] rule1Scale : f32;
|
||||
[[offset(20)]] rule2Scale : f32;
|
||||
[[offset(24)]] rule3Scale : f32;
|
||||
};
|
||||
|
||||
type Particles = struct {
|
||||
[[offset 0]] particles : [[stride 16]] array<Particle, 5>;
|
||||
[[offset(0)]] particles : [[stride 16]] array<Particle, 5>;
|
||||
};
|
||||
|
||||
[[binding 0, set 0]] var<uniform> params : SimParams;
|
||||
[[binding 1, set 0]] var<storage_buffer> particlesA : Particles;
|
||||
[[binding 2, set 0]] var<storage_buffer> particlesB : Particles;
|
||||
[[group(0), binding(0)]] var<uniform> params : SimParams;
|
||||
[[group(0), binding(1)]] var<storage_buffer> particlesA : Particles;
|
||||
[[group(0), binding(2)]] var<storage_buffer> particlesB : Particles;
|
||||
|
||||
[[builtin global_invocation_id]] var gl_GlobalInvocationID : vec3<u32>;
|
||||
[[builtin(global_invocation_id)]] var gl_GlobalInvocationID : vec3<u32>;
|
||||
|
||||
# https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
|
||||
fn compute_main() -> void {
|
||||
[[stage(compute)]]
|
||||
fn main() -> void {
|
||||
var index : u32 = gl_GlobalInvocationID.x;
|
||||
if (index >= 5) {
|
||||
return;
|
||||
@@ -148,5 +149,3 @@ fn compute_main() -> void {
|
||||
|
||||
return;
|
||||
}
|
||||
entry_point compute as "main" = compute_main;
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ fn test_function(test: f32) -> f32 {
|
||||
return test;
|
||||
}
|
||||
|
||||
fn main_vert() -> void {
|
||||
[[stage(vertex)]]
|
||||
fn main() -> void {
|
||||
var foo: f32 = std::glsl::distance(0.0, 1.0);
|
||||
var test: f32 = test_function(1.0);
|
||||
}
|
||||
|
||||
entry_point vertex as "main" = main_vert;
|
||||
@@ -1,24 +1,24 @@
|
||||
# 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>;
|
||||
[[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>;
|
||||
|
||||
fn main_vert() -> void {
|
||||
[[stage(vertex)]]
|
||||
fn main() -> void {
|
||||
o_position = vec4<f32>(c_scale * a_pos, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
entry_point vertex as "main" = main_vert;
|
||||
|
||||
# fragment
|
||||
[[location 0]] var<in> a_uv : vec2<f32>;
|
||||
[[location(0)]] var<in> a_uv : vec2<f32>;
|
||||
#layout(set = 0, binding = 0) uniform texture2D u_texture;
|
||||
#layout(set = 0, binding = 1) uniform sampler u_sampler;
|
||||
[[location 0]] var<out> o_color : vec4<f32>;
|
||||
[[location(0)]] var<out> o_color : vec4<f32>;
|
||||
|
||||
fn main_frag() -> void {
|
||||
[[stage(fragment)]]
|
||||
fn main() -> void {
|
||||
o_color = vec4<f32>(1.0, 0.0, 0.0, 1.0); #TODO: sample
|
||||
return;
|
||||
}
|
||||
entry_point fragment as "main" = main_frag;
|
||||
|
||||
@@ -64,58 +64,56 @@
|
||||
),
|
||||
),
|
||||
],
|
||||
functions: [
|
||||
(
|
||||
name: Some("main"),
|
||||
parameter_types: [],
|
||||
return_type: None,
|
||||
global_usage: [
|
||||
(
|
||||
bits: 1,
|
||||
),
|
||||
(
|
||||
bits: 2,
|
||||
),
|
||||
],
|
||||
local_variables: [
|
||||
(
|
||||
name: Some("w"),
|
||||
ty: 3,
|
||||
init: Some(3),
|
||||
),
|
||||
],
|
||||
expressions: [
|
||||
GlobalVariable(1),
|
||||
GlobalVariable(2),
|
||||
Constant(1),
|
||||
LocalVariable(1),
|
||||
Constant(2),
|
||||
Compose(
|
||||
ty: 2,
|
||||
components: [
|
||||
1,
|
||||
5,
|
||||
4,
|
||||
],
|
||||
),
|
||||
],
|
||||
body: [
|
||||
Empty,
|
||||
Store(
|
||||
pointer: 2,
|
||||
value: 6,
|
||||
),
|
||||
Return(
|
||||
value: None,
|
||||
),
|
||||
],
|
||||
functions: [],
|
||||
entry_points: {
|
||||
(Vertex, "main"): (
|
||||
early_depth_test: None,
|
||||
workgroup_size: (1, 1, 1),
|
||||
function: (
|
||||
name: Some("main"),
|
||||
parameter_types: [],
|
||||
return_type: None,
|
||||
global_usage: [
|
||||
(
|
||||
bits: 1,
|
||||
),
|
||||
(
|
||||
bits: 2,
|
||||
),
|
||||
],
|
||||
local_variables: [
|
||||
(
|
||||
name: Some("w"),
|
||||
ty: 3,
|
||||
init: Some(3),
|
||||
),
|
||||
],
|
||||
expressions: [
|
||||
GlobalVariable(1),
|
||||
GlobalVariable(2),
|
||||
Constant(1),
|
||||
LocalVariable(1),
|
||||
Constant(2),
|
||||
Compose(
|
||||
ty: 2,
|
||||
components: [
|
||||
1,
|
||||
5,
|
||||
4,
|
||||
],
|
||||
),
|
||||
],
|
||||
body: [
|
||||
Empty,
|
||||
Store(
|
||||
pointer: 2,
|
||||
value: 6,
|
||||
),
|
||||
Return(
|
||||
value: None,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
entry_points: [
|
||||
(
|
||||
stage: Vertex,
|
||||
name: "main",
|
||||
function: 1,
|
||||
),
|
||||
],
|
||||
},
|
||||
)
|
||||
@@ -1,10 +1,10 @@
|
||||
# vertex
|
||||
[[location 0]] var<in> a_pos : vec2<f32>;
|
||||
[[location 0]] var<out> o_pos : vec4<f32>;
|
||||
[[location(0)]] var<in> a_pos : vec2<f32>;
|
||||
[[location(0)]] var<out> o_pos : vec4<f32>;
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn main() -> void {
|
||||
var w: f32 = 1.0;
|
||||
o_pos = vec4<f32>(a_pos, 0.0, w);
|
||||
return;
|
||||
}
|
||||
entry_point vertex as "main" = main;
|
||||
|
||||
@@ -33,7 +33,10 @@ fn convert_quad() {
|
||||
use naga::back::msl;
|
||||
let mut binding_map = msl::BindingMap::default();
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 0 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 0,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: None,
|
||||
texture: Some(1),
|
||||
@@ -42,7 +45,10 @@ fn convert_quad() {
|
||||
},
|
||||
);
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 1 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 1,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: None,
|
||||
texture: None,
|
||||
@@ -67,7 +73,10 @@ fn convert_boids() {
|
||||
use naga::back::msl;
|
||||
let mut binding_map = msl::BindingMap::default();
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 0 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 0,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: Some(0),
|
||||
texture: None,
|
||||
@@ -76,7 +85,10 @@ fn convert_boids() {
|
||||
},
|
||||
);
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 1 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 1,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: Some(1),
|
||||
texture: None,
|
||||
@@ -85,7 +97,10 @@ fn convert_boids() {
|
||||
},
|
||||
);
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 2 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 2,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: Some(2),
|
||||
texture: None,
|
||||
@@ -113,7 +128,10 @@ fn convert_cube() {
|
||||
use naga::back::msl;
|
||||
let mut binding_map = msl::BindingMap::default();
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 0 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 0,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: Some(0),
|
||||
texture: None,
|
||||
@@ -122,7 +140,10 @@ fn convert_cube() {
|
||||
},
|
||||
);
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 1 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 1,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: None,
|
||||
texture: Some(1),
|
||||
@@ -131,7 +152,10 @@ fn convert_cube() {
|
||||
},
|
||||
);
|
||||
binding_map.insert(
|
||||
msl::BindSource { set: 0, binding: 2 },
|
||||
msl::BindSource {
|
||||
group: 0,
|
||||
binding: 2,
|
||||
},
|
||||
msl::BindTarget {
|
||||
buffer: None,
|
||||
texture: None,
|
||||
@@ -154,9 +178,7 @@ fn convert_phong_lighting() {
|
||||
let module = load_glsl(
|
||||
"glsl_phong_lighting.frag",
|
||||
"main",
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
naga::ShaderStage::Fragment,
|
||||
);
|
||||
naga::proc::Validator::new().validate(&module).unwrap();
|
||||
|
||||
@@ -176,9 +198,7 @@ fn convert_phong_lighting() {
|
||||
// let module = load_glsl(
|
||||
// "glsl_constant_expression.vert",
|
||||
// "main",
|
||||
// naga::ShaderStage::Fragment {
|
||||
// early_depth_test: None,
|
||||
// },
|
||||
// naga::ShaderStage::Fragment,
|
||||
// );
|
||||
// naga::proc::Validator::new().validate(&module).unwrap();
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user