[glsl-out] Reduce global import usage

This commit is contained in:
Gordon-F
2021-06-23 13:30:54 +03:00
committed by Dzmitry Malyshau
parent a5874eb0cf
commit 7eeab393b2

View File

@@ -44,14 +44,9 @@
pub use features::Features;
use crate::{
back::{FunctionCtx, FunctionType, COMPONENTS, INDENT},
proc::{EntryPointIndex, NameKey, Namer, TypeResolution},
valid::{FunctionInfo, ModuleInfo},
ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant, ConstantInner,
DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle, ImageClass,
Interpolation, Module, RelationalFunction, Sampling, ScalarKind, ScalarValue, ShaderStage,
Statement, StorageAccess, StorageClass, StorageFormat, StructMember, Type, TypeInner,
UnaryOperator,
back,
proc::{self, NameKey},
valid, Handle, ShaderStage, TypeInner,
};
use features::FeaturesManager;
use std::{
@@ -153,8 +148,8 @@ impl Default for Options {
/// Structure that contains a reflection info
pub struct ReflectionInfo {
pub texture_mapping: FastHashMap<String, TextureMapping>,
pub uniforms: FastHashMap<Handle<GlobalVariable>, String>,
pub texture_mapping: crate::FastHashMap<String, TextureMapping>,
pub uniforms: crate::FastHashMap<Handle<crate::GlobalVariable>, String>,
}
/// Structure that connects a texture to a sampler or not
@@ -169,9 +164,9 @@ pub struct ReflectionInfo {
#[derive(Debug, Clone)]
pub struct TextureMapping {
/// Handle to the image global variable
pub texture: Handle<GlobalVariable>,
pub texture: Handle<crate::GlobalVariable>,
/// Handle to the associated sampler global variable if it exists
pub sampler: Option<Handle<GlobalVariable>>,
pub sampler: Option<Handle<crate::GlobalVariable>>,
}
/// Helper structure that generates a number
@@ -196,14 +191,14 @@ impl IdGenerator {
/// prefix identifying which pipeline stage the varying connects, and `X` is
/// the location.
struct VaryingName<'a> {
binding: &'a Binding,
binding: &'a crate::Binding,
stage: ShaderStage,
output: bool,
}
impl fmt::Display for VaryingName<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.binding {
Binding::Location { location, .. } => {
crate::Binding::Location { location, .. } => {
let prefix = match (self.stage, self.output) {
(ShaderStage::Compute, _) => unreachable!(),
// pipeline to vertex
@@ -215,7 +210,7 @@ impl fmt::Display for VaryingName<'_> {
};
write!(f, "_{}_location{}", prefix, location,)
}
Binding::BuiltIn(built_in) => {
crate::Binding::BuiltIn(built_in) => {
write!(f, "{}", glsl_built_in(built_in, self.output))
}
}
@@ -251,7 +246,7 @@ pub enum Error {
UnsupportedExternal(String),
/// A scalar with an unsupported width was requested
#[error("A scalar with an unsupported width was requested: {0:?} {1:?}")]
UnsupportedScalar(ScalarKind, Bytes),
UnsupportedScalar(crate::ScalarKind, crate::Bytes),
/// A image was used with multiple samplers, this isn't supported
#[error("A image was used with multiple samplers")]
ImageMultipleSamplers,
@@ -263,9 +258,9 @@ pub enum Error {
pub struct Writer<'a, W> {
// Inputs
/// The module being written
module: &'a Module,
module: &'a crate::Module,
/// The module analysis.
info: &'a ModuleInfo,
info: &'a valid::ModuleInfo,
/// The output writer
out: W,
/// User defined configuration to be used
@@ -274,16 +269,16 @@ pub struct Writer<'a, W> {
// Internal State
/// Features manager used to store all the needed features and write them
features: FeaturesManager,
namer: Namer,
namer: proc::Namer,
/// A map with all the names needed for writing the module
/// (generated by a [`Namer`](crate::proc::Namer))
names: FastHashMap<NameKey, String>,
names: crate::FastHashMap<NameKey, String>,
/// A map with all the names needed for reflections
reflection_names: FastHashMap<Handle<Type>, String>,
reflection_names: crate::FastHashMap<Handle<crate::Type>, String>,
/// The selected entry point
entry_point: &'a crate::EntryPoint,
/// The index of the selected entry point
entry_point_idx: EntryPointIndex,
entry_point_idx: proc::EntryPointIndex,
/// Used to generate a unique number for blocks
block_id: IdGenerator,
/// Set of expressions that have associated temporary variables
@@ -299,8 +294,8 @@ impl<'a, W: Write> Writer<'a, W> {
/// - If the version specified doesn't support some used features
pub fn new(
out: W,
module: &'a Module,
info: &'a ModuleInfo,
module: &'a crate::Module,
info: &'a valid::ModuleInfo,
options: &'a Options,
) -> Result<Self, Error> {
// Check if the requested version is supported
@@ -317,8 +312,8 @@ impl<'a, W: Write> Writer<'a, W> {
.ok_or(Error::EntryPointNotFound)?;
// Generate a map with names required to write the module
let mut names = FastHashMap::default();
let mut namer = Namer::default();
let mut names = crate::FastHashMap::default();
let mut namer = proc::Namer::default();
namer.reset(module, keywords::RESERVED_KEYWORDS, &["gl_"], &mut names);
// Build the instance
@@ -330,7 +325,7 @@ impl<'a, W: Write> Writer<'a, W> {
namer,
features: FeaturesManager::new(),
names,
reflection_names: FastHashMap::default(),
reflection_names: crate::FastHashMap::default(),
entry_point: &module.entry_points[ep_idx],
entry_point_idx: ep_idx as u16,
@@ -390,13 +385,15 @@ impl<'a, W: Write> Writer<'a, W> {
writeln!(self.out, "layout(early_fragment_tests) in;")?;
if let Some(conservative) = depth_test.conservative {
use crate::ConservativeDepth as Cd;
writeln!(
self.out,
"layout (depth_{}) out float gl_FragDepth;",
match conservative {
ConservativeDepth::GreaterEqual => "greater",
ConservativeDepth::LessEqual => "less",
ConservativeDepth::Unchanged => "unchanged",
Cd::GreaterEqual => "greater",
Cd::LessEqual => "less",
Cd::Unchanged => "unchanged",
}
)?;
}
@@ -444,7 +441,7 @@ impl<'a, W: Write> Writer<'a, W> {
} => {
// Write the storage format if needed
if let TypeInner::Image {
class: ImageClass::Storage(format),
class: crate::ImageClass::Storage(format),
..
} = self.module.types[global.ty].inner
{
@@ -505,13 +502,18 @@ impl<'a, W: Write> Writer<'a, W> {
let fun_info = &self.info[handle];
// Write the function
self.write_function(FunctionType::Function(handle), function, fun_info, &name)?;
self.write_function(
back::FunctionType::Function(handle),
function,
fun_info,
&name,
)?;
writeln!(self.out)?;
}
self.write_function(
FunctionType::EntryPoint(self.entry_point_idx),
back::FunctionType::EntryPoint(self.entry_point_idx),
&self.entry_point.function,
ep_info,
"main",
@@ -524,21 +526,23 @@ impl<'a, W: Write> Writer<'a, W> {
self.collect_reflection_info()
}
fn write_array_size(&mut self, size: ArraySize) -> BackendResult {
fn write_array_size(&mut self, size: crate::ArraySize) -> BackendResult {
write!(self.out, "[")?;
// Write the array size
// Writes nothing if `ArraySize::Dynamic`
// Panics if `ArraySize::Constant` has a constant that isn't an uint
match size {
ArraySize::Constant(const_handle) => match self.module.constants[const_handle].inner {
ConstantInner::Scalar {
width: _,
value: ScalarValue::Uint(size),
} => write!(self.out, "{}", size)?,
_ => unreachable!(),
},
ArraySize::Dynamic => (),
crate::ArraySize::Constant(const_handle) => {
match self.module.constants[const_handle].inner {
crate::ConstantInner::Scalar {
width: _,
value: crate::ScalarValue::Uint(size),
} => write!(self.out, "{}", size)?,
_ => unreachable!(),
}
}
crate::ArraySize::Dynamic => (),
}
write!(self.out, "]")?;
@@ -589,7 +593,7 @@ impl<'a, W: Write> Writer<'a, W> {
} => write!(
self.out,
"{}mat{}x{}",
glsl_scalar(ScalarKind::Float, width)?.prefix,
glsl_scalar(crate::ScalarKind::Float, width)?.prefix,
columns as u8,
rows as u8
)?,
@@ -619,7 +623,7 @@ impl<'a, W: Write> Writer<'a, W> {
/// - If type is either a image or sampler
/// - If it's an Array with a [`ArraySize::Constant`](crate::ArraySize::Constant) with a
/// constant that isn't [`Uint`](crate::ConstantInner::Uint)
fn write_type(&mut self, ty: Handle<Type>) -> BackendResult {
fn write_type(&mut self, ty: Handle<crate::Type>) -> BackendResult {
match self.module.types[ty].inner {
// glsl has no pointer types so just write types as normal and loads are skipped
TypeInner::Pointer { base, .. } => self.write_type(base),
@@ -649,7 +653,7 @@ impl<'a, W: Write> Writer<'a, W> {
&mut self,
dim: crate::ImageDimension,
arrayed: bool,
class: ImageClass,
class: crate::ImageClass,
) -> BackendResult {
// glsl images consist of four parts the scalar prefix, the image "type", the dimensions
// and modifiers
@@ -663,12 +667,13 @@ impl<'a, W: Write> Writer<'a, W> {
// - MS - used if it's a multisampled image
// - Array - used if it's an image array
// - Shadow - used if it's a depth image
use crate::ImageClass as Ic;
let (base, kind, ms, comparison) = match class {
ImageClass::Sampled { kind, multi: true } => ("sampler", kind, "MS", ""),
ImageClass::Sampled { kind, multi: false } => ("sampler", kind, "", ""),
ImageClass::Depth => ("sampler", crate::ScalarKind::Float, "", "Shadow"),
ImageClass::Storage(format) => ("image", format.into(), "", ""),
Ic::Sampled { kind, multi: true } => ("sampler", kind, "MS", ""),
Ic::Sampled { kind, multi: false } => ("sampler", kind, "", ""),
Ic::Depth => ("sampler", crate::ScalarKind::Float, "", "Shadow"),
Ic::Storage(format) => ("image", format.into(), "", ""),
};
write!(
@@ -694,8 +699,8 @@ impl<'a, W: Write> Writer<'a, W> {
/// If the global has type sampler
fn write_global(
&mut self,
handle: Handle<GlobalVariable>,
global: &GlobalVariable,
handle: Handle<crate::GlobalVariable>,
global: &crate::GlobalVariable,
) -> BackendResult {
if let Some(storage_access) = glsl_storage_access(global.storage_access) {
write!(self.out, "{} ", storage_access)?;
@@ -737,7 +742,11 @@ impl<'a, W: Write> Writer<'a, W> {
/// - Globals without bindings use the name from the [`Namer`](crate::proc::Namer)
/// - Globals with resource binding are named `_group_X_binding_Y` where `X`
/// is the group and `Y` is the binding
fn get_global_name(&self, handle: Handle<GlobalVariable>, global: &GlobalVariable) -> String {
fn get_global_name(
&self,
handle: Handle<crate::GlobalVariable>,
global: &crate::GlobalVariable,
) -> String {
match global.binding {
Some(ref br) => {
format!("_group_{}_binding_{}", br.group, br.binding)
@@ -749,8 +758,8 @@ impl<'a, W: Write> Writer<'a, W> {
/// Writes the varying declaration.
fn write_varying(
&mut self,
binding: Option<&Binding>,
ty: Handle<Type>,
binding: Option<&crate::Binding>,
ty: Handle<crate::Type>,
output: bool,
) -> Result<(), Error> {
match self.module.types[ty].inner {
@@ -761,7 +770,7 @@ impl<'a, W: Write> Writer<'a, W> {
}
_ => {
let (location, interpolation, sampling) = match binding {
Some(&Binding::Location {
Some(&crate::Binding::Location {
location,
interpolation,
sampling,
@@ -814,7 +823,7 @@ impl<'a, W: Write> Writer<'a, W> {
// Finally write the global name and end the global with a `;` and a newline
// Leading space is important
let vname = VaryingName {
binding: &Binding::Location {
binding: &crate::Binding::Location {
location,
interpolation: None,
sampling: None,
@@ -834,13 +843,13 @@ impl<'a, W: Write> Writer<'a, W> {
/// Adds a newline
fn write_function(
&mut self,
ty: FunctionType,
func: &Function,
info: &FunctionInfo,
ty: back::FunctionType,
func: &crate::Function,
info: &valid::FunctionInfo,
name: &str,
) -> BackendResult {
// Create a function context for the function being written
let ctx = FunctionCtx {
let ctx = back::FunctionCtx {
ty,
info,
expressions: &func.expressions,
@@ -862,7 +871,7 @@ impl<'a, W: Write> Writer<'a, W> {
// Start by writing the return type if any otherwise write void
// This is the only place where `void` is a valid type
// (though it's more a keyword than a type)
if let FunctionType::EntryPoint(_) = ctx.ty {
if let back::FunctionType::EntryPoint(_) = ctx.ty {
write!(self.out, "void")?;
} else if let Some(ref result) = func.result {
self.write_type(result.ty)?;
@@ -878,8 +887,8 @@ impl<'a, W: Write> Writer<'a, W> {
// We need access to `Self` here so we use the reference passed to the closure as an
// argument instead of capturing as that would cause a borrow checker error
let arguments = match ctx.ty {
FunctionType::EntryPoint(_) => &[][..],
FunctionType::Function(_) => &func.arguments,
back::FunctionType::EntryPoint(_) => &[][..],
back::FunctionType::Function(_) => &func.arguments,
};
self.write_slice(arguments, |this, i, arg| {
// Write the argument type
@@ -897,10 +906,10 @@ impl<'a, W: Write> Writer<'a, W> {
writeln!(self.out, ") {{")?;
// Compose the function arguments from globals, in case of an entry point.
if let FunctionType::EntryPoint(ep_index) = ctx.ty {
if let back::FunctionType::EntryPoint(ep_index) = ctx.ty {
let stage = self.module.entry_points[ep_index as usize].stage;
for (index, arg) in func.arguments.iter().enumerate() {
write!(self.out, "{}", INDENT)?;
write!(self.out, "{}", back::INDENT)?;
self.write_type(arg.ty)?;
let name = &self.names[&NameKey::EntryPointArgument(ep_index, index as u32)];
write!(self.out, " {}", name)?;
@@ -941,7 +950,7 @@ impl<'a, W: Write> Writer<'a, W> {
for (handle, local) in func.local_variables.iter() {
// Write indentation (only for readability) and the type
// `write_type` adds no trailing space
write!(self.out, "{}", INDENT)?;
write!(self.out, "{}", back::INDENT)?;
self.write_type(local.ty)?;
// Write the local name
@@ -1009,28 +1018,30 @@ impl<'a, W: Write> Writer<'a, W> {
///
/// # Notes
/// Adds no newlines or leading/trailing whitespace
fn write_constant(&mut self, constant: &Constant) -> BackendResult {
fn write_constant(&mut self, constant: &crate::Constant) -> BackendResult {
use crate::ScalarValue as Sv;
match constant.inner {
ConstantInner::Scalar {
crate::ConstantInner::Scalar {
width: _,
ref value,
} => match *value {
// Signed integers don't need anything special
ScalarValue::Sint(int) => write!(self.out, "{}", int)?,
Sv::Sint(int) => write!(self.out, "{}", int)?,
// Unsigned integers need a `u` at the end
//
// While `core` doesn't necessarily need it, it's allowed and since `es` needs it we
// always write it as the extra branch wouldn't have any benefit in readability
ScalarValue::Uint(int) => write!(self.out, "{}u", int)?,
Sv::Uint(int) => write!(self.out, "{}u", int)?,
// Floats are written using `Debug` instead of `Display` because it always appends the
// decimal part even it's zero which is needed for a valid glsl float constant
ScalarValue::Float(float) => write!(self.out, "{:?}", float)?,
Sv::Float(float) => write!(self.out, "{:?}", float)?,
// Booleans are either `true` or `false` so nothing special needs to be done
ScalarValue::Bool(boolean) => write!(self.out, "{}", boolean)?,
Sv::Bool(boolean) => write!(self.out, "{}", boolean)?,
},
// Composite constant are created using the same syntax as compose
// `type(components)` where `components` is a comma separated list of constants
ConstantInner::Composite { ty, ref components } => {
crate::ConstantInner::Composite { ty, ref components } => {
self.write_type(ty)?;
write!(self.out, "(")?;
@@ -1053,8 +1064,8 @@ impl<'a, W: Write> Writer<'a, W> {
fn write_struct(
&mut self,
block: bool,
handle: Handle<Type>,
members: &[StructMember],
handle: Handle<crate::Type>,
members: &[crate::StructMember],
) -> BackendResult {
// glsl structs are written as in C
// `struct name() { members };`
@@ -1080,7 +1091,7 @@ impl<'a, W: Write> Writer<'a, W> {
for (idx, member) in members.iter().enumerate() {
// The indentation is only for readability
write!(self.out, "{}", INDENT)?;
write!(self.out, "{}", back::INDENT)?;
match self.module.types[member.ty].inner {
TypeInner::Array {
@@ -1142,10 +1153,13 @@ impl<'a, W: Write> Writer<'a, W> {
/// Always adds a newline
fn write_stmt(
&mut self,
sta: &Statement,
ctx: &FunctionCtx<'_>,
sta: &crate::Statement,
ctx: &back::FunctionCtx<'_>,
indent: usize,
) -> BackendResult {
use crate::Statement;
use back::INDENT;
match *sta {
// This is where we can generate intermediate constants for some expression types.
Statement::Emit(ref range) => {
@@ -1313,7 +1327,7 @@ impl<'a, W: Write> Writer<'a, W> {
Statement::Return { value } => {
write!(self.out, "{}", INDENT.repeat(indent))?;
match ctx.ty {
FunctionType::Function(_) => {
back::FunctionType::Function(_) => {
write!(self.out, "return")?;
// Write the expression to be returned if needed
if let Some(expr) = value {
@@ -1322,14 +1336,16 @@ impl<'a, W: Write> Writer<'a, W> {
}
writeln!(self.out, ";")?;
}
FunctionType::EntryPoint(ep_index) => {
back::FunctionType::EntryPoint(ep_index) => {
let ep = &self.module.entry_points[ep_index as usize];
if let Some(ref result) = ep.function.result {
let value = value.unwrap();
match self.module.types[result.ty].inner {
crate::TypeInner::Struct { ref members, .. } => {
let (mut is_temp_struct_used, mut return_struct) = (false, "");
if let Expression::Compose { .. } = ctx.expressions[value] {
if let crate::Expression::Compose { .. } =
ctx.expressions[value]
{
is_temp_struct_used = true;
return_struct = "_tmp_return";
write!(
@@ -1344,7 +1360,9 @@ impl<'a, W: Write> Writer<'a, W> {
}
for (index, member) in members.iter().enumerate() {
// TODO: handle builtin in better way
if let Some(Binding::BuiltIn(builtin)) = member.binding {
if let Some(crate::Binding::BuiltIn(builtin)) =
member.binding
{
match builtin {
crate::BuiltIn::ClipDistance
| crate::BuiltIn::CullDistance
@@ -1461,7 +1479,13 @@ impl<'a, W: Write> Writer<'a, W> {
///
/// # Notes
/// Doesn't add any newlines or leading/trailing spaces
fn write_expr(&mut self, expr: Handle<Expression>, ctx: &FunctionCtx<'_>) -> BackendResult {
fn write_expr(
&mut self,
expr: Handle<crate::Expression>,
ctx: &back::FunctionCtx<'_>,
) -> BackendResult {
use crate::Expression;
if let Some(name) = self.named_expressions.get(&expr) {
write!(self.out, "{}", name)?;
return Ok(());
@@ -1494,7 +1518,7 @@ impl<'a, W: Write> Writer<'a, W> {
match *resolved {
TypeInner::Vector { .. } => {
// Write vector access as a swizzle
write!(self.out, ".{}", COMPONENTS[index as usize])?
write!(self.out, ".{}", back::COMPONENTS[index as usize])?
}
TypeInner::Matrix { .. }
| TypeInner::Array { .. }
@@ -1534,7 +1558,7 @@ impl<'a, W: Write> Writer<'a, W> {
self.write_expr(vector, ctx)?;
write!(self.out, ".")?;
for &sc in pattern[..size as usize].iter() {
self.out.write_char(COMPONENTS[sc as usize])?;
self.out.write_char(back::COMPONENTS[sc as usize])?;
}
}
// `Compose` is pretty simple we just write `type(components)` where `components` is a
@@ -1695,10 +1719,10 @@ impl<'a, W: Write> Writer<'a, W> {
};
let fun_name = match class {
ImageClass::Sampled { .. } => "texelFetch",
ImageClass::Storage(_) => "imageLoad",
crate::ImageClass::Sampled { .. } => "texelFetch",
crate::ImageClass::Storage(_) => "imageLoad",
// TODO: Is there even a function for this?
ImageClass::Depth => todo!(),
crate::ImageClass::Depth => todo!(),
};
write!(self.out, "{}(", fun_name)?;
@@ -1717,6 +1741,8 @@ impl<'a, W: Write> Writer<'a, W> {
// - textureQueryLevels
// - textureSamples/imageSamples
Expression::ImageQuery { image, query } => {
use crate::ImageClass;
// This will only panic if the module is invalid
let (dim, class) = match *ctx.info[image].ty.inner_with(&self.module.types) {
TypeInner::Image {
@@ -1764,7 +1790,7 @@ impl<'a, W: Write> Writer<'a, W> {
};
write!(self.out, "{}(", fun_name)?;
self.write_expr(image, ctx)?;
write!(self.out, ",0).{}", COMPONENTS[components])?;
write!(self.out, ",0).{}", back::COMPONENTS[components])?;
}
crate::ImageQuery::NumSamples => {
// assumes ARB_shader_texture_image_samples
@@ -1786,31 +1812,23 @@ impl<'a, W: Write> Writer<'a, W> {
//
// We also wrap the everything in parentheses to avoid precedence issues
Expression::Unary { op, expr } => {
use crate::{ScalarKind as Sk, UnaryOperator as Uo};
write!(
self.out,
"({} ",
match op {
UnaryOperator::Negate => "-",
UnaryOperator::Not =>
match *ctx.info[expr].ty.inner_with(&self.module.types) {
TypeInner::Scalar {
kind: ScalarKind::Sint,
..
} => "~",
TypeInner::Scalar {
kind: ScalarKind::Uint,
..
} => "~",
TypeInner::Scalar {
kind: ScalarKind::Bool,
..
} => "!",
ref other =>
return Err(Error::Custom(format!(
"Cannot apply not to type {:?}",
other
))),
},
Uo::Negate => "-",
Uo::Not => match *ctx.info[expr].ty.inner_with(&self.module.types) {
TypeInner::Scalar { kind: Sk::Sint, .. } => "~",
TypeInner::Scalar { kind: Sk::Uint, .. } => "~",
TypeInner::Scalar { kind: Sk::Bool, .. } => "!",
ref other =>
return Err(Error::Custom(format!(
"Cannot apply not to type {:?}",
other
))),
},
}
)?;
@@ -1825,17 +1843,19 @@ impl<'a, W: Write> Writer<'a, W> {
Expression::Binary { op, left, right } => {
// Holds `Some(function_name)` if the binary operation is
// implemented as a function call
use crate::BinaryOperator as Bo;
let function = if let (&TypeInner::Vector { .. }, &TypeInner::Vector { .. }) = (
ctx.info[left].ty.inner_with(&self.module.types),
ctx.info[right].ty.inner_with(&self.module.types),
) {
match op {
BinaryOperator::Less => Some("lessThan"),
BinaryOperator::LessEqual => Some("lessThanEqual"),
BinaryOperator::Greater => Some("greaterThan"),
BinaryOperator::GreaterEqual => Some("greaterThanEqual"),
BinaryOperator::Equal => Some("equal"),
BinaryOperator::NotEqual => Some("notEqual"),
Bo::Less => Some("lessThan"),
Bo::LessEqual => Some("lessThanEqual"),
Bo::Greater => Some("greaterThan"),
Bo::GreaterEqual => Some("greaterThanEqual"),
Bo::Equal => Some("equal"),
Bo::NotEqual => Some("notEqual"),
_ => None,
}
} else {
@@ -1872,13 +1892,15 @@ impl<'a, W: Write> Writer<'a, W> {
}
// `Derivative` is a function call to a glsl provided function
Expression::Derivative { axis, expr } => {
use crate::DerivativeAxis as Da;
write!(
self.out,
"{}(",
match axis {
DerivativeAxis::X => "dFdx",
DerivativeAxis::Y => "dFdy",
DerivativeAxis::Width => "fwidth",
Da::X => "dFdx",
Da::Y => "dFdy",
Da::Width => "fwidth",
}
)?;
self.write_expr(expr, ctx)?;
@@ -1886,15 +1908,17 @@ impl<'a, W: Write> Writer<'a, W> {
}
// `Relational` is a normal function call to some glsl provided functions
Expression::Relational { fun, argument } => {
use crate::RelationalFunction as Rf;
let fun_name = match fun {
// There's no specific function for this but we can invert the result of `isinf`
RelationalFunction::IsFinite => "!isinf",
RelationalFunction::IsInf => "isinf",
RelationalFunction::IsNan => "isnan",
Rf::IsFinite => "!isinf",
Rf::IsInf => "isinf",
Rf::IsNan => "isnan",
// There's also no function for this but we can invert `isnan`
RelationalFunction::IsNormal => "!isnan",
RelationalFunction::All => "all",
RelationalFunction::Any => "any",
Rf::IsNormal => "!isnan",
Rf::All => "all",
Rf::Any => "any",
};
write!(self.out, "{}(", fun_name)?;
@@ -2003,18 +2027,20 @@ impl<'a, W: Write> Writer<'a, W> {
}
}
None => {
use crate::ScalarKind as Sk;
let source_kind = inner.scalar_kind().unwrap();
write!(
self.out,
"{}",
match (source_kind, target_kind) {
(ScalarKind::Float, ScalarKind::Sint) => "floatBitsToInt",
(ScalarKind::Float, ScalarKind::Uint) => "floatBitsToUInt",
(ScalarKind::Sint, ScalarKind::Float) => "intBitsToFloat",
(ScalarKind::Uint, ScalarKind::Float) => "uintBitsToFloat",
(Sk::Float, Sk::Sint) => "floatBitsToInt",
(Sk::Float, Sk::Uint) => "floatBitsToUInt",
(Sk::Sint, Sk::Float) => "intBitsToFloat",
(Sk::Uint, Sk::Float) => "uintBitsToFloat",
// There is no way to bitcast between Uint/Sint in glsl. Use constructor conversion
(ScalarKind::Uint, ScalarKind::Sint) => "int",
(ScalarKind::Sint, ScalarKind::Uint) => "uint",
(Sk::Uint, Sk::Sint) => "int",
(Sk::Sint, Sk::Uint) => "uint",
_ => {
return Err(Error::Custom(format!(
"Cannot bitcast {:?} to {:?}",
@@ -2044,18 +2070,20 @@ impl<'a, W: Write> Writer<'a, W> {
fn write_texture_coordinates(
&mut self,
coordinate: Handle<Expression>,
array_index: Option<Handle<Expression>>,
coordinate: Handle<crate::Expression>,
array_index: Option<Handle<crate::Expression>>,
dim: crate::ImageDimension,
ctx: &FunctionCtx,
ctx: &back::FunctionCtx,
) -> Result<(), Error> {
use crate::ImageDimension as IDim;
match array_index {
Some(layer_expr) => {
let tex_coord_type = match dim {
crate::ImageDimension::D1 => "ivec2",
crate::ImageDimension::D2 => "ivec3",
crate::ImageDimension::D3 => "ivec4",
crate::ImageDimension::Cube => "ivec4",
IDim::D1 => "ivec2",
IDim::D2 => "ivec3",
IDim::D3 => "ivec4",
IDim::Cube => "ivec4",
};
write!(self.out, "{}(", tex_coord_type)?;
self.write_expr(coordinate, ctx)?;
@@ -2072,12 +2100,12 @@ impl<'a, W: Write> Writer<'a, W> {
fn write_named_expr(
&mut self,
handle: Handle<Expression>,
handle: Handle<crate::Expression>,
name: String,
ctx: &FunctionCtx,
ctx: &back::FunctionCtx,
) -> BackendResult {
match ctx.info[handle].ty {
TypeResolution::Handle(ty_handle) => match self.module.types[ty_handle].inner {
proc::TypeResolution::Handle(ty_handle) => match self.module.types[ty_handle].inner {
TypeInner::Struct { .. } => {
let ty_name = &self.names[&NameKey::Type(ty_handle)];
write!(self.out, "{}", ty_name)?;
@@ -2086,7 +2114,7 @@ impl<'a, W: Write> Writer<'a, W> {
self.write_type(ty_handle)?;
}
},
TypeResolution::Value(ref inner) => {
proc::TypeResolution::Value(ref inner) => {
self.write_value_type(inner)?;
}
}
@@ -2117,8 +2145,8 @@ impl<'a, W: Write> Writer<'a, W> {
fn collect_reflection_info(&self) -> Result<ReflectionInfo, Error> {
use std::collections::hash_map::Entry;
let info = self.info.get_entry_point(self.entry_point_idx as usize);
let mut mappings = FastHashMap::default();
let mut uniforms = FastHashMap::default();
let mut mappings = crate::FastHashMap::default();
let mut uniforms = crate::FastHashMap::default();
for sampling in info.sampling_set.iter() {
let global = self.module.global_variables[sampling.image].clone();
@@ -2146,7 +2174,7 @@ impl<'a, W: Write> Writer<'a, W> {
}
match self.module.types[var.ty].inner {
crate::TypeInner::Struct { .. } => match var.class {
StorageClass::Uniform | StorageClass::Storage => {
crate::StorageClass::Uniform | crate::StorageClass::Storage => {
let name = self.reflection_names[&var.ty].clone();
uniforms.insert(handle, name);
}
@@ -2179,17 +2207,22 @@ struct ScalarString<'a> {
///
/// # Errors
/// If a [`Float`](crate::ScalarKind::Float) with an width that isn't 4 or 8
fn glsl_scalar(kind: ScalarKind, width: Bytes) -> Result<ScalarString<'static>, Error> {
fn glsl_scalar(
kind: crate::ScalarKind,
width: crate::Bytes,
) -> Result<ScalarString<'static>, Error> {
use crate::ScalarKind as Sk;
Ok(match kind {
ScalarKind::Sint => ScalarString {
Sk::Sint => ScalarString {
prefix: "i",
full: "int",
},
ScalarKind::Uint => ScalarString {
Sk::Uint => ScalarString {
prefix: "u",
full: "uint",
},
ScalarKind::Float => match width {
Sk::Float => match width {
4 => ScalarString {
prefix: "",
full: "float",
@@ -2200,7 +2233,7 @@ fn glsl_scalar(kind: ScalarKind, width: Bytes) -> Result<ScalarString<'static>,
},
_ => return Err(Error::UnsupportedScalar(kind, width)),
},
ScalarKind::Bool => ScalarString {
Sk::Bool => ScalarString {
prefix: "b",
full: "bool",
},
@@ -2208,9 +2241,11 @@ fn glsl_scalar(kind: ScalarKind, width: Bytes) -> Result<ScalarString<'static>,
}
/// Helper function that returns the glsl variable name for a builtin
fn glsl_built_in(built_in: BuiltIn, output: bool) -> &'static str {
fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str {
use crate::BuiltIn as Bi;
match built_in {
BuiltIn::Position => {
Bi::Position => {
if output {
"gl_Position"
} else {
@@ -2218,18 +2253,18 @@ fn glsl_built_in(built_in: BuiltIn, output: bool) -> &'static str {
}
}
// vertex
BuiltIn::BaseInstance => "uint(gl_BaseInstance)",
BuiltIn::BaseVertex => "uint(gl_BaseVertex)",
BuiltIn::ClipDistance => "gl_ClipDistance",
BuiltIn::CullDistance => "gl_CullDistance",
BuiltIn::InstanceIndex => "uint(gl_InstanceID)",
BuiltIn::PointSize => "gl_PointSize",
BuiltIn::VertexIndex => "uint(gl_VertexID)",
Bi::BaseInstance => "uint(gl_BaseInstance)",
Bi::BaseVertex => "uint(gl_BaseVertex)",
Bi::ClipDistance => "gl_ClipDistance",
Bi::CullDistance => "gl_CullDistance",
Bi::InstanceIndex => "uint(gl_InstanceID)",
Bi::PointSize => "gl_PointSize",
Bi::VertexIndex => "uint(gl_VertexID)",
// fragment
BuiltIn::FragDepth => "gl_FragDepth",
BuiltIn::FrontFacing => "gl_FrontFacing",
BuiltIn::SampleIndex => "gl_SampleID",
BuiltIn::SampleMask => {
Bi::FragDepth => "gl_FragDepth",
Bi::FrontFacing => "gl_FrontFacing",
Bi::SampleIndex => "gl_SampleID",
Bi::SampleMask => {
if output {
"gl_SampleMask"
} else {
@@ -2237,90 +2272,100 @@ fn glsl_built_in(built_in: BuiltIn, output: bool) -> &'static str {
}
}
// compute
BuiltIn::GlobalInvocationId => "gl_GlobalInvocationID",
BuiltIn::LocalInvocationId => "gl_LocalInvocationID",
BuiltIn::LocalInvocationIndex => "gl_LocalInvocationIndex",
BuiltIn::WorkGroupId => "gl_WorkGroupID",
BuiltIn::WorkGroupSize => "gl_WorkGroupSize",
Bi::GlobalInvocationId => "gl_GlobalInvocationID",
Bi::LocalInvocationId => "gl_LocalInvocationID",
Bi::LocalInvocationIndex => "gl_LocalInvocationIndex",
Bi::WorkGroupId => "gl_WorkGroupID",
Bi::WorkGroupSize => "gl_WorkGroupSize",
}
}
/// Helper function that returns the string corresponding to the storage class
fn glsl_storage_class(class: StorageClass) -> Option<&'static str> {
fn glsl_storage_class(class: crate::StorageClass) -> Option<&'static str> {
use crate::StorageClass as Sc;
match class {
StorageClass::Function => None,
StorageClass::Private => None,
StorageClass::Storage => Some("buffer"),
StorageClass::Uniform => Some("uniform"),
StorageClass::Handle => Some("uniform"),
StorageClass::WorkGroup => Some("shared"),
StorageClass::PushConstant => None,
Sc::Function => None,
Sc::Private => None,
Sc::Storage => Some("buffer"),
Sc::Uniform => Some("uniform"),
Sc::Handle => Some("uniform"),
Sc::WorkGroup => Some("shared"),
Sc::PushConstant => None,
}
}
/// Helper function that returns the string corresponding to the glsl interpolation qualifier
fn glsl_interpolation(interpolation: Interpolation) -> &'static str {
fn glsl_interpolation(interpolation: crate::Interpolation) -> &'static str {
use crate::Interpolation as I;
match interpolation {
Interpolation::Perspective => "smooth",
Interpolation::Linear => "noperspective",
Interpolation::Flat => "flat",
I::Perspective => "smooth",
I::Linear => "noperspective",
I::Flat => "flat",
}
}
/// Return the GLSL auxiliary qualifier for the given sampling value.
fn glsl_sampling(sampling: Sampling) -> Option<&'static str> {
fn glsl_sampling(sampling: crate::Sampling) -> Option<&'static str> {
use crate::Sampling as S;
match sampling {
Sampling::Center => None,
Sampling::Centroid => Some("centroid"),
Sampling::Sample => Some("sample"),
S::Center => None,
S::Centroid => Some("centroid"),
S::Sample => Some("sample"),
}
}
/// Helper function that returns the glsl dimension string of [`ImageDimension`](crate::ImageDimension)
fn glsl_dimension(dim: crate::ImageDimension) -> &'static str {
use crate::ImageDimension as IDim;
match dim {
crate::ImageDimension::D1 => "1D",
crate::ImageDimension::D2 => "2D",
crate::ImageDimension::D3 => "3D",
crate::ImageDimension::Cube => "Cube",
IDim::D1 => "1D",
IDim::D2 => "2D",
IDim::D3 => "3D",
IDim::Cube => "Cube",
}
}
/// Helper function that returns the glsl storage format string of [`StorageFormat`](crate::StorageFormat)
fn glsl_storage_format(format: StorageFormat) -> &'static str {
fn glsl_storage_format(format: crate::StorageFormat) -> &'static str {
use crate::StorageFormat as Sf;
match format {
StorageFormat::R8Unorm => "r8",
StorageFormat::R8Snorm => "r8_snorm",
StorageFormat::R8Uint => "r8ui",
StorageFormat::R8Sint => "r8i",
StorageFormat::R16Uint => "r16ui",
StorageFormat::R16Sint => "r16i",
StorageFormat::R16Float => "r16f",
StorageFormat::Rg8Unorm => "rg8",
StorageFormat::Rg8Snorm => "rg8_snorm",
StorageFormat::Rg8Uint => "rg8ui",
StorageFormat::Rg8Sint => "rg8i",
StorageFormat::R32Uint => "r32ui",
StorageFormat::R32Sint => "r32i",
StorageFormat::R32Float => "r32f",
StorageFormat::Rg16Uint => "rg16ui",
StorageFormat::Rg16Sint => "rg16i",
StorageFormat::Rg16Float => "rg16f",
StorageFormat::Rgba8Unorm => "rgba8ui",
StorageFormat::Rgba8Snorm => "rgba8_snorm",
StorageFormat::Rgba8Uint => "rgba8ui",
StorageFormat::Rgba8Sint => "rgba8i",
StorageFormat::Rgb10a2Unorm => "rgb10_a2ui",
StorageFormat::Rg11b10Float => "r11f_g11f_b10f",
StorageFormat::Rg32Uint => "rg32ui",
StorageFormat::Rg32Sint => "rg32i",
StorageFormat::Rg32Float => "rg32f",
StorageFormat::Rgba16Uint => "rgba16ui",
StorageFormat::Rgba16Sint => "rgba16i",
StorageFormat::Rgba16Float => "rgba16f",
StorageFormat::Rgba32Uint => "rgba32ui",
StorageFormat::Rgba32Sint => "rgba32i",
StorageFormat::Rgba32Float => "rgba32f",
Sf::R8Unorm => "r8",
Sf::R8Snorm => "r8_snorm",
Sf::R8Uint => "r8ui",
Sf::R8Sint => "r8i",
Sf::R16Uint => "r16ui",
Sf::R16Sint => "r16i",
Sf::R16Float => "r16f",
Sf::Rg8Unorm => "rg8",
Sf::Rg8Snorm => "rg8_snorm",
Sf::Rg8Uint => "rg8ui",
Sf::Rg8Sint => "rg8i",
Sf::R32Uint => "r32ui",
Sf::R32Sint => "r32i",
Sf::R32Float => "r32f",
Sf::Rg16Uint => "rg16ui",
Sf::Rg16Sint => "rg16i",
Sf::Rg16Float => "rg16f",
Sf::Rgba8Unorm => "rgba8ui",
Sf::Rgba8Snorm => "rgba8_snorm",
Sf::Rgba8Uint => "rgba8ui",
Sf::Rgba8Sint => "rgba8i",
Sf::Rgb10a2Unorm => "rgb10_a2ui",
Sf::Rg11b10Float => "r11f_g11f_b10f",
Sf::Rg32Uint => "rg32ui",
Sf::Rg32Sint => "rg32i",
Sf::Rg32Float => "rg32f",
Sf::Rgba16Uint => "rgba16ui",
Sf::Rgba16Sint => "rgba16i",
Sf::Rgba16Float => "rgba16f",
Sf::Rgba32Uint => "rgba32ui",
Sf::Rgba32Sint => "rgba32i",
Sf::Rgba32Float => "rgba32f",
}
}
@@ -2329,10 +2374,10 @@ fn glsl_storage_format(format: StorageFormat) -> &'static str {
/// glsl allows adding both `readonly` and `writeonly` but this means that
/// they can only be used to query information about the resource which isn't what
/// we want here so when storage access is both `LOAD` and `STORE` add no modifiers
fn glsl_storage_access(storage_access: StorageAccess) -> Option<&'static str> {
if storage_access == StorageAccess::LOAD {
fn glsl_storage_access(storage_access: crate::StorageAccess) -> Option<&'static str> {
if storage_access == crate::StorageAccess::LOAD {
Some("readonly")
} else if storage_access == StorageAccess::STORE {
} else if storage_access == crate::StorageAccess::STORE {
Some("writeonly")
} else {
None
@@ -2343,7 +2388,7 @@ fn glsl_storage_access(storage_access: StorageAccess) -> Option<&'static str> {
fn zero_init_value_str(inner: &TypeInner) -> Option<String> {
match *inner {
TypeInner::Scalar { kind, .. } => match kind {
ScalarKind::Bool => Some(String::from("false")),
crate::ScalarKind::Bool => Some(String::from("false")),
_ => Some(String::from("0")),
},
TypeInner::Vector { size, kind, width } => {