mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Implement Execution Modes (#169)
Add documentation, make clippy happy Compilation errors Add some more docs Few more compilation errors Changes based on the review glsl-new parser fix Set default local size to (0, 0, 0) final cleanup Last design New design
This commit is contained in:
@@ -91,7 +91,9 @@ fn main() {
|
||||
naga::front::glsl_new::parse_str(
|
||||
&input,
|
||||
"main".to_string(),
|
||||
naga::ShaderStage::Fragment,
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -104,7 +106,9 @@ fn main() {
|
||||
naga::front::glsl::parse_str(
|
||||
&input,
|
||||
"main".to_string(),
|
||||
naga::ShaderStage::Fragment,
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -115,8 +119,14 @@ fn main() {
|
||||
#[cfg(feature = "glsl")]
|
||||
"comp" => {
|
||||
let input = fs::read_to_string(&args[1]).unwrap();
|
||||
naga::front::glsl::parse_str(&input, "main".to_string(), naga::ShaderStage::Compute)
|
||||
.unwrap()
|
||||
naga::front::glsl::parse_str(
|
||||
&input,
|
||||
"main".to_string(),
|
||||
naga::ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
#[cfg(feature = "deserialize")]
|
||||
"ron" => {
|
||||
@@ -209,8 +219,12 @@ fn main() {
|
||||
String::from("main"),
|
||||
match stage {
|
||||
"vert" => ShaderStage::Vertex,
|
||||
"frag" => ShaderStage::Fragment,
|
||||
"comp" => ShaderStage::Compute,
|
||||
"frag" => ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
"comp" => ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
),
|
||||
|
||||
@@ -129,7 +129,7 @@ pub fn write<'a>(module: &'a Module, out: &mut impl Write, options: Options) ->
|
||||
.ok_or_else(|| Error::Custom(String::from("Entry point not found")))?;
|
||||
let func = &module.functions[entry_point.function];
|
||||
|
||||
if entry_point.stage == ShaderStage::Compute {
|
||||
if let ShaderStage::Compute { .. } = entry_point.stage {
|
||||
if (es && version < 310) || (!es && version < 430) {
|
||||
return Err(Error::Custom(format!(
|
||||
"Version {} doesn't support compute shaders",
|
||||
@@ -293,12 +293,13 @@ pub fn write<'a>(module: &'a Module, out: &mut impl Write, options: Options) ->
|
||||
}
|
||||
|
||||
if let Some(interpolation) = global.interpolation {
|
||||
if (entry_point.stage == ShaderStage::Fragment && global.class == StorageClass::Input)
|
||||
|| (entry_point.stage == ShaderStage::Vertex
|
||||
&& global.class == StorageClass::Output)
|
||||
{
|
||||
write!(out, "{} ", write_interpolation(interpolation)?)?;
|
||||
}
|
||||
match (entry_point.stage, global.class) {
|
||||
(ShaderStage::Fragment { .. }, StorageClass::Input)
|
||||
| (ShaderStage::Vertex, StorageClass::Output) => {
|
||||
write!(out, "{} ", write_interpolation(interpolation)?)?;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
let block = match global.class {
|
||||
|
||||
183
src/back/msl.rs
183
src/back/msl.rs
@@ -1020,111 +1020,116 @@ impl<W: Write> Writer<W> {
|
||||
LocationMode::VertexInput,
|
||||
LocationMode::Intermediate,
|
||||
),
|
||||
crate::ShaderStage::Fragment => (
|
||||
crate::ShaderStage::Fragment { .. } => (
|
||||
"fragment",
|
||||
LocationMode::Intermediate,
|
||||
LocationMode::FragmentOutput,
|
||||
),
|
||||
crate::ShaderStage::Compute => {
|
||||
crate::ShaderStage::Compute { .. } => {
|
||||
("kernel", LocationMode::Uniform, LocationMode::Uniform)
|
||||
}
|
||||
};
|
||||
let location_input_name = fun.name.or_index(InputStructIndex(fun_handle));
|
||||
|
||||
if stage != crate::ShaderStage::Compute {
|
||||
writeln!(self.out, "struct {} {{", location_input_name)?;
|
||||
for ((handle, var), &usage) in
|
||||
module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
if var.class != crate::StorageClass::Input
|
||||
|| !usage.contains(crate::GlobalUse::LOAD)
|
||||
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)
|
||||
{
|
||||
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 var.class != crate::StorageClass::Input
|
||||
|| !usage.contains(crate::GlobalUse::LOAD)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
} 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) => {
|
||||
// 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")?;
|
||||
}
|
||||
crate::MemberOrigin::Offset(_) => {
|
||||
//TODO
|
||||
}
|
||||
} 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
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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, "}};")?;
|
||||
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
|
||||
)?;
|
||||
} else {
|
||||
writeln!(self.out, "{} void {}(", em_str, fun_name)?;
|
||||
}
|
||||
_ => {
|
||||
writeln!(self.out, "{} void {}(", em_str, fun_name)?;
|
||||
}
|
||||
};
|
||||
|
||||
for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage)
|
||||
{
|
||||
@@ -1142,10 +1147,10 @@ impl<W: Write> Writer<W> {
|
||||
LocationMode::VertexInput
|
||||
}
|
||||
(crate::ShaderStage::Vertex, crate::StorageClass::Output)
|
||||
| (crate::ShaderStage::Fragment, crate::StorageClass::Input) => {
|
||||
| (crate::ShaderStage::Fragment { .. }, crate::StorageClass::Input) => {
|
||||
LocationMode::Intermediate
|
||||
}
|
||||
(crate::ShaderStage::Fragment, crate::StorageClass::Output) => {
|
||||
(crate::ShaderStage::Fragment { .. }, crate::StorageClass::Output) => {
|
||||
LocationMode::FragmentOutput
|
||||
}
|
||||
_ => LocationMode::Uniform,
|
||||
@@ -1188,11 +1193,11 @@ impl<W: Write> Writer<W> {
|
||||
|
||||
// write down function body
|
||||
let has_output = match shader_stage {
|
||||
Some(crate::ShaderStage::Vertex) | Some(crate::ShaderStage::Fragment) => {
|
||||
Some(crate::ShaderStage::Vertex) | Some(crate::ShaderStage::Fragment { .. }) => {
|
||||
writeln!(self.out, "\t{} {};", output_name, OUTPUT_STRUCT_NAME)?;
|
||||
true
|
||||
}
|
||||
Some(crate::ShaderStage::Compute) | None => false,
|
||||
Some(crate::ShaderStage::Compute { .. }) | None => false,
|
||||
};
|
||||
for (local_handle, local) in fun.local_variables.iter() {
|
||||
let ty_name = module.types[local.ty].name.or_index(local.ty);
|
||||
|
||||
@@ -271,8 +271,8 @@ impl Writer {
|
||||
|
||||
let exec_model = match entry_point.stage {
|
||||
crate::ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
|
||||
crate::ShaderStage::Fragment => spirv::ExecutionModel::Fragment,
|
||||
crate::ShaderStage::Compute => spirv::ExecutionModel::GLCompute,
|
||||
crate::ShaderStage::Fragment { .. } => spirv::ExecutionModel::Fragment,
|
||||
crate::ShaderStage::Compute { .. } => spirv::ExecutionModel::GLCompute,
|
||||
};
|
||||
|
||||
instruction.add_operand(exec_model as u32);
|
||||
@@ -298,13 +298,13 @@ impl Writer {
|
||||
self.try_add_capabilities(exec_model.required_capabilities());
|
||||
match entry_point.stage {
|
||||
crate::ShaderStage::Vertex => {}
|
||||
crate::ShaderStage::Fragment => {
|
||||
crate::ShaderStage::Fragment { .. } => {
|
||||
let execution_mode = spirv::ExecutionMode::OriginUpperLeft;
|
||||
self.try_add_capabilities(execution_mode.required_capabilities());
|
||||
self.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) {
|
||||
|
||||
@@ -638,7 +638,7 @@ impl<'a> Parser<'a> {
|
||||
name: Some(name),
|
||||
class: match self.shader_stage {
|
||||
ShaderStage::Vertex => StorageClass::Output,
|
||||
ShaderStage::Fragment => StorageClass::Input,
|
||||
ShaderStage::Fragment { .. } => StorageClass::Input,
|
||||
_ => panic!(),
|
||||
},
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
|
||||
@@ -1327,7 +1327,13 @@ mod tests {
|
||||
|
||||
println!(
|
||||
"{:#?}",
|
||||
parse_str(data, String::from("main"), crate::ShaderStage::Fragment)
|
||||
parse_str(
|
||||
data,
|
||||
String::from("main"),
|
||||
crate::ShaderStage::Fragment {
|
||||
early_depth_test: None
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,52 +130,56 @@ pomelo! {
|
||||
|
||||
// expression
|
||||
variable_identifier ::= Identifier(v) {
|
||||
if v.1.as_str() == "gl_Position" &&
|
||||
(extra.shader_stage == ShaderStage::Vertex ||
|
||||
extra.shader_stage == ShaderStage::Fragment) {
|
||||
let h = extra.global_variables.fetch_or_append(
|
||||
GlobalVariable {
|
||||
name: Some(v.1.clone()),
|
||||
class: match extra.shader_stage {
|
||||
ShaderStage::Vertex => StorageClass::Output,
|
||||
ShaderStage::Fragment => StorageClass::Input,
|
||||
_ => StorageClass::Input,
|
||||
},
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
|
||||
ty: extra.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
let gl_position = if let ShaderStage::Vertex | ShaderStage::Fragment { .. } = extra.shader_stage {
|
||||
if v.1.as_str() == "gl_Position" {
|
||||
let h = extra.global_variables.fetch_or_append(
|
||||
GlobalVariable {
|
||||
name: Some(v.1.clone()),
|
||||
class: match extra.shader_stage {
|
||||
ShaderStage::Vertex => StorageClass::Output,
|
||||
ShaderStage::Fragment { .. } => StorageClass::Input,
|
||||
_ => StorageClass::Input,
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
},
|
||||
);
|
||||
extra.lookup_global_variables.insert(v.1.clone(), h);
|
||||
let expression = extra.context.expressions.append(
|
||||
Expression::GlobalVariable(h)
|
||||
);
|
||||
extra.context.lookup_global_var_exps.insert(v.1, expression);
|
||||
ExpressionRule{
|
||||
expression,
|
||||
statements: vec![],
|
||||
binding: Some(Binding::BuiltIn(BuiltIn::Position)),
|
||||
ty: extra.types.fetch_or_append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
interpolation: None,
|
||||
},
|
||||
);
|
||||
extra.lookup_global_variables.insert(v.1.clone(), h);
|
||||
let expression = extra.context.expressions.append(
|
||||
Expression::GlobalVariable(h)
|
||||
);
|
||||
extra.context.lookup_global_var_exps.insert(v.1.clone(), expression);
|
||||
|
||||
Some(expression)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// try global and local vars
|
||||
let expression =
|
||||
if let Some(local_var) = extra.context.lookup_local_var(&v.1) {
|
||||
local_var
|
||||
} else if let Some(global_var) = extra.context.lookup_global_var_exps.get(&v.1) {
|
||||
*global_var
|
||||
} else {
|
||||
return Err(ErrorKind::UnknownVariable(v.0, v.1))
|
||||
};
|
||||
ExpressionRule{
|
||||
expression,
|
||||
statements: vec![],
|
||||
}
|
||||
None
|
||||
};
|
||||
|
||||
let expression =
|
||||
if let Some(gl_position) = gl_position {
|
||||
gl_position
|
||||
} else if let Some(local_var) = extra.context.lookup_local_var(&v.1) {
|
||||
local_var
|
||||
} else if let Some(global_var) = extra.context.lookup_global_var_exps.get(&v.1) {
|
||||
*global_var
|
||||
} else {
|
||||
return Err(ErrorKind::UnknownVariable(v.0, v.1));
|
||||
};
|
||||
|
||||
ExpressionRule {
|
||||
expression,
|
||||
statements: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ pub enum Error {
|
||||
UnsupportedExtInst(spirv::Word),
|
||||
UnsupportedType(Handle<crate::Type>),
|
||||
UnsupportedExecutionModel(spirv::Word),
|
||||
UnsupportedExecutionMode(spirv::Word),
|
||||
UnsupportedStorageClass(spirv::Word),
|
||||
UnsupportedImageDim(spirv::Word),
|
||||
UnsupportedImageFormat(spirv::Word),
|
||||
|
||||
@@ -29,7 +29,11 @@ use crate::{
|
||||
use num_traits::cast::FromPrimitive;
|
||||
use std::{convert::TryInto, num::NonZeroU32};
|
||||
|
||||
pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[spirv::Capability::Shader];
|
||||
pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[
|
||||
spirv::Capability::Shader,
|
||||
spirv::Capability::CullDistance,
|
||||
spirv::Capability::StorageImageExtendedFormats,
|
||||
];
|
||||
pub const SUPPORTED_EXTENSIONS: &[&str] = &[];
|
||||
pub const SUPPORTED_EXT_SETS: &[&str] = &["GLSL.std.450"];
|
||||
|
||||
@@ -235,7 +239,7 @@ struct LookupFunctionType {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EntryPoint {
|
||||
exec_model: spirv::ExecutionModel,
|
||||
stage: crate::ShaderStage,
|
||||
name: String,
|
||||
function_id: spirv::Word,
|
||||
variable_ids: Vec<spirv::Word>,
|
||||
@@ -300,6 +304,7 @@ pub struct Parser<I> {
|
||||
lookup_sampled_image: FastHashMap<spirv::Word, LookupSampledImage>,
|
||||
lookup_function_type: FastHashMap<spirv::Word, LookupFunctionType>,
|
||||
lookup_function: FastHashMap<spirv::Word, Handle<crate::Function>>,
|
||||
lookup_entry_point: FastHashMap<spirv::Word, EntryPoint>,
|
||||
deferred_function_calls: Vec<DeferredFunctionCall>,
|
||||
}
|
||||
|
||||
@@ -322,6 +327,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
lookup_sampled_image: FastHashMap::default(),
|
||||
lookup_function_type: FastHashMap::default(),
|
||||
lookup_function: FastHashMap::default(),
|
||||
lookup_entry_point: FastHashMap::default(),
|
||||
deferred_function_calls: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -1402,7 +1408,6 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
generator,
|
||||
}
|
||||
});
|
||||
let mut entry_points = Vec::new();
|
||||
|
||||
while let Ok(inst) = self.next_inst() {
|
||||
use spirv::Op;
|
||||
@@ -1412,7 +1417,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
Op::Extension => self.parse_extension(inst),
|
||||
Op::ExtInstImport => self.parse_ext_inst_import(inst),
|
||||
Op::MemoryModel => self.parse_memory_model(inst),
|
||||
Op::EntryPoint => self.parse_entry_point(inst, &mut entry_points),
|
||||
Op::EntryPoint => self.parse_entry_point(inst),
|
||||
Op::ExecutionMode => self.parse_execution_mode(inst),
|
||||
Op::Source => self.parse_source(inst),
|
||||
Op::SourceExtension => self.parse_source_extension(inst),
|
||||
@@ -1492,16 +1497,11 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
self.future_member_decor.clear();
|
||||
}
|
||||
|
||||
module.entry_points.reserve(entry_points.len());
|
||||
for raw in entry_points {
|
||||
module.entry_points.reserve(self.lookup_entry_point.len());
|
||||
for raw in self.lookup_entry_point.values() {
|
||||
module.entry_points.push(crate::EntryPoint {
|
||||
stage: match raw.exec_model {
|
||||
spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex,
|
||||
spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment,
|
||||
spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute,
|
||||
other => return Err(Error::UnsupportedExecutionModel(other as u32)),
|
||||
},
|
||||
name: raw.name,
|
||||
stage: raw.stage,
|
||||
name: raw.name.clone(),
|
||||
function: *self.lookup_function.lookup(raw.function_id)?,
|
||||
});
|
||||
}
|
||||
@@ -1557,11 +1557,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_entry_point(
|
||||
&mut self,
|
||||
inst: Instruction,
|
||||
entry_points: &mut Vec<EntryPoint>,
|
||||
) -> Result<(), Error> {
|
||||
fn parse_entry_point(&mut self, inst: Instruction) -> Result<(), Error> {
|
||||
self.switch(ModuleState::EntryPoint, inst.op)?;
|
||||
inst.expect_at_least(4)?;
|
||||
let exec_model = self.next()?;
|
||||
@@ -1570,23 +1566,93 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let function_id = self.next()?;
|
||||
let (name, left) = self.next_string(inst.wc - 3)?;
|
||||
let ep = EntryPoint {
|
||||
exec_model,
|
||||
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),
|
||||
},
|
||||
_ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)),
|
||||
},
|
||||
name,
|
||||
function_id,
|
||||
variable_ids: self.data.by_ref().take(left as usize).collect(),
|
||||
};
|
||||
entry_points.push(ep);
|
||||
self.lookup_entry_point.insert(function_id, ep);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> {
|
||||
use crate::ShaderStage;
|
||||
use spirv::ExecutionMode;
|
||||
|
||||
self.switch(ModuleState::ExecutionMode, inst.op)?;
|
||||
inst.expect_at_least(3)?;
|
||||
let _ep_id = self.next()?;
|
||||
let _mode = self.next()?;
|
||||
for _ in 3..inst.wc {
|
||||
let _ = self.next()?; //TODO
|
||||
}
|
||||
|
||||
let ep_id = self.next()?;
|
||||
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
|
||||
.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));
|
||||
}
|
||||
};
|
||||
}
|
||||
ShaderStage::Compute { ref mut local_size } => {
|
||||
match mode {
|
||||
ExecutionMode::LocalSize => {
|
||||
*local_size = (args[0], args[1], args[2]);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedExecutionMode(mode_id));
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnsupportedExecutionMode(mode_id));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -265,8 +265,12 @@ impl Parser {
|
||||
fn get_shader_stage(word: &str) -> Result<crate::ShaderStage, Error<'_>> {
|
||||
match word {
|
||||
"vertex" => Ok(crate::ShaderStage::Vertex),
|
||||
"fragment" => Ok(crate::ShaderStage::Fragment),
|
||||
"compute" => Ok(crate::ShaderStage::Compute),
|
||||
"fragment" => Ok(crate::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
}),
|
||||
"compute" => Ok(crate::ShaderStage::Compute {
|
||||
local_size: (0, 0, 0),
|
||||
}),
|
||||
_ => Err(Error::UnknownShaderStage(word)),
|
||||
}
|
||||
}
|
||||
|
||||
50
src/lib.rs
50
src/lib.rs
@@ -45,6 +45,48 @@ pub struct Header {
|
||||
pub generator: u32,
|
||||
}
|
||||
|
||||
/// Early fragment tests. In a standard situation if a driver determines that it is possible to
|
||||
/// switch on early depth test it will. Typical situations when early depth test is switched off:
|
||||
/// - Calling ```discard``` in a shader.
|
||||
/// - Writing to the depth buffer, unless ConservativeDepth is enabled.
|
||||
///
|
||||
/// SPIR-V: ExecutionMode EarlyFragmentTests
|
||||
/// In GLSL: layout(early_fragment_tests) in;
|
||||
/// HLSL: Attribute earlydepthstencil
|
||||
///
|
||||
/// For more, see:
|
||||
/// - https://www.khronos.org/opengl/wiki/Early_Fragment_Test#Explicit_specification
|
||||
/// - https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-attributes-earlydepthstencil
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct EarlyDepthTest {
|
||||
conservative: Option<ConservativeDepth>,
|
||||
}
|
||||
/// Enables adjusting depth without disabling early Z.
|
||||
///
|
||||
/// SPIR-V: ExecutionMode DepthGreater/DepthLess/DepthUnchanged
|
||||
/// GLSL: layout (depth_<greater/less/unchanged/any>) out float gl_FragDepth;
|
||||
/// - ```depth_any``` option behaves as if the layout qualifier was not present.
|
||||
/// HLSL: SV_Depth/SV_DepthGreaterEqual/SV_DepthLessEqual
|
||||
///
|
||||
/// For more, see:
|
||||
/// - https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_conservative_depth.txt
|
||||
/// - https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics#system-value-semantics
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub enum ConservativeDepth {
|
||||
/// Shader may rewrite depth only with a value greater than calculated;
|
||||
GreaterEqual,
|
||||
|
||||
/// Shader may rewrite depth smaller than one that would have been written without the modification.
|
||||
LessEqual,
|
||||
|
||||
/// Shader may not rewrite depth value.
|
||||
Unchanged,
|
||||
}
|
||||
|
||||
/// Stage of the programmable pipeline.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
@@ -52,8 +94,12 @@ pub struct Header {
|
||||
#[allow(missing_docs)] // The names are self evident
|
||||
pub enum ShaderStage {
|
||||
Vertex,
|
||||
Fragment,
|
||||
Compute,
|
||||
Fragment {
|
||||
early_depth_test: Option<EarlyDepthTest>,
|
||||
},
|
||||
Compute {
|
||||
local_size: (u32, u32, u32),
|
||||
},
|
||||
}
|
||||
|
||||
/// Class of storage for variables.
|
||||
|
||||
@@ -114,7 +114,9 @@ fn convert_phong_lighting() {
|
||||
let module = load_glsl(
|
||||
"glsl_phong_lighting.frag",
|
||||
"main",
|
||||
naga::ShaderStage::Fragment,
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
);
|
||||
naga::proc::Validator::new().validate(&module).unwrap();
|
||||
|
||||
@@ -133,7 +135,9 @@ fn constant_expressions() {
|
||||
let module = load_glsl(
|
||||
"glsl_constant_expression.vert",
|
||||
"main",
|
||||
naga::ShaderStage::Fragment,
|
||||
naga::ShaderStage::Fragment {
|
||||
early_depth_test: None,
|
||||
},
|
||||
);
|
||||
naga::proc::Validator::new().validate(&module).unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user