///|
fn WgslIrEmitter::emit_entry_point(
self : WgslIrEmitter,
out : StringBuilder,
entry_point : EntryPoint,
function_plan : WgslIrFunctionWriterPlan,
index : Int,
) -> Unit raise WgslIrEmitError {
let multiline_attributes = entry_point.stage == Task ||
entry_point.stage == Mesh ||
entry_point.task_payload != None
match entry_point.stage {
Mesh =>
match entry_point.mesh_info {
Some(mesh_info) =>
out.write_string(
"@mesh(\{self.global_variable_name(mesh_info.output_variable)})",
)
None => raise Unsupported("mesh entry point without mesh output")
}
_ => out.write_string(self.stage_attribute(entry_point.stage))
}
match entry_point.task_payload {
Some(payload) =>
out.write_string("\n@payload(\{self.global_variable_name(payload)})")
None => ()
}
if wgsl_ir_stage_has_workgroup_size(entry_point.stage) {
if multiline_attributes {
out.write_string("\n@workgroup_size(")
} else {
out.write_string(" @workgroup_size(")
}
out.write_string(self.workgroup_size_component(entry_point, 0))
out.write_string(", ")
out.write_string(self.workgroup_size_component(entry_point, 1))
out.write_string(", ")
out.write_string(self.workgroup_size_component(entry_point, 2))
out.write_string(")")
} else if !multiline_attributes {
out.write_string(" ")
}
if wgsl_ir_stage_has_workgroup_size(entry_point.stage) &&
!multiline_attributes &&
self.options.emit_trailing_space_after_entry_point_attributes() {
out.write_string(" ")
}
out.write_string("\n")
self.emit_function(
out,
entry_point.function,
function_plan,
EntryPointFunction(index),
)
}
///|
fn wgsl_ir_stage_has_workgroup_size(stage : ShaderStage) -> Bool {
stage == Compute || stage == Task || stage == Mesh
}
///|
fn WgslIrEmitter::workgroup_size_component(
self : WgslIrEmitter,
entry_point : EntryPoint,
index : Int,
) -> String raise WgslIrEmitError {
match entry_point.workgroup_size_overrides {
Some(overrides) =>
match overrides.get(index) {
Some(Some(handle)) => return self.global_expression(handle)
_ => ()
}
None => ()
}
match entry_point.workgroup_size.get(index) {
Some(value) => "\{value}"
None => "1"
}
}
///|
fn WgslIrEmitter::emit_function(
self : WgslIrEmitter,
out : StringBuilder,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
origin : WgslIrEmitFunctionOrigin,
) -> Unit raise WgslIrEmitError {
let emitter = self.with_function_origin(origin)
let name = match origin {
UserFunction(index) =>
emitter.required_emit_name(wgsl_ir_emit_name_key("fn", index))
EntryPointFunction(index) =>
emitter.required_emit_name(wgsl_ir_emit_name_key("ep", index))
}
out.write_string("fn \{name}(")
for index in 0.. 0 {
out.write_string(", ")
}
emitter.emit_function_argument(out, function, index)
}
out.write_string(")")
match function.result {
Some(result) => {
out.write_string(" -> ")
emitter.emit_binding_attribute_prefix(
out,
result.binding,
Some(result.ty),
)
out.write_string(emitter.type_name(result.ty))
}
None => ()
}
out.write_string(" {\n")
emitter.emit_function_local_var_declarations(out, function, function_plan, 1)
emitter.emit_block_statements(out, function, function_plan, function.body, 1)
out.write_string("}\n")
}
///|
fn WgslIrEmitter::emit_function_argument(
self : WgslIrEmitter,
out : StringBuilder,
function : Function,
index : Int,
) -> Unit raise WgslIrEmitError {
guard function.arguments.get(index) is Some(argument) else {
raise MissingHandle("function argument \{index}")
}
self.emit_binding_attribute_prefix(out, argument.binding, Some(argument.ty))
let name = self.function_argument_name(Some(function), index)
out.write_string("\{name}: \{self.type_name(argument.ty)}")
}
///|
fn WgslIrEmitter::emit_local_declaration(
self : WgslIrEmitter,
out : StringBuilder,
function : Function,
handle : Handle,
indent : Int,
) -> Unit raise WgslIrEmitError {
let local_var = match function.local_variables.items.get(handle.index()) {
Some(value) => value
None => raise MissingHandle("local variable \{handle.index()}")
}
if wgsl_ir_local_variable_is_generated_call_result_alias(function, local_var) {
return
}
let name = self.local_variable_name(Some(function), handle)
out.write_string(
"\{wgsl_ir_indent(indent)}\{self.local_variable_keyword(local_var.kind)} \{name}",
)
if self.local_variable_needs_type_annotation(local_var) {
out.write_string(": \{self.type_name(local_var.ty)}")
}
match local_var.init {
Some(init) => {
let init_expr = if local_var.generated_temporary {
self.function_expression_inline(function, init)
} else {
self.function_expression(function, init)
}
if self.type_is_pointer(local_var.ty) &&
wgsl_ir_expression_text_needs_address(init_expr) &&
!self.expression_is_pointer(Some(function), init) {
out.write_string(
" = \{self.options.address_of_text(self.function_pointer_expression(function, init))}",
)
} else {
out.write_string(" = \{init_expr}")
}
}
None => ()
}
out.write_string(";\n")
}
///|
fn wgsl_ir_local_variable_is_generated_call_result_alias(
function : Function,
local_var : LocalVariable,
) -> Bool {
guard local_var.generated_temporary else { return false }
guard local_var.init is Some(init) else { return false }
match function.expressions.items.get(init.index()) {
Some(CallResult(_)) => true
_ => false
}
}
///|
fn WgslIrEmitter::emit_function_local_var_declarations(
self : WgslIrEmitter,
out : StringBuilder,
function : Function,
function_plan : WgslIrFunctionWriterPlan,
indent : Int,
) -> Unit raise WgslIrEmitError {
for index in function_plan.local_declaration_order() {
self.emit_local_declaration(out, function, Handle(index), indent)
}
if function_plan.needs_blank_after_local_declarations() {
out.write_string("\n")
}
}
///|
fn wgsl_ir_expression_text_needs_address(text : String) -> Bool {
text.length() == 0 || text[0:1] != "&"
}
///|
fn WgslIrEmitter::local_variable_keyword(
self : WgslIrEmitter,
kind : LocalVariableKind,
) -> String {
ignore(self)
match kind {
Var => "var"
Let => "let"
}
}
///|
fn WgslIrEmitter::local_variable_needs_type_annotation(
self : WgslIrEmitter,
local_var : LocalVariable,
) -> Bool {
if self.type_contains_abstract_scalar(local_var.ty) {
return false
}
if self.type_is_predeclared_result(local_var.ty) &&
!self.options.annotate_all_local_types() {
return false
}
if self.options.annotate_all_local_types() {
return true
}
true
}
///|
fn WgslIrEmitter::inferred_result_type_annotation(
self : WgslIrEmitter,
ty : Handle,
) -> String raise WgslIrEmitError {
if self.type_is_predeclared_result(ty) &&
!self.options.annotate_all_local_types() {
""
} else {
": \{self.type_name(ty)}"
}
}
///|
fn WgslIrEmitter::type_is_predeclared_result(
self : WgslIrEmitter,
handle : Handle,
) -> Bool {
for item in self.shader_module.special_types.predeclared_types {
let (_, existing) = item
if existing == handle {
return true
}
}
false
}