vulkan now uses sm6.6 bindless heaps

This commit is contained in:
Turánszki János
2026-01-29 09:14:46 +01:00
parent 0c9d3c7b19
commit fa96c64fe5
4 changed files with 55 additions and 120 deletions
+10 -75
View File
@@ -333,7 +333,7 @@ SamplerComparisonState sampler_cmp_depth : register(s109);
// Direct heap indexing compatibility functions for HLSL6.6+:
// Note: on PS5 this feature is implemented in the preincluded HLSL_to_PSSL.h file
#if defined(__hlsl_dx_compiler) && !defined(__spirv__) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6
#if defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6
template<typename T>
struct BindlessResource
{
@@ -344,9 +344,9 @@ struct BindlessResource<SamplerState>
{
SamplerState operator[](uint index) { return SamplerState(SamplerDescriptorHeap[index]); }
};
#endif // defined(__hlsl_dx_compiler) && !defined(__spirv__) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6
#endif // defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6
#if defined(__PSSL__) || (defined(__hlsl_dx_compiler) && !defined(__spirv__) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
#if defined(__PSSL__) || (defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
static const BindlessResource<SamplerState> bindless_samplers;
static const BindlessResource<Texture2D> bindless_textures;
static const BindlessResource<ByteAddressBuffer> bindless_buffers;
@@ -394,67 +394,12 @@ static const BindlessResource<RWTexture2D<uint2> > bindless_rwtextures_uint2;
static const BindlessResource<RWTexture2D<uint3> > bindless_rwtextures_uint3;
static const BindlessResource<RWTexture2D<uint4> > bindless_rwtextures_uint4;
#ifdef __hlsl_dx_compiler
#ifdef RTAPI
#ifdef __spirv__
[[vk::binding(0, 1)]] RaytracingAccelerationStructure bindless_accelerationstructures[];
#elif defined(__hlsl_dx_compiler)
static const BindlessResource<RaytracingAccelerationStructure> bindless_accelerationstructures;
#endif // __hlsl_dx_compiler
#elif defined(__spirv__)
// In Vulkan, we can manually overlap descriptor sets to reduce bindings:
// Note that HLSL register space declaration was not working correctly with overlapped spaces,
// But vk::binding works correctly in this case.
// HLSL register space declaration is working well with Vulkan when spaces are not overlapping.
// This layout with two descriptor sets can be implemented onn Vulkan side with mutable descriptors.
static const uint DESCRIPTOR_SET_BINDLESS_SAMPLER = 1;
static const uint DESCRIPTOR_SET_BINDLESS_RESOURCE = 2;
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_SAMPLER)]] SamplerState bindless_samplers[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] ByteAddressBuffer bindless_buffers[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<uint> bindless_buffers_uint[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<uint2> bindless_buffers_uint2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<uint3> bindless_buffers_uint3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<uint4> bindless_buffers_uint4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<float> bindless_buffers_float[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<float2> bindless_buffers_float2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<float3> bindless_buffers_float3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<float4> bindless_buffers_float4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<half> bindless_buffers_half[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<half2> bindless_buffers_half2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<half3> bindless_buffers_half3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Buffer<half4> bindless_buffers_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D bindless_textures[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2DArray bindless_textures2DArray[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2DArray<half4> bindless_textures2DArray_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] TextureCube bindless_cubemaps[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] TextureCube<half4> bindless_cubemaps_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] TextureCubeArray bindless_cubearrays[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture3D bindless_textures3D[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture3D<half4> bindless_textures3D_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D<float> bindless_textures_float[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D<float2> bindless_textures_float2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D<uint> bindless_textures_uint[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D<uint4> bindless_textures_uint4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture2D<half4> bindless_textures_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture1D<half4> bindless_textures1D[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] Texture1D<half4> bindless_textures1D_half4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWByteAddressBuffer bindless_rwbuffers[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<uint> bindless_rwbuffers_uint[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<uint2> bindless_rwbuffers_uint2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<uint3> bindless_rwbuffers_uint3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<uint4> bindless_rwbuffers_uint4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<float> bindless_rwbuffers_float[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<float2> bindless_rwbuffers_float2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<float3> bindless_rwbuffers_float3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWBuffer<float4> bindless_rwbuffers_float4[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2D<float4> bindless_rwtextures[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2DArray<float4> bindless_rwtextures2DArray[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture3D<float4> bindless_rwtextures3D[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2D<uint> bindless_rwtextures_uint[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2D<uint2> bindless_rwtextures_uint2[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2D<uint3> bindless_rwtextures_uint3[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RWTexture2D<uint4> bindless_rwtextures_uint4[];
#ifdef RTAPI
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] RaytracingAccelerationStructure bindless_accelerationstructures[];
#endif // RTAPI
#else
@@ -508,11 +453,11 @@ RWTexture2D<uint2> bindless_rwtextures_uint2[] : register(space113);
RWTexture2D<uint3> bindless_rwtextures_uint3[] : register(space114);
RWTexture2D<uint4> bindless_rwtextures_uint4[] : register(space115);
#endif // __spirv__
#endif // defined(__PSSL__) || (defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
#include "ShaderInterop_Renderer.h"
#if defined(__PSSL__) || (defined(__hlsl_dx_compiler) && !defined(__spirv__) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
#if defined(__PSSL__) || (defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
static const BindlessResource<StructuredBuffer<ShaderMeshInstance> > bindless_structured_meshinstance;
static const BindlessResource<StructuredBuffer<ShaderGeometry> > bindless_structured_geometry;
static const BindlessResource<StructuredBuffer<ShaderMeshlet> > bindless_structured_meshlet;
@@ -522,16 +467,6 @@ static const BindlessResource<StructuredBuffer<ShaderMaterial> > bindless_struct
static const BindlessResource<StructuredBuffer<uint> > bindless_structured_uint;
static const BindlessResource<StructuredBuffer<ShaderTerrainChunk> > bindless_structured_terrain_chunks;
static const BindlessResource<StructuredBuffer<DDGIProbe> > bindless_structured_ddi_probes;
#elif defined(__spirv__)
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderMeshInstance> bindless_structured_meshinstance[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderGeometry> bindless_structured_geometry[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderMeshlet> bindless_structured_meshlet[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderCluster> bindless_structured_cluster[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderClusterBounds> bindless_structured_cluster_bounds[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderMaterial> bindless_structured_material[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<uint> bindless_structured_uint[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<ShaderTerrainChunk> bindless_structured_terrain_chunks[];
[[vk::binding(0, DESCRIPTOR_SET_BINDLESS_RESOURCE)]] StructuredBuffer<DDGIProbe> bindless_structured_ddi_probes[];
#else
StructuredBuffer<ShaderMeshInstance> bindless_structured_meshinstance[] : register(space200);
StructuredBuffer<ShaderGeometry> bindless_structured_geometry[] : register(space201);
@@ -542,7 +477,7 @@ StructuredBuffer<ShaderMaterial> bindless_structured_material[] : register(space
StructuredBuffer<uint> bindless_structured_uint[] : register(space206);
StructuredBuffer<ShaderTerrainChunk> bindless_structured_terrain_chunks[] : register(space207);
StructuredBuffer<DDGIProbe> bindless_structured_ddi_probes[] : register(space208);
#endif // defined(__PSSL__) || (defined(__hlsl_dx_compiler) && !defined(__spirv__) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
#endif // defined(__PSSL__) || (defined(__hlsl_dx_compiler) && __SHADER_TARGET_MAJOR >= 6 && __SHADER_TARGET_MINOR >= 6)
// Note: these are macros, the SPIRV compilation is a LOT slower and uses a LOT more memory when functions return large structs, issue: https://github.com/microsoft/DirectXShaderCompiler/issues/7493
#define GetFrame() (g_xFrame)
+13 -31
View File
@@ -37,17 +37,6 @@ namespace vulkan_internal
static constexpr uint64_t timeout_value = 3'000'000'000ull; // 3 seconds
static constexpr uint64_t dynamic_cbv_maxsize = 64 * 1024;
// These shifts are made so that Vulkan resource bindings slots don't interfere with each other across shader stages:
// These are also defined in wi::shadercompiler.cpp as hard coded compiler arguments for SPIRV, so they need to be the same
enum
{
VULKAN_BINDING_SHIFT_B = 0,
VULKAN_BINDING_SHIFT_T = 1000,
VULKAN_BINDING_SHIFT_U = 2000,
VULKAN_BINDING_SHIFT_S = 3000,
};
// Converters:
constexpr VkFormat _ConvertFormat(Format value)
{
@@ -3222,15 +3211,17 @@ using namespace vulkan_internal;
assert(features_1_2.descriptorBindingStorageTexelBufferUpdateAfterBind == VK_TRUE);
// Note: bindless uniform buffer is not used, don't need to check it
allocationhandler->bindless_samplers.init(this, VK_DESCRIPTOR_TYPE_SAMPLER, std::min(BINDLESS_SAMPLER_CAPACITY, properties_1_2.maxDescriptorSetUpdateAfterBindSampledImages));
descriptor_set_layouts[DESCRIPTOR_SET_BINDLESS_SAMPLER] = allocationhandler->bindless_samplers.descriptorSetLayout;
uint32_t bindless_resource_capacity_real = BINDLESS_RESOURCE_CAPACITY;
bindless_resource_capacity_real = std::min(bindless_resource_capacity_real, properties_1_2.maxDescriptorSetUpdateAfterBindSampledImages);
bindless_resource_capacity_real = std::min(bindless_resource_capacity_real, properties_1_2.maxDescriptorSetUpdateAfterBindStorageImages);
bindless_resource_capacity_real = std::min(bindless_resource_capacity_real, properties_1_2.maxDescriptorSetUpdateAfterBindStorageBuffers);
allocationhandler->bindless_resources.init(this, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, bindless_resource_capacity_real);
descriptor_set_layouts[DESCRIPTOR_SET_BINDLESS_RESOURCE] = allocationhandler->bindless_resources.descriptorSetLayout;
descriptor_heaps[DESCRIPTOR_HEAP_RESOURCE] = allocationhandler->bindless_resources.descriptorSet;
allocationhandler->bindless_samplers.init(this, VK_DESCRIPTOR_TYPE_SAMPLER, std::min(BINDLESS_SAMPLER_CAPACITY, properties_1_2.maxDescriptorSetUpdateAfterBindSampledImages));
descriptor_set_layouts[DESCRIPTOR_SET_BINDLESS_SAMPLER] = allocationhandler->bindless_samplers.descriptorSetLayout;
descriptor_heaps[DESCRIPTOR_HEAP_SAMPLER] = allocationhandler->bindless_samplers.descriptorSet;
}
// Pipeline layouts:
@@ -6391,11 +6382,6 @@ using namespace vulkan_internal;
vulkan_check(vkBeginCommandBuffer(commandlist.GetCommandBuffer(), &beginInfo));
const VkDescriptorSet descriptor_sets[] = {
allocationhandler->bindless_samplers.descriptorSet,
allocationhandler->bindless_resources.descriptorSet,
};
if (queue == QUEUE_GRAPHICS)
{
vkCmdSetRasterizerDiscardEnable(commandlist.GetCommandBuffer(), VK_FALSE);
@@ -6449,8 +6435,8 @@ using namespace vulkan_internal;
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_layout,
1,
arraysize(descriptor_sets),
descriptor_sets,
arraysize(descriptor_heaps),
descriptor_heaps,
0,
nullptr
);
@@ -6460,8 +6446,8 @@ using namespace vulkan_internal;
VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline_layout,
1,
arraysize(descriptor_sets),
descriptor_sets,
arraysize(descriptor_heaps),
descriptor_heaps,
0,
nullptr
);
@@ -6473,8 +6459,8 @@ using namespace vulkan_internal;
VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline_layout,
1,
arraysize(descriptor_sets),
descriptor_sets,
arraysize(descriptor_heaps),
descriptor_heaps,
0,
nullptr
);
@@ -8482,17 +8468,13 @@ using namespace vulkan_internal;
vkCmdBindPipeline(commandlist.GetCommandBuffer(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, to_internal(rtpso)->pipeline);
// Note: bind descriptor set for RT here instead of BeginCommandList to not set it needlessly
const VkDescriptorSet descriptor_sets[] = {
allocationhandler->bindless_samplers.descriptorSet,
allocationhandler->bindless_resources.descriptorSet,
};
vkCmdBindDescriptorSets(
commandlist.GetCommandBuffer(),
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
pipeline_layout,
1,
arraysize(descriptor_sets),
descriptor_sets,
arraysize(descriptor_heaps),
descriptor_heaps,
0,
nullptr
);
+23 -7
View File
@@ -37,6 +37,21 @@ namespace wi::graphics
class GraphicsDevice_Vulkan final : public GraphicsDevice
{
friend struct CommandQueue;
public:
enum VULKAN_BINDING_SHIFT
{
VULKAN_BINDING_SHIFT_B = 0,
VULKAN_BINDING_SHIFT_T = 1000,
VULKAN_BINDING_SHIFT_U = 2000,
VULKAN_BINDING_SHIFT_S = 3000,
};
enum DESCRIPTOR_SET
{
DESCRIPTOR_SET_BINDINGS,
DESCRIPTOR_SET_BINDLESS_RESOURCE,
DESCRIPTOR_SET_BINDLESS_SAMPLER,
DESCRIPTOR_SET_COUNT,
};
protected:
VkInstance instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT debugUtilsMessenger = VK_NULL_HANDLE;
@@ -111,15 +126,16 @@ namespace wi::graphics
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
enum DESCRIPTOR_SET
{
DESCRIPTOR_SET_BINDINGS,
DESCRIPTOR_SET_BINDLESS_SAMPLER,
DESCRIPTOR_SET_BINDLESS_RESOURCE,
DESCRIPTOR_SET_COUNT,
};
VkDescriptorSetLayout descriptor_set_layouts[DESCRIPTOR_SET_COUNT] = {};
enum DESCRIPTOR_HEAP
{
DESCRIPTOR_HEAP_RESOURCE,
DESCRIPTOR_HEAP_SAMPLER,
DESCRIPTOR_HEAP_COUNT,
};
VkDescriptorSet descriptor_heaps[DESCRIPTOR_HEAP_COUNT] = {};
uint32_t dynamic_cbv_count = ROOT_CBV_COUNT;
wi::vector<VkDescriptorPoolSize> binding_layout_allocations;
+9 -7
View File
@@ -25,6 +25,7 @@ using namespace Microsoft::WRL;
#ifdef SHADERCOMPILER_ENABLED_DXCOMPILER
#include "Utility/dxc/dxcapi.h"
#include "wiGraphicsDevice_Vulkan.h"
#endif // SHADERCOMPILER_ENABLED_DXCOMPILER
#ifdef SHADERCOMPILER_ENABLED_D3DCOMPILER
@@ -180,10 +181,12 @@ namespace wi::shadercompiler
args.push_back(L"-fspv-target-env=vulkan1.3");
args.push_back(L"-fvk-use-dx-layout");
args.push_back(L"-fvk-use-dx-position-w");
//args.push_back(L"-fvk-b-shift"); args.push_back(L"0"); args.push_back(L"0");
args.push_back(L"-fvk-t-shift"); args.push_back(L"1000"); args.push_back(L"0");
args.push_back(L"-fvk-u-shift"); args.push_back(L"2000"); args.push_back(L"0");
args.push_back(L"-fvk-s-shift"); args.push_back(L"3000"); args.push_back(L"0");
args.push_back(L"-fvk-b-shift"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::VULKAN_BINDING_SHIFT_B)); args.push_back(L"0");
args.push_back(L"-fvk-t-shift"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::VULKAN_BINDING_SHIFT_T)); args.push_back(L"0");
args.push_back(L"-fvk-u-shift"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::VULKAN_BINDING_SHIFT_U)); args.push_back(L"0");
args.push_back(L"-fvk-s-shift"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::VULKAN_BINDING_SHIFT_S)); args.push_back(L"0");
args.push_back(L"-fvk-bind-resource-heap"); args.push_back(L"0"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::DESCRIPTOR_SET_BINDLESS_RESOURCE));
args.push_back(L"-fvk-bind-sampler-heap"); args.push_back(L"0"); args.push_back(std::to_wstring((int)wi::graphics::GraphicsDevice_Vulkan::DESCRIPTOR_SET_BINDLESS_SAMPLER));
break;
case ShaderFormat::METAL:
args.push_back(L"-D"); args.push_back(L"__metal__");
@@ -204,10 +207,9 @@ namespace wi::shadercompiler
args.push_back(L"-enable-16bit-types");
}
if (input.format == ShaderFormat::METAL)
if (input.format == ShaderFormat::SPIRV || input.format == ShaderFormat::METAL)
{
// handling SM6.6 style bindless in Metal API is simpler than unbounded descriptor tables:
minshadermodel = ShaderModel::SM_6_6;
minshadermodel = std::max(minshadermodel, ShaderModel::SM_6_6);
}
args.push_back(L"-T");