<commit_before>
#ifdef METAL
#    include "RayQueryMtl.fxh"
#endif

#include "Structures.fxh"
#include "Utils.fxh"

// Vulkan and DirectX:
//   Resource indices are not allowed to vary within the wave by default.
//   When dynamic indexing is required, we have to use NonUniformResourceIndex() qualifier to avoid undefined behavior.
// Metal:
//   NonUniformResourceIndex() qualifier is not needed.
#ifndef DXCOMPILER
#    define NonUniformResourceIndex(x) x
#endif

#ifdef METAL
#    define TextureSample(Texture, Sampler, f2Coord, fLevel) Texture.sample(Sampler, f2Coord, level(fLevel))
#    define TextureLoad(Texture, u2Coord)                    Texture.read(u2Coord)
#    define TextureStore(Texture, u2Coord, f4Value)          Texture.write(f4Value, u2Coord)
#    define TextureDimensions(Texture, Dim)                  Dim=uint2(Texture.get_width(), Texture.get_height())

#    define TEXTURE(Name)                const texture2d<float>              Name
#    define TEXTURE_ARRAY(Name, Size)    const array<texture2d<float>, Size> Name
#    define WTEXTURE(Name)               texture2d<float, access::write>     Name
#    define SAMPLER_ARRAY(Name, Size)    const array<sampler, Size>          Name
#    define BUFFER(Name, Type)           const device Type*                  Name
#    define CONSTANT_BUFFER(Name, Type)  constant GlobalConstants&           Name
#else
#    define TextureSample(Texture, Sampler, f2Coord, fLevel) Texture.SampleLevel(Sampler, f2Coord, fLevel)
#    define TextureLoad(Texture, u2Coord)                    Texture.Load(int3(u2Coord, 0))
#    define TextureStore(Texture, u2Coord, f4Value)          Texture[u2Coord] = f4Value
#    define TextureDimensions(Texture, Dim)                  Texture.GetDimensions(Dim.x, Dim.y)

#    define TEXTURE(Name)                Texture2D<float4>      Name
#    define TEXTURE_ARRAY(Name, Size)    Texture2D<float4>      Name[Size]
#    define WTEXTURE(Name)               RWTexture2D<float4>    Name
#    define SAMPLER_ARRAY(Name, Size)    SamplerState           Name[Size]
#    define BUFFER(Name, Type)           StructuredBuffer<Type> Name
#    define CONSTANT_BUFFER(Name, Type)  ConstantBuffer<Type>   Name
#endif

// Returns 0 when occluder is found, and 1 otherwise
float CastShadow(float3 Origin, float3 RayDir, float MaxRayLength, RaytracingAccelerationStructure TLAS)
{
    RayDesc ShadowRay;
    ShadowRay.Origin    = Origin;
    ShadowRay.Direction = RayDir;
    ShadowRay.TMin      = 0.0;
    ShadowRay.TMax      = MaxRayLength;

    // Cull front faces to avaid self-intersections.
    // We don't use distance to occluder, so ray query can find any intersection and end search.
    RayQuery<RAY_FLAG_CULL_FRONT_FACING_TRIANGLES | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> ShadowQuery;

    // Setup ray tracing query
    ShadowQuery.TraceRayInline(TLAS,            // Acceleration Structure
                                RAY_FLAG_NONE,  // Ray Flags
                                ~0,             // Instance Inclusion Mask
                                ShadowRay);

    // Find the first intersection.
    // If a scene contains non-opaque objects then Proceed() may return TRUE until all intersections are processed or Abort() is called.
    // This behaviour is not supported by Metal RayQuery emulation, so Proceed() already returns FALSE.
    ShadowQuery.Proceed();
        
    // The scene contains only triangles, so we don't need to check COMMITTED_PROCEDURAL_PRIMITIVE_HIT
    return ShadowQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0.0 : 1.0;
}

struct ReflectionInputAttribs
{
    float3 Origin;
    float3 ReflectionRayDir;
    float  MaxReflectionRayLength;
    float  MaxShadowRayLength;
    float3 CameraPos;
    float3 LightDir;
};
struct ReflectionResult
{
    float4 BaseColor;
    float  NdotL;
    bool   Found;
};
ReflectionResult Reflection(TEXTURE_ARRAY(Textures,      NUM_TEXTURES   ),
                            SAMPLER_ARRAY(Samplers,      NUM_SAMPLERS   ),
                            BUFFER(       VertexBuffer,  Vertex         ),
                            BUFFER(       IndexBuffer,   uint           ),
                            BUFFER(       Objects,       ObjectAttribs  ),
                            BUFFER(       Materials,     MaterialAttribs),
                            RaytracingAccelerationStructure TLAS,
                            ReflectionInputAttribs          In)
{
    RayDesc ReflRay;
    ReflRay.Origin    = In.Origin;
    ReflRay.Direction = In.ReflectionRayDir;
    ReflRay.TMin      = 0.0;
    ReflRay.TMax      = In.MaxReflectionRayLength;
        
    // Rasterization PSO uses back-face culling, so we use the same culling for ray traced reflections.
    RayQuery<RAY_FLAG_CULL_BACK_FACING_TRIANGLES> ReflQuery;
<commit_msg>Added workaround for DXC sampler array bug (microsoft/DirectXShaderCompiler#4666)<commit_after>
#ifdef METAL
#    include "RayQueryMtl.fxh"
#endif

#include "Structures.fxh"
#include "Utils.fxh"

// Vulkan and DirectX:
//   Resource indices are not allowed to vary within the wave by default.
//   When dynamic indexing is required, we have to use NonUniformResourceIndex() qualifier to avoid undefined behavior.
// Metal:
//   NonUniformResourceIndex() qualifier is not needed.
#ifndef DXCOMPILER
#    define NonUniformResourceIndex(x) x
#endif

#ifdef METAL
#    define TextureSample(Texture, Sampler, f2Coord, fLevel) Texture.sample(Sampler, f2Coord, level(fLevel))
#    define TextureLoad(Texture, u2Coord)                    Texture.read(u2Coord)
#    define TextureStore(Texture, u2Coord, f4Value)          Texture.write(f4Value, u2Coord)
#    define TextureDimensions(Texture, Dim)                  Dim=uint2(Texture.get_width(), Texture.get_height())

#    define TEXTURE(Name)                const texture2d<float>              Name
#    define TEXTURE_ARRAY(Name, Size)    const array<texture2d<float>, Size> Name
#    define WTEXTURE(Name)               texture2d<float, access::write>     Name
#    define SAMPLER_ARRAY(Name, Size)    const array<sampler, Size>          Name
#    define BUFFER(Name, Type)           const device Type*                  Name
#    define CONSTANT_BUFFER(Name, Type)  constant GlobalConstants&           Name
#else
#    define TextureSample(Texture, Sampler, f2Coord, fLevel) Texture.SampleLevel(Sampler, f2Coord, fLevel)
#    define TextureLoad(Texture, u2Coord)                    Texture.Load(int3(u2Coord, 0))
#    define TextureStore(Texture, u2Coord, f4Value)          Texture[u2Coord] = f4Value
#    define TextureDimensions(Texture, Dim)                  Texture.GetDimensions(Dim.x, Dim.y)

#    define TEXTURE(Name)                Texture2D<float4>      Name
#    define TEXTURE_ARRAY(Name, Size)    Texture2D<float4>      Name[Size]
#    define WTEXTURE(Name)               RWTexture2D<float4>    Name
#    define SAMPLER_ARRAY(Name, Size)    SamplerState           Name[Size]
#    define BUFFER(Name, Type)           StructuredBuffer<Type> Name
#    define CONSTANT_BUFFER(Name, Type)  ConstantBuffer<Type>   Name
#endif

// Returns 0 when occluder is found, and 1 otherwise
float CastShadow(float3 Origin, float3 RayDir, float MaxRayLength, RaytracingAccelerationStructure TLAS)
{
    RayDesc ShadowRay;
    ShadowRay.Origin    = Origin;
    ShadowRay.Direction = RayDir;
    ShadowRay.TMin      = 0.0;
    ShadowRay.TMax      = MaxRayLength;

    // Cull front faces to avaid self-intersections.
    // We don't use distance to occluder, so ray query can find any intersection and end search.
    RayQuery<RAY_FLAG_CULL_FRONT_FACING_TRIANGLES | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> ShadowQuery;

    // Setup ray tracing query
    ShadowQuery.TraceRayInline(TLAS,            // Acceleration Structure
                                RAY_FLAG_NONE,  // Ray Flags
                                ~0,             // Instance Inclusion Mask
                                ShadowRay);

    // Find the first intersection.
    // If a scene contains non-opaque objects then Proceed() may return TRUE until all intersections are processed or Abort() is called.
    // This behaviour is not supported by Metal RayQuery emulation, so Proceed() already returns FALSE.
    ShadowQuery.Proceed();
        
    // The scene contains only triangles, so we don't need to check COMMITTED_PROCEDURAL_PRIMITIVE_HIT
    return ShadowQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0.0 : 1.0;
}

struct ReflectionInputAttribs
{
    float3 Origin;
    float3 ReflectionRayDir;
    float  MaxReflectionRayLength;
    float  MaxShadowRayLength;
    float3 CameraPos;
    float3 LightDir;
};
struct ReflectionResult
{
    float4 BaseColor;
    float  NdotL;
    bool   Found;
};

#ifdef DXCOMPILER
// Without this struct, DXC fails to compile the shader with the following error:
//
//      error: variable has incomplete type 'SamplerState [2]'
//                SAMPLER_ARRAY(Samplers,      NUM_SAMPLERS   ),
//                              ^
//
// https://github.com/microsoft/DirectXShaderCompiler/issues/4666
struct _DXCBugWorkaround_
{
    SamplerState Samplers[2];
};
#endif

ReflectionResult Reflection(TEXTURE_ARRAY(Textures,      NUM_TEXTURES   ),
                            SAMPLER_ARRAY(Samplers,      NUM_SAMPLERS   ),
                            BUFFER(       VertexBuffer,  Vertex         ),
                            BUFFER(       IndexBuffer,   uint           ),
                            BUFFER(       Objects,       ObjectAttribs  ),
                            BUFFER(       Materials,     MaterialAttribs),
                            RaytracingAccelerationStructure TLAS,
                            ReflectionInputAttribs          In)
{
    RayDesc ReflRay;
    ReflRay.Origin    = In.Origin;
    ReflRay.Direction = In.ReflectionRayDir;
    ReflRay.TMin      = 0.0;
    ReflRay.TMax      = In.MaxReflectionRayLength;
        
    // Rasterization PSO uses back-face culling, so we use the same culling for ray traced reflections.
    RayQuery<RAY_FLAG_CULL_BACK_FACING_TRIANGLES> ReflQuery;

{'fraction_non_alphanumeric': 0.07579073005768848, 'fraction_numerical': 0.010145215834493734, 'mean_word_length': 2.3889450623525446, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7147946', 'n_tokens_mistral': 3020, 'n_tokens_neox': 2883, 'n_words': 761}