Files
Xenia-Canary/src/xenia/ui/shaders/xesl.xesli
2022-06-24 23:24:30 +03:00

1277 lines
58 KiB
Plaintext

/**
******************************************************************************
* 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 <metal_stdlib>
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<value_type> name : register(hlsl_t, hlsl_t_space);
#define xesl_writeTypedStorageBuffer_declare(value_type, name, glsl_set, \
glsl_binding, hlsl_u, \
hlsl_u_space) \
RWBuffer<value_type> 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<const device packed_uint2*>( \
&((name)[size_t(position)])))
#define xesl_uintVectorBufferLoad3(name, position) \
xesl_uint3(*reinterpret_cast<const device packed_uint3*>( \
&((name)[size_t(position)])))
#define xesl_uintVectorBufferLoad4(name, position) \
xesl_uint4(*reinterpret_cast<const device packed_uint4*>( \
&((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<xesl_float4>
#define xesl_utextureBuffer Buffer<xesl_uint4>
#define xesl_texture2D Texture2D<xesl_float4>
#define xesl_texture2DMS Texture2DMS<xesl_float4>
#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<format> 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<float>
#define xesl_utextureBuffer texture_buffer<uint>
#define xesl_texture2D texture2d<float>
#define xesl_texture2DMS texture2d_ms<float>
#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<format, access::write> 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<int>(xesl_var_value);
}
xesl_int2 xesl_floatBitsToInt(xesl_float2 xesl_var_value) {
return as_type<xesl_int2>(xesl_var_value);
}
xesl_int3 xesl_floatBitsToInt(xesl_float3 xesl_var_value) {
return as_type<xesl_int3>(xesl_var_value);
}
xesl_int4 xesl_floatBitsToInt(xesl_float4 xesl_var_value) {
return as_type<xesl_int4>(xesl_var_value);
}
uint xesl_floatBitsToUint(float xesl_var_value) {
return as_type<uint>(xesl_var_value);
}
xesl_uint2 xesl_floatBitsToUint(xesl_float2 xesl_var_value) {
return as_type<xesl_uint2>(xesl_var_value);
}
xesl_uint3 xesl_floatBitsToUint(xesl_float3 xesl_var_value) {
return as_type<xesl_uint3>(xesl_var_value);
}
xesl_uint4 xesl_floatBitsToUint(xesl_float4 xesl_var_value) {
return as_type<xesl_uint4>(xesl_var_value);
}
float xesl_intBitsToFloat(int xesl_var_value) {
return as_type<float>(xesl_var_value);
}
xesl_float2 xesl_intBitsToFloat(xesl_int2 xesl_var_value) {
return as_type<xesl_float2>(xesl_var_value);
}
xesl_float3 xesl_intBitsToFloat(xesl_int3 xesl_var_value) {
return as_type<xesl_float3>(xesl_var_value);
}
xesl_float4 xesl_intBitsToFloat(xesl_int4 xesl_var_value) {
return as_type<xesl_float4>(xesl_var_value);
}
float xesl_uintBitsToFloat(uint xesl_var_value) {
return as_type<float>(xesl_var_value);
}
xesl_float2 xesl_uintBitsToFloat(xesl_uint2 xesl_var_value) {
return as_type<xesl_float2>(xesl_var_value);
}
xesl_float3 xesl_uintBitsToFloat(xesl_uint3 xesl_var_value) {
return as_type<xesl_float3>(xesl_var_value);
}
xesl_float4 xesl_uintBitsToFloat(xesl_uint4 xesl_var_value) {
return as_type<xesl_float4>(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<ushort>(half(xesl_var_value.x))) |
(uint(as_type<ushort>(half(xesl_var_value.y))) << 16u);
}
xesl_float2 xesl_unpackHalf2x16(uint xesl_var_value) {
return xesl_float2(as_type<half2>(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_