///|
fn WgslIrLowerer::image_expression_result_type(
self : WgslIrLowerer,
function : Function,
image : Handle,
gather : SwizzleComponent?,
depth_ref : Handle?,
) -> Handle? {
guard self.function_expression_type(function, image) is Some(image_ty) else {
return None
}
match self.shader_module.types.items.get(image_ty.index()) {
Some(ty) =>
match ty.inner {
Image(_, _, Sampled(kind, _)) =>
Some(
self.intern_type(
"vec4<\{wgsl_ir_scalar_name(kind, 4)}>",
Vector(Quad, Scalar(kind, 4)),
),
)
Image(_, _, Depth(_)) =>
if gather != None {
Some(self.intern_type("vec4", Vector(Quad, Scalar(Float, 4))))
} else if depth_ref != None {
self.type_cache.get("f32")
} else {
self.type_cache.get("f32")
}
Image(_, _, Storage(format, _)) => {
let scalar = wgsl_ir_storage_format_scalar(format)
Some(
self.intern_type(
"vec4<\{wgsl_ir_scalar_name(scalar.kind, scalar.width)}>",
Vector(Quad, scalar),
),
)
}
Image(_, _, External) =>
Some(self.intern_type("vec4", Vector(Quad, Scalar(Float, 4))))
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::image_query_expression_result_type(
self : WgslIrLowerer,
function : Function,
image : Handle,
query : ImageQuery,
) -> Handle? {
match query {
Size(_) =>
match self.image_expression_inner(function, image) {
Some((dimension, _, _)) =>
Some(self.image_dimension_size_type(dimension))
None => None
}
NumLevels | NumLayers | NumSamples => self.type_cache.get("u32")
}
}
///|
fn WgslIrLowerer::image_dimension_size_type(
self : WgslIrLowerer,
dimension : ImageDimension,
) -> Handle {
let u32_scalar = Scalar::Scalar(Uint, 4)
match dimension {
D1 => self.scalar_type_handle(u32_scalar)
D2 | Cube => self.numeric_value_type_handle(Some(Bi), u32_scalar)
D3 => self.numeric_value_type_handle(Some(Tri), u32_scalar)
}
}
///|
fn WgslIrLowerer::indexed_expression_type(
self : WgslIrLowerer,
function : Function,
base : Handle,
index : Int32?,
) -> Handle? {
guard self.function_expression_type(function, base) is Some(base_ty) else {
return None
}
self.indexed_type_from_type_handle(base_ty, index)
}
///|
fn WgslIrLowerer::indexed_type_from_type_handle(
self : WgslIrLowerer,
ty_handle : Handle,
index : Int32?,
) -> Handle? {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Struct(members, _) | PredeclaredStruct(members, _) =>
match index {
Some(i) =>
match members.get(i) {
Some(struct_member) => Some(struct_member.ty)
None => None
}
None => None
}
Vector(_, scalar) => Some(self.scalar_type_handle(scalar))
Matrix(_, rows, scalar) => Some(self.vector_type_handle(rows, scalar))
Array(element, _, _) | BindingArray(element, _) => Some(element)
Pointer(inner, _) => self.indexed_type_from_type_handle(inner, index)
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::array_element_type(
self : WgslIrLowerer,
ty_handle : Handle,
) -> Handle? {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Array(element, _, _) | BindingArray(element, _) => Some(element)
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::numeric_binary_scalar_result_type(
self : WgslIrLowerer,
left_ty : Handle,
right_ty : Handle,
) -> Handle? {
guard self.scalar_from_numeric_type_handle(left_ty) is Some(left) else {
return None
}
guard self.scalar_from_numeric_type_handle(right_ty) is Some(right) else {
return None
}
if left.kind == AbstractInt {
match right.kind {
Sint | Uint | Float | AbstractFloat => return Some(right_ty)
AbstractInt => return Some(left_ty)
_ => ()
}
}
if left.kind == AbstractFloat {
match right.kind {
Float => return Some(right_ty)
AbstractInt | AbstractFloat => return Some(left_ty)
_ => ()
}
}
match right.kind {
AbstractInt => Some(left_ty)
AbstractFloat =>
match left.kind {
Float => Some(left_ty)
AbstractInt => Some(right_ty)
_ => Some(left_ty)
}
_ => Some(left_ty)
}
}
///|
fn wgsl_ir_binary_operator_is_arithmetic(op : BinaryOperator) -> Bool {
match op {
Add | Subtract | Multiply | Divide | Modulo => true
_ => false
}
}
///|
fn wgsl_ir_binary_operator_requires_vector_splat(op : BinaryOperator) -> Bool {
match op {
Add | Subtract | Divide | Modulo => true
_ => false
}
}
///|
fn WgslIrLowerer::scalar_from_numeric_type_handle(
self : WgslIrLowerer,
ty_handle : Handle,
) -> Scalar? {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Scalar(scalar) =>
match scalar.kind {
Sint | Uint | Float | AbstractInt | AbstractFloat => Some(scalar)
_ => None
}
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::expected_constructor_type(
self : WgslIrLowerer,
name : String,
expected_ty : Handle?,
) -> Handle? {
guard expected_ty is Some(ty_handle) else { return None }
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Scalar(scalar) =>
if name == wgsl_ir_scalar_name(scalar.kind, scalar.width) {
Some(ty_handle)
} else {
None
}
Vector(size, _) =>
if name == "vec\{size.width()}" {
Some(ty_handle)
} else {
None
}
Matrix(columns, rows, _) =>
if name == "mat\{columns.width()}x\{rows.width()}" {
Some(ty_handle)
} else {
None
}
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::contextualized_component_constructor_type(
self : WgslIrLowerer,
name : String,
actual_ty : Handle,
expected_ty : Handle?,
) -> Handle? {
guard expected_ty is Some(expected_handle) else { return None }
guard wgsl_ir_vector_size_from_constructor_name(name) is Some(size) else {
return None
}
guard self.shader_module.types.get(expected_handle) is Some(expected) else {
return None
}
match expected.inner {
Scalar(scalar) =>
self.contextualized_constructor_type(
actual_ty,
self.vector_type_handle(size, scalar),
)
_ => None
}
}
///|
fn WgslIrLowerer::constructor_component_expected_type(
self : WgslIrLowerer,
ty_handle : Handle,
) -> Handle? {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Vector(_, scalar) => Some(self.scalar_type_handle(scalar))
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::constructor_argument_expected_type(
self : WgslIrLowerer,
ty_handle : Handle,
argument_count : Int32,
) -> Handle? {
match self.shader_module.types.get(ty_handle) {
Some(ty) =>
match ty.inner {
Vector(_, scalar) => Some(self.scalar_type_handle(scalar))
Matrix(columns, rows, scalar) => {
let column_count = columns.width()
let row_count = rows.width()
if argument_count == column_count {
Some(self.vector_type_handle(rows, scalar))
} else if argument_count == column_count * row_count {
Some(self.scalar_type_handle(scalar))
} else {
None
}
}
_ => None
}
None => None
}
}
///|
fn WgslIrLowerer::literal_type(
self : WgslIrLowerer,
literal : Literal,
) -> Handle? {
match literal {
Bool(_) => self.type_cache.get("bool")
I32(_) => self.type_cache.get("i32")
AbstractInt(_) => self.type_cache.get("__abstract_int")
U32(_) => self.type_cache.get("u32")
F16(_) => self.type_cache.get("f16")
F32(_) | F32Exact(_) => self.type_cache.get("f32")
F64(_) => self.type_cache.get("f64")
AbstractFloat(_) => self.type_cache.get("__abstract_float")
_ => None
}
}
///|
fn WgslIrLowerer::scalar_type_handle(
self : WgslIrLowerer,
scalar : Scalar,
) -> Handle {
let name = match scalar.kind {
Bool => "bool"
Sint => "i32"
Uint => "u32"
Float =>
if scalar.width == 2 {
"f16"
} else if scalar.width == 8 {
"f64"
} else {
"f32"
}
AbstractInt => "__abstract_int"
AbstractFloat => "__abstract_float"
}
self.intern_type(name, Scalar(scalar))
}
///|
fn wgsl_ir_scalar_name(kind : ScalarKind, width : Int32) -> String {
match kind {
Bool => "bool"
Sint => if width == 8 { "i64" } else { "i32" }
Uint => if width == 8 { "u64" } else { "u32" }
Float => if width == 2 { "f16" } else if width == 8 { "f64" } else { "f32" }
AbstractInt => "__abstract_int"
AbstractFloat => "__abstract_float"
}
}
///|
fn wgsl_ir_storage_format_scalar(format : StorageFormat) -> Scalar {
match format {
R64Uint => Scalar(Uint, 8)
R8Uint
| R16Uint
| Rg8Uint
| R32Uint
| Rg16Uint
| Rgba8Uint
| Rgb10a2Uint
| Rg32Uint
| Rgba16Uint
| Rgba32Uint => Scalar(Uint, 4)
R8Sint
| R16Sint
| Rg8Sint
| R32Sint
| Rg16Sint
| Rgba8Sint
| Rg32Sint
| Rgba16Sint
| Rgba32Sint => Scalar(Sint, 4)
_ => Scalar(Float, 4)
}
}
///|
fn wgsl_ir_gather_component_from_node(
node : @ast.WgslExprNode,
) -> SwizzleComponent raise WgslIrLowerError {
match node.kind() {
Literal(token) =>
match token.kind() {
NumericLiteral(literal) =>
match wgsl_ir_numeric_literal_to_small_int(literal) {
Some(value) =>
match value {
0 => X
1 => Y
2 => Z
3 => W
_ =>
raise UnsupportedExpression(
"textureGather component must be 0, 1, 2, or 3",
)
}
None =>
raise UnsupportedExpression(
"textureGather component must be an integer literal",
)
}
_ =>
raise UnsupportedExpression(
"textureGather component must be an integer literal",
)
}
_ =>
raise UnsupportedExpression(
"textureGather component must be an integer literal",
)
}
}
///|
fn wgsl_ir_expr_node_is_gather_component(node : @ast.WgslExprNode) -> Bool {
match node.kind() {
Literal(token) =>
match token.kind() {
NumericLiteral(literal) =>
match wgsl_ir_numeric_literal_to_small_int(literal) {
Some(value) =>
match value {
0 | 1 | 2 | 3 => true
_ => false
}
None => false
}
_ => false
}
_ => false
}
}
///|
fn wgsl_ir_struct_member_index(
members : Array[StructMember],
member_name : String,
) -> Int32? {
for i in 0.. Int32 raise WgslIrLowerError {
match name {
"x" | "r" => 0
"y" | "g" => 1
"z" | "b" => 2
"w" | "a" => 3
_ =>
raise UnsupportedExpression(
"member access requires resolved struct member index: \{name}",
)
}
}
///|
fn wgsl_ir_swizzle_components(name : String) -> Array[SwizzleComponent]? {
if name.length() == 0 || name.length() > 4 {
return None
}
let components : Array[SwizzleComponent] = []
for i in 0.. components.push(X)
121 | 103 => components.push(Y)
122 | 98 => components.push(Z)
119 | 97 => components.push(W)
_ => return None
}
}
Some(components)
}
///|
fn wgsl_ir_vector_size_from_component_count(count : Int32) -> VectorSize {
match count {
2 => Bi
3 => Tri
_ => Quad
}
}
///|
fn WgslIrLowerer::global_expression_references_override(
self : WgslIrLowerer,
handle : Handle,
) -> Bool {
match self.shader_module.global_expressions.items.get(handle.index()) {
Some(expression) =>
self.global_expression_inner_references_override(expression)
None => false
}
}
///|
fn WgslIrLowerer::global_expression_inner_references_override(
self : WgslIrLowerer,
expression : Expression,
) -> Bool {
match expression {
Override(_) => true
Constant(handle) =>
match self.shader_module.constants.items.get(handle.index()) {
Some(constant) =>
self.global_expression_references_override(constant.init)
None => false
}
Compose(_, components)
| AtomicCall(_, components)
| FunctionCall(_, components) =>
wgsl_ir_global_expression_list_references_override(self, components)
Access(base, index) | Binary(_, base, index) =>
self.global_expression_references_override(base) ||
self.global_expression_references_override(index)
AccessIndex(base, _)
| Component(base, _)
| Splat(_, base)
| Swizzle(_, base, _)
| Load(base)
| Unary(_, base)
| Bitcast(_, base)
| Derivative(_, _, base)
| Relational(_, base)
| As(base, _, _)
| CallResult(base)
| WorkGroupUniformLoadResult(base)
| WorkGroupUniformLoad(base)
| ArrayLength(base)
| RayQueryProceed(base)
| RayQueryConfirmIntersection(base)
| RayQueryTerminate(base)
| RayQueryVertexPositions(base, _)
| RayQueryGetIntersection(base, _)
| SubgroupOperationResult(base) =>
self.global_expression_references_override(base)
AtomicResult(_, _) => false
SubgroupCall(_, arguments) =>
wgsl_ir_global_expression_list_references_override(self, arguments)
AddressOf(_, target) => self.global_expression_references_override(target)
RayQueryGenerateIntersection(base, intersection_t) =>
self.global_expression_references_override(base) ||
self.global_expression_references_override(intersection_t)
RayQueryInitialize(query, acceleration, ray_desc) =>
self.global_expression_references_override(query) ||
self.global_expression_references_override(acceleration) ||
self.global_expression_references_override(ray_desc)
CooperativeMultiplyAdd(a, b, c) =>
self.global_expression_references_override(a) ||
self.global_expression_references_override(b) ||
self.global_expression_references_override(c)
ImageLoad(image, coordinate, array_index, sample, level) =>
self.global_expression_references_override(image) ||
self.global_expression_references_override(coordinate) ||
wgsl_ir_optional_global_expression_references_override(self, array_index) ||
wgsl_ir_optional_global_expression_references_override(self, sample) ||
wgsl_ir_optional_global_expression_references_override(self, level)
ImageQuery(image, query) =>
self.global_expression_references_override(image) ||
wgsl_ir_image_query_references_override(self, query)
ImageSample(
image,
sampler,
_,
coordinate,
array_index,
offset,
level,
depth_ref,
_
) =>
self.global_expression_references_override(image) ||
self.global_expression_references_override(sampler) ||
self.global_expression_references_override(coordinate) ||
wgsl_ir_optional_global_expression_references_override(self, array_index) ||
wgsl_ir_optional_global_expression_references_override(self, offset) ||
wgsl_ir_sample_level_references_override(self, level) ||
wgsl_ir_optional_global_expression_references_override(self, depth_ref)
Select(condition, accept, reject) =>
self.global_expression_references_override(condition) ||
self.global_expression_references_override(accept) ||
self.global_expression_references_override(reject)
Math(_, a, b, c, d) =>
self.global_expression_references_override(a) ||
wgsl_ir_optional_global_expression_references_override(self, b) ||
wgsl_ir_optional_global_expression_references_override(self, c) ||
wgsl_ir_optional_global_expression_references_override(self, d)
Literal(_)
| ZeroValue(_)
| FunctionArgument(_)
| GlobalVariable(_)
| LocalVariable(_)
| RayQueryProceedResult
| SubgroupBallotResult
| CooperativeLoad(_, _, _, _) => false
}
}
///|
fn wgsl_ir_global_expression_list_references_override(
lowerer : WgslIrLowerer,
handles : Array[Handle],
) -> Bool {
for handle in handles {
if lowerer.global_expression_references_override(handle) {
return true
}
}
false
}
///|
fn wgsl_ir_optional_global_expression_references_override(
lowerer : WgslIrLowerer,
handle : Handle?,
) -> Bool {
match handle {
Some(handle) => lowerer.global_expression_references_override(handle)
None => false
}
}
///|
fn wgsl_ir_sample_level_references_override(
lowerer : WgslIrLowerer,
level : SampleLevel,
) -> Bool {
match level {
Exact(handle) | Bias(handle) =>
lowerer.global_expression_references_override(handle)
Zero => false
Gradient(x, y) =>
lowerer.global_expression_references_override(x) ||
lowerer.global_expression_references_override(y)
Auto => false
}
}
///|
fn wgsl_ir_image_query_references_override(
lowerer : WgslIrLowerer,
query : ImageQuery,
) -> Bool {
match query {
Size(level) =>
wgsl_ir_optional_global_expression_references_override(lowerer, level)
NumLevels | NumLayers | NumSamples => false
}
}
///|
fn wgsl_ir_optional_handle_array_is_empty(handles : Array[Handle?]) -> Bool {
for handle in handles {
if handle != None {
return false
}
}
true
}
///|
fn wgsl_ir_image_dimension_from_name(name : String) -> ImageDimension {
if name.contains("_1d") {
D1
} else if name.contains("_3d") {
D3
} else if name.contains("cube") {
Cube
} else {
D2
}
}
///|
fn wgsl_ir_storage_format_from_name(
name : String,
) -> StorageFormat raise WgslIrLowerError {
match name {
"r8unorm" => R8Unorm
"r8snorm" => R8Snorm
"r8uint" => R8Uint
"r8sint" => R8Sint
"r16uint" => R16Uint
"r16sint" => R16Sint
"r16float" => R16Float
"rg8unorm" => Rg8Unorm
"rg8snorm" => Rg8Snorm
"rg8uint" => Rg8Uint
"rg8sint" => Rg8Sint
"r32uint" => R32Uint
"r32sint" => R32Sint
"r32float" => R32Float
"rg16uint" => Rg16Uint
"rg16sint" => Rg16Sint
"rg16float" => Rg16Float
"rgba8unorm" => Rgba8Unorm
"rgba8snorm" => Rgba8Snorm
"rgba8uint" => Rgba8Uint
"rgba8sint" => Rgba8Sint
"bgra8unorm" => Bgra8Unorm
"rgb10a2uint" => Rgb10a2Uint
"rgb10a2unorm" => Rgb10a2Unorm
"rg11b10ufloat" => Rg11b10Ufloat
"r64uint" => R64Uint
"rg32uint" => Rg32Uint
"rg32sint" => Rg32Sint
"rg32float" => Rg32Float
"rgba16uint" => Rgba16Uint
"rgba16sint" => Rgba16Sint
"rgba16float" => Rgba16Float
"rgba32uint" => Rgba32Uint
"rgba32sint" => Rgba32Sint
"rgba32float" => Rgba32Float
"r16unorm" => R16Unorm
"r16snorm" => R16Snorm
"rg16unorm" => Rg16Unorm
"rg16snorm" => Rg16Snorm
"rgba16unorm" => Rgba16Unorm
"rgba16snorm" => Rgba16Snorm
_ => raise UnsupportedType("storage format \{name}")
}
}