/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_UI_SHADERS_XESL_XESLI_ #define XENIA_UI_SHADERS_XESL_XESLI_ // XESL_LANGUAGE_GLSL / HLSL / MSL = 1 are expected to be defined via compiler // arguments. // Required GLSL extensions: // - GL_EXT_control_flow_attributes // - GL_EXT_samplerless_texture_functions // For functions, it's preferable to take the identifiers here from an existing // target language, such as GLSL or HLSL, prefixing them with xesl_, only // modifying the names when altering (generalizing or specializing usually) // their functionality compared to that of the original function. The preferred // name choice from all the shading languages is the name that reflects the // functionality the closest, especially if some languages have a narrower input // domain (for instance, HLSL has asuint that can accept both float and int, // while GLSL has floatBitsToUint that accepts only float - there are two // options here, a xesl_floatBitsToUint alias, or xesl_asuint overloads, but the // former is more precisely descriptive, so it's preferred; xesl_lerp is // preferred over xesl_mix because the former describes how exactly the mixing // will be performed), and / or that is the most visually consistent // (xesl_float4 over xesl_vec4 considering it's a float vector). #if XESL_LANGUAGE_MSL #include using namespace metal; #endif // Vectors. // Scalars for definition consistency. #define xesl_bool bool #define xesl_int int #define xesl_uint uint #define xesl_float float #if XESL_LANGUAGE_GLSL #define xesl_bool2 bvec2 #define xesl_bool3 bvec3 #define xesl_bool4 bvec4 #define xesl_int2 ivec2 #define xesl_int3 ivec3 #define xesl_int4 ivec4 #define xesl_uint2 uvec2 #define xesl_uint3 uvec3 #define xesl_uint4 uvec4 #define xesl_float2 vec2 #define xesl_float3 vec3 #define xesl_float4 vec4 #else #define xesl_bool2 bool2 #define xesl_bool3 bool3 #define xesl_bool4 bool4 #define xesl_int2 int2 #define xesl_int3 int3 #define xesl_int4 int4 #define xesl_uint2 uint2 #define xesl_uint3 uint3 #define xesl_uint4 uint4 #define xesl_float2 float2 #define xesl_float3 float3 #define xesl_float4 float4 #endif // XESL_LANGUAGE_GLSL xesl_bool2 xesl_bool_x2(bool xesl_var_value) { return xesl_bool2(xesl_var_value, xesl_var_value); } xesl_bool3 xesl_bool_x3(bool xesl_var_value) { return xesl_bool3(xesl_var_value, xesl_var_value, xesl_var_value); } xesl_bool4 xesl_bool_x4(bool xesl_var_value) { return xesl_bool4(xesl_var_value, xesl_var_value, xesl_var_value, xesl_var_value); } xesl_int2 xesl_int_x2(int xesl_var_value) { return xesl_int2(xesl_var_value, xesl_var_value); } xesl_int3 xesl_int_x3(int xesl_var_value) { return xesl_int3(xesl_var_value, xesl_var_value, xesl_var_value); } xesl_int4 xesl_int_x4(int xesl_var_value) { return xesl_int4(xesl_var_value, xesl_var_value, xesl_var_value, xesl_var_value); } xesl_uint2 xesl_uint_x2(uint xesl_var_value) { return xesl_uint2(xesl_var_value, xesl_var_value); } xesl_uint3 xesl_uint_x3(uint xesl_var_value) { return xesl_uint3(xesl_var_value, xesl_var_value, xesl_var_value); } xesl_uint4 xesl_uint_x4(uint xesl_var_value) { return xesl_uint4(xesl_var_value, xesl_var_value, xesl_var_value, xesl_var_value); } xesl_float2 xesl_float_x2(float xesl_var_value) { return xesl_float2(xesl_var_value, xesl_var_value); } xesl_float3 xesl_float_x3(float xesl_var_value) { return xesl_float3(xesl_var_value, xesl_var_value, xesl_var_value); } xesl_float4 xesl_float_x4(float xesl_var_value) { return xesl_float4(xesl_var_value, xesl_var_value, xesl_var_value, xesl_var_value); } // Declarations. // // Resource binding is very different between shading languages, so any // customizations are fine in it. All binding slots for all APIs, however, // should be explicitly specified by the shader for ease of manual lookup and // tweaking. They should be alphabetically ordered by the name of the target // shading language in the argument lists (GLSL before HLSL). For readability, // the `set=` and `binding=` specifiers, and register types and the `space` // prefix in HLSL, are exposed to the shader, even though they're redundant. // // The `xesl_id_` prefix (with context-specific sub-prefixes) can be used to // create internal derivative identifiers (such as buffer block names from // instance names, or separate texture and sampler from a combined texture / // sampler for languages not supporting the latter). // Non-compute shader entry point must be declared as: // xesl_entry_outputs_begin // - Linked stage outputs. // - Linked system stage outputs (like vertex position). // - System stage outputs. // xesl_entry_outputs_end_stageInputs_begin // - Linked stage inputs (vertex attributes, interpolants). // xesl_entry_stageInputs_end_bindings_begin_[stage] (vertex, pixel) // Everything here must be separated with xesl_entry_binding_next, with no // leading or trailing separators. // - Buffer, texture, sampler bindings. // xesl_entry_bindings_end_inputs_begin // (or xesl_entry_bindings_empty_end_inputs_begin if there are no bindings). // Everything here must be separated with xesl_entry_input_next, with no // leading or trailing separators. // - xesl_entry_input_stageInputs if any linked stage inputs are used. // - Linked system inputs (like pixel position). // - System inputs. // xesl_entry_inputs_end_code_begin // - Main function code. // xesl_entry_code_end // // Compute shader entry point must be declared as: // #define xesl_localSize_x, y, z // xesl_entry_bindings_begin_compute // Everything here must be separated with xesl_entry_binding_next, with no // leading or trailing separators. // - Buffer, texture, sampler bindings. // xesl_entry_bindings_end_inputs_begin_compute // Everything here must be separated with xesl_entry_input_next, with no // leading or trailing separators. // - System inputs. // xesl_entry_inputs_end_code_begin_compute // - Main function code. // xesl_entry_code_end_compute // // Bindings are in the entry point because they are passed this way in MSL. For // this reason, constant and storage buffer declarations are also split into the // declaration itself and the binding (because blocks can't be passed as // function arguments in GLSL, for instance, so they must be fully declared // before functions referencing them in headers, for example - but in MSL, their // structure has to be forward-declared for this purpose, and the reference to // the binding should be passed to the function). // // Note that for the stage inputs / outputs, the order must be the same as in // HLSL linkage. For this reason, the position and the fragment coordinate also // must be after the stage inputs structure in the input list. // // Both input / output and binding names may be placed in the global scope in // the target language, make sure they don't collide with anything there. // // In compute shaders, the total group size must not exceed 128 threads (unless // the shader is used with the appropriate conditionals), as that's the minimum // maxComputeWorkGroupInvocations requirement on Vulkan. 128 threads exactly is // the recommended group size overall, especially for shaders not using the // group functionality, as it's the maximum wave size supported by DXIL and // SPIR-V wave operations, and there are PowerVR GPUs with 128-lane waves, so // it provides balance between wave utilization and excess thread (and, on GPUs // with smaller waves, wave) count if the size of the actual work domain is not // aligned to the group size. // // System outputs and inputs (declared via the respective xesl_entry_output_* // and xesl_entry_input_*): // - Vertex shaders: // - out xesl_float4 xesl_Position // - in uint xesl_VertexID // - Pixel shaders: // - in xesl_float4 xesl_FragCoord // xesl_FragCoord.w is 1/W if XESL_FRAG_COORD_W_IS_INVERSE, W otherwise. // - Compute shaders: // - in xesl_uint3 xesl_WorkGroupID // - in xesl_uint3 xesl_LocalInvocationID // - in xesl_uint3 xesl_GlobalInvocationID // - in uint xesl_LocalInvocationIndex #if XESL_LANGUAGE_GLSL #define xesl_entry_output(type, name, index, semantic) \ layout(location=index) out type name; #define xesl_entry_output_target(type, name, index) \ layout(location=index) out type name; #define xesl_Output(name) name #define xesl_Position gl_Position #define xesl_entry_stageInput(type, name, index, semantic) \ layout(location=index) in type name; #define xesl_entry_bindings_end_inputs_begin_compute \ layout(local_size_x=(xesl_localSize_x), local_size_y=(xesl_localSize_y), \ local_size_z=(xesl_localSize_z)) in; #define xesl_StageInput(name) name #define xesl_VertexID (uint(gl_VertexIndex)) #define XESL_FRAG_COORD_W_IS_INVERSE 1 #define xesl_FragCoord gl_FragCoord #define xesl_WorkGroupID gl_WorkGroupID #define xesl_LocalInvocationID gl_LocalInvocationID #define xesl_GlobalInvocationID gl_GlobalInvocationID #define xesl_LocalInvocationIndex gl_LocalInvocationIndex #define xesl_entry_inputs_end_code_begin void main() { #define xesl_entry_inputs_end_code_begin_compute void main() { #define xesl_entry_return return; #elif XESL_LANGUAGE_HLSL #define xesl_entry_outputs_begin struct xesl_entry_outputs_struct { #define xesl_entry_output(type, name, index, semantic) type name : semantic; #define xesl_entry_output_target(type, name, index) \ type name : SV_Target##index; #define xesl_Output(name) xesl_entry_outputs.name #define xesl_entry_output_position \ float4 xesl_id_output_position : SV_Position; #define xesl_Position xesl_entry_outputs.xesl_id_output_position #define xesl_entry_outputs_end_stageInputs_begin \ }; \ struct xesl_entry_stageInputs_struct { #define xesl_entry_stageInput(type, name, index, semantic) \ type name : semantic; #define xesl_entry_stageInputs_end_bindings_begin_vertex }; #define xesl_entry_stageInputs_end_bindings_begin_pixel }; #define xesl_entry_bindings_end_inputs_begin xesl_entry_outputs_struct main( #define xesl_entry_bindings_empty_end_inputs_begin \ xesl_entry_outputs_struct main( #define xesl_entry_bindings_end_inputs_begin_compute \ [numthreads(xesl_localSize_x, xesl_localSize_y, xesl_localSize_z)] \ void main( #define xesl_entry_input_next , #define xesl_entry_input_stageInputs \ xesl_entry_stageInputs_struct xesl_entry_stageInputs #define xesl_StageInput(name) xesl_entry_stageInputs.name #define xesl_entry_input_vertexID uint xesl_VertexID : SV_VertexID #define xesl_entry_input_fragCoord xesl_float4 xesl_FragCoord : SV_Position #define xesl_entry_input_workGroupID xesl_uint3 xesl_WorkGroupID : SV_GroupID #define xesl_entry_input_localInvocationID \ xesl_uint3 xesl_LocalInvocationID : SV_GroupThreadID #define xesl_entry_input_globalInvocationID \ xesl_uint3 xesl_GlobalInvocationID : SV_DispatchThreadID #define xesl_entry_input_localInvocationIndex \ uint xesl_LocalInvocationIndex : SV_GroupIndex #define xesl_entry_inputs_end_code_begin \ ) { \ xesl_entry_outputs_struct xesl_entry_outputs; #define xesl_entry_inputs_end_code_begin_compute ) { #define xesl_entry_return return xesl_entry_outputs; #elif XESL_LANGUAGE_MSL #define xesl_entry_outputs_begin struct xesl_entry_outputs_struct { #define xesl_entry_output(type, name, index, semantic) \ type name [[user(semantic)]]; #define xesl_entry_output_target(type, name, index) \ type name [[color(index)]]; #define xesl_Output(name) xesl_entry_outputs.name #define xesl_entry_output_position \ xesl_float4 xesl_id_output_position [[position]]; #define xesl_Position xesl_entry_outputs.xesl_id_output_position #define xesl_entry_outputs_end_stageInputs_begin \ }; \ struct xesl_entry_stageInputs_struct { #define xesl_entry_stageInput(type, name, index, semantic) \ type name [[user(semantic)]]; #define xesl_entry_stageInput_vertex(type, name, index, semantic) \ type name [[attribute(index)]]; #define xesl_entry_stageInputs_end_bindings_begin_vertex \ }; \ vertex xesl_entry_outputs_struct xesl_entry( #define xesl_entry_stageInputs_end_bindings_begin_pixel \ }; \ fragment xesl_entry_outputs_struct xesl_entry( #define xesl_entry_bindings_begin_compute kernel void xesl_entry( #define xesl_entry_binding_next , #define xesl_entry_bindings_end_inputs_begin , #define xesl_entry_bindings_end_inputs_begin_compute , #define xesl_entry_input_next , #define xesl_entry_input_stageInputs \ xesl_entry_stageInputs_struct xesl_entry_stageInputs [[stage_in]] #define xesl_StageInput(name) xesl_entry_stageInputs.name #define xesl_entry_input_vertexID uint xesl_VertexID [[vertex_id]] #define XESL_FRAG_COORD_W_IS_INVERSE 1 #define xesl_entry_input_fragCoord xesl_float4 xesl_FragCoord [[position]] #define xesl_entry_input_workGroupID \ xesl_uint3 xesl_WorkGroupID [[threadgroup_position_in_grid]] #define xesl_entry_input_localInvocationID \ xesl_uint3 xesl_LocalInvocationID [[thread_position_in_threadgroup]] #define xesl_entry_input_globalInvocationID \ xesl_uint3 xesl_GlobalInvocationID [[thread_position_in_grid]] #define xesl_entry_input_localInvocationIndex \ uint xesl_LocalInvocationIndex [[thread_index_in_threadgroup]] #define xesl_entry_inputs_end_code_begin \ ) { \ xesl_entry_outputs_struct xesl_entry_outputs; #define xesl_entry_inputs_end_code_begin_compute ) { #define xesl_entry_return return xesl_entry_outputs; #else #error xesl_entry not defined for the target language. #endif // XE_LANGUAGE #ifndef xesl_entry_outputs_begin #define xesl_entry_outputs_begin #endif // !xesl_entry_outputs_begin #ifndef xesl_entry_output_position #define xesl_entry_output_position #endif // !xesl_entry_output_position #ifndef xesl_entry_outputs_end_stageInputs_begin #define xesl_entry_outputs_end_stageInputs_begin #endif // !xesl_entry_outputs_end_stageInputs_begin #ifndef xesl_entry_stageInput_vertex #define xesl_entry_stageInput_vertex(type, name, index, semantic) \ xesl_entry_stageInput(type, name, index, semantic) #endif // !xesl_entry_stageInput_vertex #ifndef xesl_entry_stageInputs_end_bindings_begin_vertex #define xesl_entry_stageInputs_end_bindings_begin_vertex #endif // !xesl_entry_stageInputs_end_bindings_begin_vertex #ifndef xesl_entry_stageInputs_end_bindings_begin_pixel #define xesl_entry_stageInputs_end_bindings_begin_pixel #endif // !xesl_entry_stageInputs_end_bindings_begin_pixel #ifndef xesl_entry_bindings_begin_compute #define xesl_entry_bindings_begin_compute #endif // !xesl_entry_bindings_begin_compute #ifndef xesl_entry_binding_next #define xesl_entry_binding_next #endif // !xesl_entry_binding_next #ifndef xesl_entry_bindings_end_inputs_begin #define xesl_entry_bindings_end_inputs_begin #endif // !xesl_entry_bindings_end_inputs_begin #ifndef xesl_entry_bindings_empty_end_inputs_begin #define xesl_entry_bindings_empty_end_inputs_begin #endif // !xesl_entry_bindings_empty_end_inputs_begin #ifndef xesl_entry_bindings_end_inputs_begin_compute #define xesl_entry_bindings_end_inputs_begin_compute #endif // !xesl_entry_bindings_end_inputs_begin_compute #ifndef xesl_entry_input_next #define xesl_entry_input_next #endif // !xesl_entry_input_next #ifndef xesl_entry_input_stageInputs #define xesl_entry_input_stageInputs #endif // !xesl_entry_input_stageInputs #ifndef xesl_entry_input_vertexID #define xesl_entry_input_vertexID #endif // !xesl_entry_input_vertexID #ifndef xesl_entry_input_fragCoord #define xesl_entry_input_fragCoord #endif // !xesl_entry_input_fragCoord #ifndef xesl_entry_input_workGroupID #define xesl_entry_input_workGroupID #endif // !xesl_entry_input_workGroupID #ifndef xesl_entry_input_localInvocationID #define xesl_entry_input_localInvocationID #endif // !xesl_entry_input_localInvocationID #ifndef xesl_entry_input_globalInvocationID #define xesl_entry_input_globalInvocationID #endif // !xesl_entry_input_globalInvocationID #ifndef xesl_entry_input_localInvocationIndex #define xesl_entry_input_localInvocationIndex #endif // !xesl_entry_input_localInvocationIndex #ifndef xesl_entry_code_end #define xesl_entry_code_end \ xesl_entry_return \ } #endif // !xesl_entry_code_end #ifndef xesl_entry_code_end_compute #define xesl_entry_code_end_compute } #endif // !xesl_entry_code_end_compute // XESL_Y_SCREEN_DIRECTION is 1.0 if with a positive viewport height, // +xesl_Position.y is towards +xesl_FragCoord.y, -1.0 if +xesl_Position.y is // towards -xesl_FragCoord.y. #if XESL_LANGUAGE_GLSL #define XESL_Y_SCREEN_DIRECTION 1.0 #else #define XESL_Y_SCREEN_DIRECTION -1.0 #endif // XESL_LANGUAGE_GLSL #if XESL_LANGUAGE_GLSL // GLSL requires just const for declaring a constant in the global scope. #define xesl_staticConst const #elif XESL_LANGUAGE_HLSL // HLSL requires static const for declaring a constant in the global scope so // it doesn't go to $Globals instead. #define xesl_staticConst static const #elif XESL_LANGUAGE_MSL #define xesl_staticConst constexpr constant #else #error xesl_staticConst not defined for the target language. #endif // XESL_LANGUAGE #if XESL_LANGUAGE_GLSL #define xesl_block_offset_member(glsl_offset_bytes, hlsl_packoffset, type, \ name_element_count) \ layout(offset=glsl_offset_bytes) type name_element_count; #elif XESL_LANGUAGE_HLSL #define xesl_block_offset_member(glsl_offset_bytes, hlsl_packoffset, type, \ name_element_count) \ type name_element_count : packoffset(hlsl_packoffset); #elif XESL_LANGUAGE_MSL // Explicit offset is not supported by MSL. #define xesl_block_offset_member(glsl_offset_bytes, hlsl_packoffset, type, \ name_element_count) \ type name_element_count; #else #error xesl_block_offset_member not defined for the target language. #endif // XESL_LANGUAGE // Structures of constant and structured buffer bindings must be declared before // the entry point declaration. // Constant buffers and push constants must be manually packed as std140 (which // is stricter than HLSL packing) due to the GLSL requirement. This means that // 32x4 and 32x3 vectors must start at 16-byte alignment, 32x2 at 8-byte, and a // single 32-bit value can be placed immediately after a 32x3 vector (the Vulkan // definition of this behavior). Specifically, all alignment padding must be // inserted explicitly (or xesl_block_offset_member must be used), as by default // HLSL doesn't have the alignment requirement, only the rule that elements // (array elements, or single non-array members) must not cross 32x4 vector // boundaries, so something like float|float3 or float|float2|float will be // packed differently in GLSL (float|pad3|float3 or float|pad|float2|float) and // HLSL (float|float3 or float|float2|float). // Constant buffer and push constant member names will be in the global scope in // some target languages - they must not collide with anything else there. To // access a constant, use xesl_constant or xesl_pushConstant. // Push constants, even though may be spread across multiple constant buffers in // the Direct3D 12 API, must be declared in a single structure in XeSL - the // reason is that layout qualifiers in GLSL can't be used in regular structures, // only in blocks, and sub-blocks can't be declared in a block, so there's no // way to create separate identifiers for push constant ranges in GLSL. Though // both GLSL and HLSL support anonymous push constants / cbuffers, MSL requires // a name for the buffer binding. // In GLSL, the offsets in the push constants are global across shader stages. // In HLSL, they're local to the specific root constant buffer. #if XESL_LANGUAGE_GLSL #define xesl_constantBuffer_begin(name, glsl_set, glsl_binding, hlsl_b, \ hlsl_b_space) \ layout(std140, glsl_set, glsl_binding) \ uniform xesl_id_constantBuffer_##name { #define xesl_constantBuffer_end(name) \ } name; #define xesl_constant(cbuffer_name, constant_name) cbuffer_name.constant_name #define xesl_pushConstants_begin(hlsl_b, hlsl_b_space) \ layout(push_constant) uniform xesl_pushConstants_block { #define xesl_pushConstants_end \ } xesl_pushConstants; #define xesl_pushConstant(name) xesl_pushConstants.name #elif XESL_LANGUAGE_HLSL #define xesl_constantBuffer_begin(name, glsl_set, glsl_binding, hlsl_b, \ hlsl_b_space) \ cbuffer name : register(hlsl_b, hlsl_b_space) { #define xesl_constantBuffer_end(name) \ }; #define xesl_constant(cbuffer_name, constant_name) constant_name #define xesl_pushConstants_begin(hlsl_b, hlsl_b_space) \ cbuffer xesl_pushConstants : register(hlsl_b, hlsl_b_space) { #define xesl_pushConstants_end \ }; #define xesl_pushConstant(name) name #elif XESL_LANGUAGE_MSL #define xesl_constantBuffer_begin(name, glsl_set, glsl_binding, hlsl_b, \ hlsl_b_space) \ struct xesl_id_constantBuffer_##name { #define xesl_constantBuffer_end(name) \ }; #define xesl_constantBuffer_binding(name, msl_buffer) \ constant xesl_id_constantBuffer_##name& name [[msl_buffer]] #define xesl_constant(cbuffer_name, constant_name) cbuffer_name.constant_name #define xesl_pushConstants_begin(hlsl_b, hlsl_b_space) \ struct xesl_pushConstants_struct { #define xesl_pushConstants_end \ }; #define xesl_pushConstants_binding(msl_buffer) \ constant xesl_pushConstants_struct& xesl_pushConstants [[msl_buffer]] #define xesl_pushConstant(name) xesl_pushConstants.name #else #error Constant buffers not defined for the target language. #endif // XESL_LANGUAGE #ifndef xesl_constantBuffer_binding #define xesl_constantBuffer_binding(name, msl_buffer) #endif // !xesl_constantBuffer_binding #ifndef xesl_pushConstants_binding #define xesl_pushConstants_binding(msl_buffer) #endif // !xesl_pushConstants_binding // Declarations of typed storage buffers and dword buffers (_declare) must be // outside the entry point, but their bindings (_binding) must also be specified // in the entry point binding declarations. // // xesl_typedStorageBuffer is a buffer limited to 1/2/4-component vectors of // 32-bit integers and floats, a typed buffer on Direct3D, but a storage buffer // (as opposed to a texel buffer, which has a very small minimum requirement for // the maximum size) on Vulkan. // // xesl_uintVectorBuffer is a buffer containing 32-bit values, but loading or // storing may be done for 2, 3 or 4 consecutive values that are still // 32-bit-aligned, and depending on the language and hardware support, access // of multiple elements may or may not be compiled into a single hardware // instruction instead of separate accesses of individual elements. Each index // value corresponds to a 32-bit element. Implementations for languages without // native support must use functions, not macros, for adding the component // offset to the index to avoid evaluating the address multiple times. #if XESL_LANGUAGE_GLSL // Binding declarations. #define xesl_typedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_t, hlsl_t_space) \ layout(std430, glsl_set, glsl_binding) \ readonly buffer xesl_id_buffer_##name { \ value_type xesl_id_data[]; \ } name; #define xesl_writeTypedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_u, \ hlsl_u_space) \ layout(std430, glsl_set, glsl_binding) \ writeonly buffer xesl_id_buffer_##name { \ value_type xesl_id_data[]; \ } name; #define xesl_uintVectorBuffer_declare(name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space) \ layout(std430, glsl_set, glsl_binding) \ readonly buffer xesl_id_buffer_##name { \ uint xesl_id_data[]; \ } name; \ xesl_uint2 xesl_id_uintVectorBuffer_load2_##name( \ uint xesl_var_position) { \ return xesl_uint2(name.xesl_id_data[xesl_var_position], \ name.xesl_id_data[xesl_var_position + 1u]); \ } \ xesl_uint3 xesl_id_uintVectorBuffer_load3_##name( \ uint xesl_var_position) { \ return xesl_uint3(name.xesl_id_data[xesl_var_position], \ name.xesl_id_data[xesl_var_position + 1u], \ name.xesl_id_data[xesl_var_position + 2u]); \ } \ xesl_uint4 xesl_id_uintVectorBuffer_load4_##name( \ uint xesl_var_position) { \ return xesl_uint4(name.xesl_id_data[xesl_var_position], \ name.xesl_id_data[xesl_var_position + 1u], \ name.xesl_id_data[xesl_var_position + 2u], \ name.xesl_id_data[xesl_var_position + 3u]); \ } // Loading and storing. #define xesl_typedStorageBufferLoad(name, position) \ ((name).xesl_id_data[uint(position)]) #define xesl_writeTypedStorageBufferStore(name, position, value) \ ((name).xesl_id_data[uint(position)] = (value)) #define xesl_uintVectorBufferLoad1(name, position) \ ((name).xesl_id_data[uint(position)]) #define xesl_uintVectorBufferLoad2(name, position) \ xesl_id_uintVectorBuffer_load2_##name(uint(position)) #define xesl_uintVectorBufferLoad3(name, position) \ xesl_id_uintVectorBuffer_load3_##name(uint(position)) #define xesl_uintVectorBufferLoad4(name, position) \ xesl_id_uintVectorBuffer_load4_##name(uint(position)) #elif XESL_LANGUAGE_HLSL // Binding declarations. #define xesl_typedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_t, hlsl_t_space) \ Buffer name : register(hlsl_t, hlsl_t_space); #define xesl_writeTypedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_u, \ hlsl_u_space) \ RWBuffer name : register(hlsl_u, hlsl_u_space); #define xesl_uintVectorBuffer_declare(name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space) \ ByteAddressBuffer name : register(hlsl_t, hlsl_t_space); // Loading and storing. #define xesl_typedStorageBufferLoad(name, position) ((name)[uint(position)]) #define xesl_writeTypedStorageBufferStore(name, position, value) \ ((name)[uint(position)] = (value)) #define xesl_uintVectorBufferLoad1(name, position) \ ((name).Load(int(position) << 2)) #define xesl_uintVectorBufferLoad2(name, position) \ ((name).Load2(int(position) << 2)) #define xesl_uintVectorBufferLoad3(name, position) \ ((name).Load3(int(position) << 2)) #define xesl_uintVectorBufferLoad4(name, position) \ ((name).Load4(int(position) << 2)) #elif XESL_LANGUAGE_MSL // Binding declarations. #define xesl_typedStorageBuffer_binding(value_type, name, msl_buffer) \ const device value_type* name [[msl_buffer]] #define xesl_writeTypedStorageBuffer_binding(value_type, name, msl_buffer) \ device value_type* name [[msl_buffer]] #define xesl_uintVectorBuffer_binding(name, msl_buffer) \ const device uint* name [[msl_buffer]] // Loading and storing. #define xesl_typedStorageBufferLoad(name, position) ((name)[size_t(position)]) #define xesl_writeTypedStorageBufferStore(name, position, value) \ ((name)[size_t(position)] = (value)) #define xesl_uintVectorBufferLoad1(name, position) ((name)[size_t(position)]) #define xesl_uintVectorBufferLoad2(name, position) \ xesl_uint2(*reinterpret_cast( \ &((name)[size_t(position)]))) #define xesl_uintVectorBufferLoad3(name, position) \ xesl_uint3(*reinterpret_cast( \ &((name)[size_t(position)]))) #define xesl_uintVectorBufferLoad4(name, position) \ xesl_uint4(*reinterpret_cast( \ &((name)[size_t(position)]))) #else #error Storage buffers not defined for the target language. #endif // XESL_LANGUAGE #ifndef xesl_typedStorageBuffer_declare #define xesl_typedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_t, hlsl_t_space) #endif // !xesl_typedStorageBuffer_declare #ifndef xesl_writeTypedStorageBuffer_declare #define xesl_writeTypedStorageBuffer_declare(value_type, name, glsl_set, \ glsl_binding, hlsl_u, \ hlsl_u_space) #endif // !xesl_writeTypedStorageBuffer_declare #ifndef xesl_typedStorageBuffer_binding #define xesl_typedStorageBuffer_binding(value_type, name, msl_buffer) #endif // !xesl_typedStorageBuffer_binding #ifndef xesl_writeTypedStorageBuffer_binding #define xesl_writeTypedStorageBuffer_binding(value_type, name, msl_buffer) #endif // !xesl_writeTypedStorageBuffer_binding #ifndef xesl_uintVectorBuffer_declare #define xesl_uintVectorBuffer_declare(name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space) #endif // !xesl_uintVectorBuffer_declare #ifndef xesl_uintVectorBuffer_binding #define xesl_uintVectorBuffer_binding(name, msl_buffer) #endif // !xesl_uintVectorBuffer_binding // Buffer, texture, sampler and image bindings must be in the entry point // bindings declaration. // - xesl_texture is a separate texture. // - xesl_samplerState is a separate sampler. // - xesl_sampler is a combined texture / sampler where available, internally // separate where not. #if XESL_LANGUAGE_GLSL #define XESL_COMBINED_TEXTURE_SAMPLER 1 // Types. #define xesl_textureBuffer textureBuffer #define xesl_utextureBuffer utextureBuffer #define xesl_texture2D texture2D #define xesl_texture2DMS texture2DMS #define xesl_samplerBuffer samplerBuffer #define xesl_usamplerBuffer usamplerBuffer #define xesl_sampler2D sampler2D #define xesl_image2D image2D #define xesl_imageFormat_rgb10_a2 rgb10_a2 #define xesl_imageFormat_rgba16f rgba16f // Binding declarations. #define xesl_texture(texture_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, msl_texture) \ layout(glsl_set, glsl_binding) uniform texture_type name; #define xesl_samplerState(name, glsl_set, glsl_binding, hlsl_s, \ hlsl_s_space, msl_sampler) \ layout(glsl_set, glsl_binding) uniform sampler name; #define xesl_sampler(sampler_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, hlsl_s, hlsl_s_space, msl_texture, \ msl_sampler) \ layout(glsl_set, glsl_binding) uniform sampler_type name; #define xesl_writeImage(type, format, name, glsl_set, glsl_binding, hlsl_u, \ hlsl_u_space, msl_texture) \ layout(format, glsl_set, glsl_binding) uniform writeonly type name; // Fetching and storing. #define xesl_texelFetchBuffer(texture_name, position) \ texelFetch(texture_name, int(position)) #define xesl_texelFetch2D(texture_name, position, lod) \ texelFetch(texture_name, xesl_int2(position), int(lod)) #define xesl_texelFetch2DMS(texture_name, position, sample_index) \ texelFetch(texture_name, xesl_int2(position), int(sample_index)) #define xesl_textureSampleLod2D_sep(texture_name, sampler_name, position, \ lod) \ textureLod(sampler2D(texture_name, sampler_name), position, lod) #define xesl_textureSampleLod2D_comb(texture_sampler_name, position, lod) \ textureLod(texture_sampler_name, position, lod) #define xesl_textureGatherRed2D_sep(texture_name, sampler_name, position) \ textureGather(sampler2D(texture_name, sampler_name), position, 0) #define xesl_textureGatherGreen2D_sep(texture_name, sampler_name, position) \ textureGather(sampler2D(texture_name, sampler_name), position, 1) #define xesl_textureGatherBlue2D_sep(texture_name, sampler_name, position) \ textureGather(sampler2D(texture_name, sampler_name), position, 2) #define xesl_textureGatherAlpha2D_sep(texture_name, sampler_name, position) \ textureGather(sampler2D(texture_name, sampler_name), position, 3) #define xesl_textureGatherRed2D_comb(texture_sampler_name, position) \ textureGather(texture_sampler_name, position, 0) #define xesl_textureGatherGreen2D_comb(texture_sampler_name, position) \ textureGather(texture_sampler_name, position, 1) #define xesl_textureGatherBlue2D_comb(texture_sampler_name, position) \ textureGather(texture_sampler_name, position, 2) #define xesl_textureGatherAlpha2D_comb(texture_sampler_name, position) \ textureGather(texture_sampler_name, position, 3) #define xesl_imageStore2DRGBA(name, position, data) \ imageStore(name, xesl_int2(position), data) #elif XESL_LANGUAGE_HLSL // Types. #define xesl_textureBuffer Buffer #define xesl_utextureBuffer Buffer #define xesl_texture2D Texture2D #define xesl_texture2DMS Texture2DMS #define xesl_image2D RWTexture2D #define xesl_imageFormat_rgb10_a2 unorm float4 #define xesl_imageFormat_rgba16f float4 // Binding declarations. #define xesl_texture(texture_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, msl_texture) \ texture_type name : register(hlsl_t, hlsl_t_space); #define xesl_samplerState(name, glsl_set, glsl_binding, hlsl_s, \ hlsl_s_space, msl_sampler) \ SamplerState name : register(hlsl_s, hlsl_s_space); #define xesl_writeImage(type, format, name, glsl_set, glsl_binding, hlsl_u, \ hlsl_u_space, msl_texture) \ type name : register(hlsl_u, hlsl_u_space); // Fetching and storing. #define xesl_texelFetchBuffer(texture_name, position) \ ((texture_name).Load(int(position))) #define xesl_texelFetch2D(texture_name, position, lod) \ ((texture_name).Load(xesl_int3(position, lod))) #define xesl_texelFetch2DMS(texture_name, position, sample_index) \ ((texture_name).Load(xesl_int2(position), int(sample_index))) #define xesl_textureSampleLod2D_sep(texture_name, sampler_name, position, \ lod) \ ((texture_name).SampleLevel(sampler_name, position, lod)) #define xesl_textureGatherRed2D_sep(texture_name, sampler_name, position) \ ((texture_name).GatherRed(sampler_name, position)) #define xesl_textureGatherGreen2D_sep(texture_name, sampler_name, position) \ ((texture_name).GatherGreen(sampler_name, position)) #define xesl_textureGatherBlue2D_sep(texture_name, sampler_name, position) \ ((texture_name).GatherBlue(sampler_name, position)) #define xesl_textureGatherAlpha2D_sep(texture_name, sampler_name, position) \ ((texture_name).GatherAlpha(sampler_name, position)) #define xesl_imageStore2DRGBA(name, position, data) \ ((name)[xesl_int2(position)] = (data)) #elif XESL_LANGUAGE_MSL // Types. #define xesl_textureBuffer texture_buffer #define xesl_utextureBuffer texture_buffer #define xesl_texture2D texture2d #define xesl_texture2DMS texture2d_ms #define xesl_image2D texture2d #define xesl_imageFormat_rgb10_a2 float #define xesl_imageFormat_rgba16f float // Binding declarations. #define xesl_texture(texture_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, msl_texture) \ texture_type name [[msl_texture]] #define xesl_samplerState(name, glsl_set, glsl_binding, hlsl_s, \ hlsl_s_space, msl_sampler) \ sampler name [[msl_sampler]] #define xesl_writeImage(type, format, name, glsl_set, glsl_binding, hlsl_u, \ hlsl_u_space, msl_texture) \ type name [[msl_texture]] // Fetching and storing. #define xesl_texelFetchBuffer(texture_name, position) \ ((texture_name).read(uint(position))) #define xesl_texelFetch2D(texture_name, position, lod) \ ((texture_name).read(xesl_uint2(position), uint(lod))) #define xesl_texelFetch2DMS(texture_name, position, sample_index) \ ((texture_name).read(xesl_uint2(position), uint(sample_index))) #define xesl_textureSampleLod2D_sep(texture_name, sampler_name, position, \ lod) \ ((texture_name).sample(sampler_name, position, level(lod))) #define xesl_textureGatherRed2D_sep(texture_name, sampler_name, position) \ ((texture_name).gather(sampler_name, position, xesl_int2(0), \ component::x)) #define xesl_textureGatherGreen2D_sep(texture_name, sampler_name, position) \ ((texture_name).gather(sampler_name, position, xesl_int2(0), \ component::y)) #define xesl_textureGatherBlue2D_sep(texture_name, sampler_name, position) \ ((texture_name).gather(sampler_name, position, xesl_int2(0), \ component::z)) #define xesl_textureGatherAlpha2D_sep(texture_name, sampler_name, position) \ ((texture_name).gather(sampler_name, position, xesl_int2(0), \ component::w)) #define xesl_imageStore2DRGBA(name, position, data) \ ((name).write(data, xesl_uint2(position))) #else #error Buffers and textures not defined for the target language. #endif // XESL_LANGUAGE // If there's no language specialization doing this already, implement combined // textures / samplers as separate, with the `xesl_id_sampler_` prefix for // samplers. The sampler types become the texture types. #if !XESL_COMBINED_TEXTURE_SAMPLER #ifndef xesl_sampler2D #define xesl_sampler2D xesl_texture2D #endif // !xesl_sampler2D #ifndef xesl_sampler #define xesl_sampler(sampler_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, hlsl_s, hlsl_s_space, msl_texture, \ msl_sampler) \ xesl_texture(sampler_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, msl_texture) \ xesl_entry_binding_next \ xesl_samplerState(xesl_id_sampler_##name, glsl_set, glsl_binding, \ hlsl_s, hlsl_s_space, msl_sampler) #endif // !xesl_sampler #ifndef xesl_textureSampleLod2D_comb #define xesl_textureSampleLod2D_comb(texture_sampler_name, position, lod) \ xesl_textureSampleLod2D_sep(texture_sampler_name, \ xesl_id_sampler_##texture_sampler_name, \ position, lod) #endif // !xesl_textureSampleLod2D_comb #ifndef xesl_textureGatherRed2D_comb #define xesl_textureGatherRed2D_comb(texture_sampler_name, position) \ xesl_textureGatherRed2D_sep(texture_sampler_name, \ xesl_id_sampler_##texture_sampler_name, \ position) #endif // !xesl_textureGatherRed2D_comb #ifndef xesl_textureGatherGreen2D_comb #define xesl_textureGatherGreen2D_comb(texture_sampler_name, position) \ xesl_textureGatherGreen2D_sep(texture_sampler_name, \ xesl_id_sampler_##texture_sampler_name, \ position) #endif // !xesl_textureGatherGreen2D_comb #ifndef xesl_textureGatherBlue2D_comb #define xesl_textureGatherBlue2D_comb(texture_sampler_name, position) \ xesl_textureGatherBlue2D_sep(texture_sampler_name, \ xesl_id_sampler_##texture_sampler_name, \ position) #endif // !xesl_textureGatherBlue2D_comb #ifndef xesl_textureGatherAlpha2D_comb #define xesl_textureGatherAlpha2D_comb(texture_sampler_name, position) \ xesl_textureGatherAlpha2D_sep(texture_sampler_name, \ xesl_id_sampler_##texture_sampler_name, \ position) #endif // !xesl_textureGatherAlpha2D_comb #endif // !XESL_COMBINED_TEXTURE_SAMPLER // Passing bindings to functions, and also output and input / output parameters. #if XESL_LANGUAGE_MSL #define xesl_function_param_out(type, name) thread type& name #define xesl_function_param_inout(type, name) thread type& name #else #define xesl_function_param_out(type, name) out type name #define xesl_function_param_inout(type, name) inout type name #endif // XESL_LANGUAGE_MSL #if XESL_LANGUAGE_MSL // Prototype parameters. #define xesl_function_param_constantBuffer(name) \ constant xesl_id_constantBuffer_##name& name #define xesl_function_param_next_after_constantBuffer , #define xesl_function_param_pushConstants \ constant xesl_pushConstants_struct& xesl_pushConstants #define xesl_function_param_next_after_pushConstants , #define xesl_function_param_uintVectorBuffer(name) const device uint* name #define xesl_function_param_next_after_uintVectorBuffer , // Call arguments. #define xesl_function_call_constantBuffer(name) (name) #define xesl_function_call_next_after_constantBuffer , #define xesl_function_call_pushConstants xesl_pushConstants #define xesl_function_call_next_after_pushConstants , #define xesl_function_call_uintVectorBuffer(name) (name) #define xesl_function_call_next_after_uintVectorBuffer , #endif // XESL_LANGUAGE // Prototype parameters. #ifndef xesl_function_param_constantBuffer #define xesl_function_param_constantBuffer(name) #endif // !xesl_function_param_constantBuffer #ifndef xesl_function_param_next_after_constantBuffer #define xesl_function_param_next_after_constantBuffer #endif // !xesl_function_param_next_after_constantBuffer #ifndef xesl_function_param_pushConstants #define xesl_function_param_pushConstants #endif // !xesl_function_param_pushConstants #ifndef xesl_function_param_next_after_pushConstants #define xesl_function_param_next_after_pushConstants #endif // !xesl_function_param_next_after_pushConstants #ifndef xesl_function_param_uintVectorBuffer #define xesl_function_param_uintVectorBuffer(name) #endif // !xesl_function_param_uintVectorBuffer #ifndef xesl_function_param_next_after_uintVectorBuffer #define xesl_function_param_next_after_uintVectorBuffer #endif // !xesl_function_param_next_after_uintVectorBuffer // Call arguments. #ifndef xesl_function_call_constantBuffer #define xesl_function_call_constantBuffer(name) #endif // !xesl_function_call_constantBuffer #ifndef xesl_function_call_next_after_constantBuffer #define xesl_function_call_next_after_constantBuffer #endif // !xesl_function_call_next_after_constantBuffer #ifndef xesl_function_call_pushConstants #define xesl_function_call_pushConstants #endif // !xesl_function_call_pushConstants #ifndef xesl_function_call_next_after_pushConstants #define xesl_function_call_next_after_pushConstants #endif // !xesl_function_call_next_after_pushConstants #ifndef xesl_function_call_uintVectorBuffer #define xesl_function_call_uintVectorBuffer(name) #endif // !xesl_function_call_uintVectorBuffer #ifndef xesl_function_call_next_after_uintVectorBuffer #define xesl_function_call_next_after_uintVectorBuffer #endif // !xesl_function_call_next_after_uintVectorBuffer // Attributes. #if XESL_LANGUAGE_GLSL #define xesl_unroll [[unroll]] #define xesl_dont_unroll [[dont_unroll]] #define xesl_flatten [[flatten]] #define xesl_dont_flatten [[dont_flatten]] #elif XESL_LANGUAGE_HLSL #define xesl_unroll [unroll] #define xesl_dont_unroll [loop] #define xesl_flatten [flatten] #define xesl_dont_flatten [branch] #endif // XESL_LANGUAGE #ifndef xesl_unroll #define xesl_unroll #endif // !xesl_unroll #ifndef xesl_dont_unroll #define xesl_dont_unroll #endif // !xesl_dont_unroll #ifndef xesl_flatten #define xesl_flatten #endif // !xesl_flatten #ifndef xesl_dont_flatten #define xesl_dont_flatten #endif // !xesl_dont_flatten // Function aliases. // // Use the `xesl_var_` prefix for arguments of functions that are not macros and // for local variables. #if XESL_LANGUAGE_GLSL #define xesl_lessThan lessThan #define xesl_lessThanEqual lessThanEqual #define xesl_greaterThan greaterThan #define xesl_greaterThanEqual greaterThanEqual #define xesl_equal equal #define xesl_notEqual notEqual #define xesl_not not #define xesl_select(condition, true_result, false_result) \ mix(false_result, true_result, condition) #elif XESL_LANGUAGE_HLSL #define xesl_lessThan(x, y) ((x) < (y)) #define xesl_lessThanEqual(x, y) ((x) <= (y)) #define xesl_greaterThan(x, y) ((x) > (y)) #define xesl_greaterThanEqual(x, y) ((x) >= (y)) #define xesl_equal(x, y) ((x) == (y)) #define xesl_notEqual(x, y) ((x) != (y)) #define xesl_not(x) (!(x)) #define xesl_select(condition, true_result, false_result) \ ((condition) ? (true_result) : (false_result)) #elif XESL_LANGUAGE_MSL #define xesl_lessThan(x, y) ((x) < (y)) #define xesl_lessThanEqual(x, y) ((x) <= (y)) #define xesl_greaterThan(x, y) ((x) > (y)) #define xesl_greaterThanEqual(x, y) ((x) >= (y)) #define xesl_equal(x, y) ((x) == (y)) #define xesl_notEqual(x, y) ((x) != (y)) #define xesl_not(x) (!(x)) #define xesl_select(condition, true_result, false_result) \ select(false_result, true_result, condition) #else #error Comparison operations not defined for the target language. #endif #if XESL_LANGUAGE_GLSL #define xesl_floatBitsToInt floatBitsToInt #define xesl_floatBitsToUint floatBitsToUint #define xesl_intBitsToFloat intBitsToFloat #define xesl_uintBitsToFloat uintBitsToFloat #elif XESL_LANGUAGE_HLSL // Using functions instead of #define for implicit argument conversion. int xesl_floatBitsToInt(float xesl_var_value) { return asint(xesl_var_value); } xesl_int2 xesl_floatBitsToInt(xesl_float2 xesl_var_value) { return asint(xesl_var_value); } xesl_int3 xesl_floatBitsToInt(xesl_float3 xesl_var_value) { return asint(xesl_var_value); } xesl_int4 xesl_floatBitsToInt(xesl_float4 xesl_var_value) { return asint(xesl_var_value); } uint xesl_floatBitsToUint(float xesl_var_value) { return asuint(xesl_var_value); } xesl_uint2 xesl_floatBitsToUint(xesl_float2 xesl_var_value) { return asuint(xesl_var_value); } xesl_uint3 xesl_floatBitsToUint(xesl_float3 xesl_var_value) { return asuint(xesl_var_value); } xesl_uint4 xesl_floatBitsToUint(xesl_float4 xesl_var_value) { return asuint(xesl_var_value); } float xesl_intBitsToFloat(int xesl_var_value) { return asfloat(xesl_var_value); } xesl_float2 xesl_intBitsToFloat(xesl_int2 xesl_var_value) { return asfloat(xesl_var_value); } xesl_float3 xesl_intBitsToFloat(xesl_int3 xesl_var_value) { return asfloat(xesl_var_value); } xesl_float4 xesl_intBitsToFloat(xesl_int4 xesl_var_value) { return asfloat(xesl_var_value); } float xesl_uintBitsToFloat(uint xesl_var_value) { return asfloat(xesl_var_value); } xesl_float2 xesl_uintBitsToFloat(xesl_uint2 xesl_var_value) { return asfloat(xesl_var_value); } xesl_float3 xesl_uintBitsToFloat(xesl_uint3 xesl_var_value) { return asfloat(xesl_var_value); } xesl_float4 xesl_uintBitsToFloat(xesl_uint4 xesl_var_value) { return asfloat(xesl_var_value); } #elif XESL_LANGUAGE_MSL // Using functions instead of #define for implicit argument conversion. int xesl_floatBitsToInt(float xesl_var_value) { return as_type(xesl_var_value); } xesl_int2 xesl_floatBitsToInt(xesl_float2 xesl_var_value) { return as_type(xesl_var_value); } xesl_int3 xesl_floatBitsToInt(xesl_float3 xesl_var_value) { return as_type(xesl_var_value); } xesl_int4 xesl_floatBitsToInt(xesl_float4 xesl_var_value) { return as_type(xesl_var_value); } uint xesl_floatBitsToUint(float xesl_var_value) { return as_type(xesl_var_value); } xesl_uint2 xesl_floatBitsToUint(xesl_float2 xesl_var_value) { return as_type(xesl_var_value); } xesl_uint3 xesl_floatBitsToUint(xesl_float3 xesl_var_value) { return as_type(xesl_var_value); } xesl_uint4 xesl_floatBitsToUint(xesl_float4 xesl_var_value) { return as_type(xesl_var_value); } float xesl_intBitsToFloat(int xesl_var_value) { return as_type(xesl_var_value); } xesl_float2 xesl_intBitsToFloat(xesl_int2 xesl_var_value) { return as_type(xesl_var_value); } xesl_float3 xesl_intBitsToFloat(xesl_int3 xesl_var_value) { return as_type(xesl_var_value); } xesl_float4 xesl_intBitsToFloat(xesl_int4 xesl_var_value) { return as_type(xesl_var_value); } float xesl_uintBitsToFloat(uint xesl_var_value) { return as_type(xesl_var_value); } xesl_float2 xesl_uintBitsToFloat(xesl_uint2 xesl_var_value) { return as_type(xesl_var_value); } xesl_float3 xesl_uintBitsToFloat(xesl_uint3 xesl_var_value) { return as_type(xesl_var_value); } xesl_float4 xesl_uintBitsToFloat(xesl_uint4 xesl_var_value) { return as_type(xesl_var_value); } #else #error Float bit casting not defined for the target language. #endif // XESL_LANGUAGE #if XESL_LANGUAGE_GLSL float xesl_saturate(float xesl_var_value) { return clamp(xesl_var_value, 0.0, 1.0); } xesl_float2 xesl_saturate(xesl_float2 xesl_var_value) { return clamp(xesl_var_value, xesl_float_x2(0.0), xesl_float_x2(1.0)); } xesl_float3 xesl_saturate(xesl_float3 xesl_var_value) { return clamp(xesl_var_value, xesl_float_x3(0.0), xesl_float_x3(1.0)); } xesl_float4 xesl_saturate(xesl_float4 xesl_var_value) { return clamp(xesl_var_value, xesl_float_x4(0.0), xesl_float_x4(1.0)); } #else #define xesl_saturate saturate #endif // XESL_LANGUAGE_GLSL // Returning a unsigned integer vector. The result is undefined for zero. #if XESL_LANGUAGE_GLSL uint xesl_firstOneBitLow(int xesl_var_value) { return uint(findLSB(xesl_var_value)); } xesl_uint2 xesl_firstOneBitLow(xesl_int2 xesl_var_value) { return xesl_uint2(findLSB(xesl_var_value)); } xesl_uint3 xesl_firstOneBitLow(xesl_int3 xesl_var_value) { return xesl_uint3(findLSB(xesl_var_value)); } xesl_uint4 xesl_firstOneBitLow(xesl_int4 xesl_var_value) { return xesl_uint4(findLSB(xesl_var_value)); } uint xesl_firstOneBitLow(uint xesl_var_value) { return uint(findLSB(xesl_var_value)); } xesl_uint2 xesl_firstOneBitLow(xesl_uint2 xesl_var_value) { return xesl_uint2(findLSB(xesl_var_value)); } xesl_uint3 xesl_firstOneBitLow(xesl_uint3 xesl_var_value) { return xesl_uint3(findLSB(xesl_var_value)); } xesl_uint4 xesl_firstOneBitLow(xesl_uint4 xesl_var_value) { return xesl_uint4(findLSB(xesl_var_value)); } // GLSL findMSB finds the highest 0 for a negative value. uint xesl_firstOneBitHigh(int xesl_var_value) { return uint(findMSB(uint(xesl_var_value))); } xesl_uint2 xesl_firstOneBitHigh(xesl_int2 xesl_var_value) { return xesl_uint2(findMSB(xesl_uint2(xesl_var_value))); } xesl_uint3 xesl_firstOneBitHigh(xesl_int3 xesl_var_value) { return xesl_uint3(findMSB(xesl_uint3(xesl_var_value))); } xesl_uint4 xesl_firstOneBitHigh(xesl_int4 xesl_var_value) { return xesl_uint4(findMSB(xesl_uint4(xesl_var_value))); } uint xesl_firstOneBitHigh(uint xesl_var_value) { return uint(findMSB(xesl_var_value)); } xesl_uint2 xesl_firstOneBitHigh(xesl_uint2 xesl_var_value) { return xesl_uint2(findMSB(xesl_var_value)); } xesl_uint3 xesl_firstOneBitHigh(xesl_uint3 xesl_var_value) { return xesl_uint3(findMSB(xesl_var_value)); } xesl_uint4 xesl_firstOneBitHigh(xesl_uint4 xesl_var_value) { return xesl_uint4(findMSB(xesl_var_value)); } #elif XESL_LANGUAGE_HLSL uint xesl_firstOneBitLow(int xesl_var_value) { return uint(firstbitlow(xesl_var_value)); } xesl_uint2 xesl_firstOneBitLow(xesl_int2 xesl_var_value) { return xesl_uint2(firstbitlow(xesl_var_value)); } xesl_uint3 xesl_firstOneBitLow(xesl_int3 xesl_var_value) { return xesl_uint3(firstbitlow(xesl_var_value)); } xesl_uint4 xesl_firstOneBitLow(xesl_int4 xesl_var_value) { return xesl_uint4(firstbitlow(xesl_var_value)); } uint xesl_firstOneBitLow(uint xesl_var_value) { return firstbitlow(xesl_var_value); } xesl_uint2 xesl_firstOneBitLow(xesl_uint2 xesl_var_value) { return firstbitlow(xesl_var_value); } xesl_uint3 xesl_firstOneBitLow(xesl_uint3 xesl_var_value) { return firstbitlow(xesl_var_value); } xesl_uint4 xesl_firstOneBitLow(xesl_uint4 xesl_var_value) { return firstbitlow(xesl_var_value); } // HLSL firstbithigh finds the highest 0 for a negative value. uint xesl_firstOneBitHigh(int xesl_var_value) { return uint(firstbithigh(uint(xesl_var_value))); } xesl_uint2 xesl_firstOneBitHigh(xesl_int2 xesl_var_value) { return xesl_uint2(firstbithigh(xesl_uint2(xesl_var_value))); } xesl_uint3 xesl_firstOneBitHigh(xesl_int3 xesl_var_value) { return xesl_uint3(firstbithigh(xesl_uint3(xesl_var_value))); } xesl_uint4 xesl_firstOneBitHigh(xesl_int4 xesl_var_value) { return xesl_uint4(firstbithigh(xesl_uint4(xesl_var_value))); } uint xesl_firstOneBitHigh(uint xesl_var_value) { return firstbithigh(xesl_var_value); } xesl_uint2 xesl_firstOneBitHigh(xesl_uint2 xesl_var_value) { return firstbithigh(xesl_var_value); } xesl_uint3 xesl_firstOneBitHigh(xesl_uint3 xesl_var_value) { return firstbithigh(xesl_var_value); } xesl_uint4 xesl_firstOneBitHigh(xesl_uint4 xesl_var_value) { return firstbithigh(xesl_var_value); } #elif XESL_LANGUAGE_MSL uint xesl_firstOneBitLow(int xesl_var_value) { return uint(ctz(xesl_var_value)); } xesl_uint2 xesl_firstOneBitLow(xesl_int2 xesl_var_value) { return xesl_uint2(ctz(xesl_var_value)); } xesl_uint3 xesl_firstOneBitLow(xesl_int3 xesl_var_value) { return xesl_uint3(ctz(xesl_var_value)); } xesl_uint4 xesl_firstOneBitLow(xesl_int4 xesl_var_value) { return xesl_uint4(ctz(xesl_var_value)); } uint xesl_firstOneBitLow(uint xesl_var_value) { return ctz(xesl_var_value); } xesl_uint2 xesl_firstOneBitLow(xesl_uint2 xesl_var_value) { return ctz(xesl_var_value); } xesl_uint3 xesl_firstOneBitLow(xesl_uint3 xesl_var_value) { return ctz(xesl_var_value); } xesl_uint4 xesl_firstOneBitLow(xesl_uint4 xesl_var_value) { return ctz(xesl_var_value); } uint xesl_firstOneBitHigh(int xesl_var_value) { return 32u - uint(clz(xesl_var_value)); } xesl_uint2 xesl_firstOneBitHigh(xesl_int2 xesl_var_value) { return xesl_uint_x2(32u) - xesl_uint2(clz(xesl_var_value)); } xesl_uint3 xesl_firstOneBitHigh(xesl_int3 xesl_var_value) { return xesl_uint_x3(32u) - xesl_uint3(clz(xesl_var_value)); } xesl_uint4 xesl_firstOneBitHigh(xesl_int4 xesl_var_value) { return xesl_uint_x4(32u) - xesl_uint4(clz(xesl_var_value)); } uint xesl_firstOneBitHigh(uint xesl_var_value) { return 32u - clz(xesl_var_value); } xesl_uint2 xesl_firstOneBitHigh(xesl_uint2 xesl_var_value) { return xesl_uint_x2(32u) - clz(xesl_var_value); } xesl_uint3 xesl_firstOneBitHigh(xesl_uint3 xesl_var_value) { return xesl_uint_x3(32u) - clz(xesl_var_value); } xesl_uint4 xesl_firstOneBitHigh(xesl_uint4 xesl_var_value) { return xesl_uint_x4(32u) - clz(xesl_var_value); } #else #error Bit count operations not defined for the target language. #endif // XESL_LANGUAGE #if XESL_LANGUAGE_GLSL #define xesl_packHalf2x16 packHalf2x16 #define xesl_unpackHalf2x16 unpackHalf2x16 #elif XESL_LANGUAGE_HLSL uint xesl_packHalf2x16(xesl_float2 xesl_var_value) { return f32tof16(xesl_var_value.x) | (f32tof16(xesl_var_value.y) << 16u); } xesl_float2 xesl_unpackHalf2x16(uint xesl_var_value) { return f16tof32(xesl_uint_x2(xesl_var_value) >> xesl_uint2(0u, 16u)); } #elif XESL_LANGUAGE_MSL uint xesl_packHalf2x16(xesl_float2 xesl_var_value) { return uint(as_type(half(xesl_var_value.x))) | (uint(as_type(half(xesl_var_value.y))) << 16u); } xesl_float2 xesl_unpackHalf2x16(uint xesl_var_value) { return xesl_float2(as_type(ushort2( xesl_uint_x2(xesl_var_value) >> xesl_uint2(0u, 16u)))); } #else #error xesl_packHalf2x16 not defined for the target language. #endif // XESL_LANGUAGE #endif // XENIA_UI_SHADERS_XESL_XESLI_