Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 116 additions & 53 deletions Graphics/ShaderTools/include/SPIRVShaderResources.hpp

Large diffs are not rendered by default.

204 changes: 175 additions & 29 deletions Graphics/ShaderTools/src/SPIRVShaderResources.cpp

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions Tests/DiligentCoreTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ if(NOT WEBGPU_SUPPORTED)
)
endif()

if(NOT ${DILIGENT_USE_SPIRV_TOOLCHAIN} OR ${DILIGENT_NO_GLSLANG})
list(REMOVE_ITEM SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/src/ShaderTools/SPIRVShaderResourcesTest.cpp
)
endif()

set_source_files_properties(${SHADERS} PROPERTIES VS_TOOL_OVERRIDE "None")

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test for acceleration structures
// GLSL ray gen shader for testing acceleration structure resource reflection
#version 460
#extension GL_EXT_ray_tracing : require

layout(set = 0, binding = 0) uniform accelerationStructureEXT g_AccelStruct;

layout(location = 0) rayPayloadEXT vec4 payload;

void main()
{
// Use traceRayEXT to ensure g_AccelStruct is actually used and not optimized away
// This is the proper way to use acceleration structures in ray gen shaders
const vec2 uv = vec2(gl_LaunchIDEXT.xy + 0.5) / vec2(gl_LaunchSizeEXT.xy);
const vec3 origin = vec3(uv.x, 1.0 - uv.y, -1.0);
const vec3 direction = vec3(0.0, 0.0, 1.0);

payload = vec4(0.0);
traceRayEXT(g_AccelStruct, // acceleration structure (first parameter)
gl_RayFlagsNoneEXT, // ray flags
0xFF, // cullMask
0, // sbtRecordOffset
1, // sbtRecordStride
0, // missIndex
origin, // ray origin
0.01, // ray min range
direction, // ray direction
10.0, // ray max range
0); // payload location
}
30 changes: 30 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test for atomic counters
// GLSL fragment shader for testing atomic counter resource reflection
// Note: Vulkan does not support atomic_uint (AtomicCounter storage class).
// We use a storage buffer with atomic operations to simulate atomic counters.
// However, this will be reflected as RWStorageBuffer, not AtomicCounter.
#version 450

layout(binding = 0) coherent buffer AtomicCounterBuffer
{
uint counter;
} g_AtomicCounter;

layout(location = 0) out vec4 FragColor;

void main()
{
// Increment atomic counter using atomicAdd
// atomicAdd returns the value before the addition
uint counterValue = atomicAdd(g_AtomicCounter.counter, 1u);

// Create a color based on counter value
vec4 color = vec4(
float(counterValue & 0xFFu) / 255.0,
float((counterValue >> 8u) & 0xFFu) / 255.0,
float((counterValue >> 16u) & 0xFFu) / 255.0,
1.0
);

FragColor = color;
}
14 changes: 14 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Test for input attachments (subpass inputs)
// In HLSL, subpass inputs are declared using SubpassInput type with vk::input_attachment_index attribute
[[vk::input_attachment_index(0)]]
[[vk::binding(0)]]
SubpassInput<float4> g_InputAttachment;

float4 main() : SV_Target
{
// Read from input attachment (subpass input)
float4 color = g_InputAttachment.SubpassLoad();

// Process the input color
return color * 2.0;
}
66 changes: 66 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Test for mixed resources to verify all resource types work together

struct BufferData
{
float4 data[4];
};

// Uniform buffer
cbuffer UniformBuff : register(b0)
{
float4x4 g_WorldViewProj;
float4 g_MaterialParams;
};

// Read-only structured buffer
StructuredBuffer<BufferData> ROStorageBuff : register(t0);

// Read-write structured buffer
RWStructuredBuffer<BufferData> RWStorageBuff : register(u0);

// Sampled texture
Texture2D<float4> SampledTex : register(t1);

// Storage texture
RWTexture2D<float4> StorageTex : register(u1);

// Sampler
SamplerState Sampler : register(s0);

// Test for push constants
struct PushConstants_t
{
float2 Offset;
float Time;
uint FrameCount;
};

[[vk::push_constant]]
cbuffer PushConstants
{
PushConstants_t g_PushConstants;
};

float4 main() : SV_Target
{
// Use uniform buffer data
float4 color = g_MaterialParams;

// Read from RO structured buffer
color += ROStorageBuff[0].data[0];

// Write to RW structured buffer
RWStorageBuff[1].data[1] = color * 2.0;

// Sample texture
color += SampledTex.Sample(Sampler, float2(0.5, 0.5));

// Write to storage texture
StorageTex[uint2(0, 0)] = color;

// Use push constant data
color.xy += g_PushConstants.Offset;
color.rgb *= sin(g_PushConstants.Time) * 0.5 + 0.5;

return color;
}
26 changes: 26 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Test for push constants
struct PushConstants_t
{
float4x4 g_MVPMatrix;
float4 g_Color;
float2 g_Offset;
float g_Scale;
uint g_Padding;
};

[[vk::push_constant]]
cbuffer PushConstants
{
PushConstants_t g_PushConstants;
};

float4 main() : SV_Target
{
// Use push constant data through the structure instance
float4 result = g_PushConstants.g_Color * g_PushConstants.g_Scale;

// Apply offset to result (simplified example)
result.xy += g_PushConstants.g_Offset;

return result;
}
43 changes: 43 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Test for storage buffers (structured buffers and byte address buffers)
struct BufferData0
{
float4 data0;
float4 data1;
};

struct BufferData1
{
float4 data0;
float4 data1;
float4 data2;
float4 data3;
};

// Read-only structured buffer
StructuredBuffer<BufferData0> g_ROBuffer : register(t0);

// Read-write structured buffer
RWStructuredBuffer<BufferData1> g_RWBuffer : register(u0);

// Atomic counter buffers
ByteAddressBuffer g_ROAtomicBuffer : register(t1);
RWByteAddressBuffer g_RWAtomicBuffer : register(u1);

float4 main() : SV_Target
{
float4 result = float4(0.0, 0.0, 0.0, 0.0);

// Read from RO buffer
result += g_ROBuffer[0].data0;
result += g_ROBuffer[1].data1;

// Write to RW buffer
g_RWBuffer[0].data0 = result;
g_RWBuffer[1].data1 = result * 2.0;

// Atomic operations
uint atomicValue = g_ROAtomicBuffer.Load(0);
g_RWAtomicBuffer.Store(0, atomicValue + 1);

return result;
}
20 changes: 20 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Test for storage images (read-write textures)
// Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images
RWTexture2D<float4> g_RWImage2D : register(u0);
RWTexture2DArray<float4> g_RWImage2DArray : register(u1);
RWTexture3D<float4> g_RWImage3D : register(u2);

float4 main() : SV_Target
{
// Write to storage images
g_RWImage2D[uint2(0, 0)] = float4(1.0, 0.0, 0.0, 1.0);
g_RWImage2DArray[uint3(0, 0, 0)] = float4(0.0, 1.0, 0.0, 1.0);
g_RWImage3D[uint3(0, 0, 0)] = float4(0.0, 0.0, 1.0, 1.0);

// Read back and combine
float4 color = g_RWImage2D[uint2(0, 0)];
color += g_RWImage2DArray[uint3(0, 0, 0)];
color += g_RWImage3D[uint3(0, 0, 0)];

return color;
}
15 changes: 15 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Test for texel buffers (buffer textures)
Buffer<float4> g_UniformTexelBuffer : register(t0); // Uniform texel buffer (read-only)
RWBuffer<float4> g_StorageTexelBuffer : register(u0); // Storage texel buffer (read-write)

float4 main() : SV_Target
{
// Read from uniform texel buffer
float4 value = g_UniformTexelBuffer[0];

// Write to storage texel buffer
g_StorageTexelBuffer[0] = value * 2.0;

// Read back from storage texel buffer
return g_StorageTexelBuffer[0];
}
30 changes: 30 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test for textures and samplers
Texture2D<float4> g_SampledImage : register(t0); // 2D texture (sampled image)
Texture2DMS<float4> g_SampledImageMS : register(t1); // 2D multisample texture
Texture3D<float4> g_SampledImage3D : register(t2); // 3D texture
TextureCube<float4> g_SampledImageCube : register(t3); // Cubemap texture

SamplerState g_Sampler : register(s0); // Separate sampler
Texture2D<float4> g_SeparateImage : register(t4); // Separate image (used with separate sampler)

// Combined sampler test - when texture and sampler follow the naming convention,
// they should be recognized as SampledImage instead of SeparateImage
Texture2D<float4> g_Texture : register(t5);
SamplerState g_Texture_sampler : register(s1);

float4 main() : SV_Target
{
// Sample textures
float4 color1 = g_SampledImage.Sample(g_Sampler, float2(0.5, 0.5));
float4 color2 = g_SampledImageMS.Load(int2(0, 0), 0); // Texture2DMS uses Load instead of Sample
float4 color3 = g_SampledImage3D.Sample(g_Sampler, float3(0.5, 0.5, 0.5));
float4 color4 = g_SampledImageCube.Sample(g_Sampler, float3(0.0, 1.0, 0.0));

// Sample separate image with separate sampler
float4 color5 = g_SeparateImage.Sample(g_Sampler, float2(0.25, 0.25));

// Sample combined sampler texture
float4 color6 = g_Texture.Sample(g_Texture_sampler, float2(0.5, 0.5));

return color1 + color2 + color3 + color4 + color5 + color6;
}
24 changes: 24 additions & 0 deletions Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Test for uniform buffers (constant buffers)
cbuffer CB0 : register(b0)
{
float4x4 g_WorldViewProj;
};

cbuffer CB1 : register(b1)
{
float4 g_Color;
float3 g_LightDir;
float g_LightIntensity;
float2 g_TexScale;
uint2 g_Padding;
};

cbuffer CB2 : register(b2)
{
float4 g_MaterialParams;
};

float4 main() : SV_Target
{
return g_Color * g_MaterialParams;
}
Loading
Loading