Skip to content

Commit 9f3c22f

Browse files
Add bindless materials
1 parent b2be8de commit 9f3c22f

File tree

2 files changed

+155
-49
lines changed

2 files changed

+155
-49
lines changed

attachments/38_ray_tracing.cpp

Lines changed: 142 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ class HelloTriangleApplication {
117117
vk::Extent2D swapChainExtent;
118118
std::vector<vk::raii::ImageView> swapChainImageViews;
119119

120-
vk::raii::DescriptorSetLayout descriptorSetLayout = nullptr;
120+
vk::raii::DescriptorSetLayout descriptorSetLayoutGlobal = nullptr;
121+
vk::raii::DescriptorSetLayout descriptorSetLayoutMaterial = nullptr;
121122
vk::raii::PipelineLayout pipelineLayout = nullptr;
122123
vk::raii::Pipeline graphicsPipeline = nullptr;
123124

@@ -153,7 +154,8 @@ class HelloTriangleApplication {
153154
std::vector<tinyobj::material_t> materials;
154155

155156
vk::raii::DescriptorPool descriptorPool = nullptr;
156-
std::vector<vk::raii::DescriptorSet> descriptorSets;
157+
std::vector<vk::raii::DescriptorSet> globalDescriptorSets;
158+
std::vector<vk::raii::DescriptorSet> materialDescriptorSets;
157159

158160
vk::raii::CommandPool commandPool = nullptr;
159161
std::vector<vk::raii::CommandBuffer> commandBuffers;
@@ -197,12 +199,12 @@ class HelloTriangleApplication {
197199
createLogicalDevice();
198200
createSwapChain();
199201
createImageViews();
202+
createCommandPool();
203+
loadModel();
200204
createDescriptorSetLayout();
201205
createGraphicsPipeline();
202-
createCommandPool();
203206
createDepthResources();
204207
createTextureSampler();
205-
loadModel();
206208
createVertexBuffer();
207209
createIndexBuffer();
208210
createUniformBuffers();
@@ -343,10 +345,18 @@ class HelloTriangleApplication {
343345
{ return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } );
344346
} );
345347

346-
auto features = device.template getFeatures2<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
348+
auto features = device.template getFeatures2<vk::PhysicalDeviceFeatures2,
349+
vk::PhysicalDeviceVulkan12Features,
350+
vk::PhysicalDeviceVulkan13Features,
351+
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
347352
bool supportsRequiredFeatures = features.template get<vk::PhysicalDeviceFeatures2>().features.samplerAnisotropy &&
348353
features.template get<vk::PhysicalDeviceVulkan13Features>().dynamicRendering &&
349-
features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState;
354+
features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState &&
355+
features.template get<vk::PhysicalDeviceVulkan12Features>().descriptorBindingSampledImageUpdateAfterBind &&
356+
features.template get<vk::PhysicalDeviceVulkan12Features>().descriptorBindingPartiallyBound &&
357+
features.template get<vk::PhysicalDeviceVulkan12Features>().descriptorBindingVariableDescriptorCount &&
358+
features.template get<vk::PhysicalDeviceVulkan12Features>().runtimeDescriptorArray &&
359+
features.template get<vk::PhysicalDeviceVulkan12Features>().shaderSampledImageArrayNonUniformIndexing;
350360

351361
return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures;
352362
} );
@@ -409,10 +419,14 @@ class HelloTriangleApplication {
409419
}
410420

411421
// query for Vulkan 1.3 features
412-
vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT> featureChain = {
413-
{.features = {.samplerAnisotropy = true } }, // vk::PhysicalDeviceFeatures2
414-
{.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features
415-
{.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT
422+
vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan12Features,
423+
vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT> featureChain = {
424+
{.features = {.samplerAnisotropy = true } }, // vk::PhysicalDeviceFeatures2
425+
{.shaderSampledImageArrayNonUniformIndexing = true, .descriptorBindingSampledImageUpdateAfterBind = true,
426+
.descriptorBindingPartiallyBound = true, .descriptorBindingVariableDescriptorCount = true,
427+
.runtimeDescriptorArray = true }, // vk::PhysicalDeviceVulkan12Features
428+
{.synchronization2 = true, .dynamicRendering = true }, // vk::PhysicalDeviceVulkan13Features
429+
{.extendedDynamicState = true } // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT
416430
};
417431

418432
// create a Device
@@ -462,13 +476,41 @@ class HelloTriangleApplication {
462476
}
463477

464478
void createDescriptorSetLayout() {
465-
std::array bindings = {
466-
vk::DescriptorSetLayoutBinding( 0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex, nullptr),
467-
vk::DescriptorSetLayoutBinding( 1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment, nullptr)
479+
// Use descriptor set 0 for global data
480+
std::array global_bindings = {
481+
vk::DescriptorSetLayoutBinding( 0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, nullptr),
482+
};
483+
484+
vk::DescriptorSetLayoutCreateInfo globalLayoutInfo{ .bindingCount = static_cast<uint32_t>(global_bindings.size()), .pBindings = global_bindings.data() };
485+
486+
descriptorSetLayoutGlobal = vk::raii::DescriptorSetLayout(device, globalLayoutInfo);
487+
488+
// Use descriptor set 1 for bindless material data
489+
uint32_t textureCount = static_cast<uint32_t>(textureImageViews.size());
490+
491+
std::array material_bindings = {
492+
vk::DescriptorSetLayoutBinding( 0, vk::DescriptorType::eSampler, 1, vk::ShaderStageFlagBits::eFragment, nullptr),
493+
vk::DescriptorSetLayoutBinding( 1, vk::DescriptorType::eSampledImage, static_cast<uint32_t>(textureCount), vk::ShaderStageFlagBits::eFragment, nullptr)
468494
};
469495

470-
vk::DescriptorSetLayoutCreateInfo layoutInfo{ .bindingCount = static_cast<uint32_t>(bindings.size()), .pBindings = bindings.data() };
471-
descriptorSetLayout = vk::raii::DescriptorSetLayout(device, layoutInfo);
496+
std::vector<vk::DescriptorBindingFlags> bindingFlags = {
497+
vk::DescriptorBindingFlagBits::eUpdateAfterBind,
498+
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::eUpdateAfterBind
499+
};
500+
501+
vk::DescriptorSetLayoutBindingFlagsCreateInfo flagsCreateInfo{
502+
.bindingCount = static_cast<uint32_t>(bindingFlags.size()),
503+
.pBindingFlags = bindingFlags.data()
504+
};
505+
506+
vk::DescriptorSetLayoutCreateInfo materialLayoutInfo{
507+
.pNext = &flagsCreateInfo,
508+
.flags = vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool,
509+
.bindingCount = static_cast<uint32_t>(material_bindings.size()),
510+
.pBindings = material_bindings.data(),
511+
};
512+
513+
descriptorSetLayoutMaterial = vk::raii::DescriptorSetLayout(device, materialLayoutInfo);
472514
}
473515

474516
void createGraphicsPipeline() {
@@ -531,13 +573,15 @@ class HelloTriangleApplication {
531573
};
532574
vk::PipelineDynamicStateCreateInfo dynamicState{ .dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()), .pDynamicStates = dynamicStates.data() };
533575

576+
vk::DescriptorSetLayout setLayouts[] = {*descriptorSetLayoutGlobal, *descriptorSetLayoutMaterial};
577+
534578
vk::PushConstantRange pushConstantRange {
535579
.stageFlags = vk::ShaderStageFlagBits::eFragment,
536580
.offset = 0,
537581
.size = sizeof(PushConstant)
538582
};
539583

540-
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{ .setLayoutCount = 1, .pSetLayouts = &*descriptorSetLayout, .pushConstantRangeCount = 1, .pPushConstantRanges = &pushConstantRange };
584+
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{ .setLayoutCount = 2, .pSetLayouts = setLayouts, .pushConstantRangeCount = 1, .pPushConstantRanges = &pushConstantRange };
541585

542586
pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo);
543587

@@ -885,59 +929,109 @@ class HelloTriangleApplication {
885929
void createDescriptorPool() {
886930
std::array poolSize {
887931
vk::DescriptorPoolSize( vk::DescriptorType::eUniformBuffer, MAX_FRAMES_IN_FLIGHT),
888-
vk::DescriptorPoolSize( vk::DescriptorType::eCombinedImageSampler, MAX_FRAMES_IN_FLIGHT)
932+
vk::DescriptorPoolSize( vk::DescriptorType::eSampler, MAX_FRAMES_IN_FLIGHT),
933+
vk::DescriptorPoolSize( vk::DescriptorType::eSampledImage, (uint32_t)materials.size())
889934
};
890935
vk::DescriptorPoolCreateInfo poolInfo{
891-
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
892-
.maxSets = MAX_FRAMES_IN_FLIGHT,
936+
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet |
937+
vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
938+
.maxSets = MAX_FRAMES_IN_FLIGHT + 1, // + 1 for bindless materials
893939
.poolSizeCount = static_cast<uint32_t>(poolSize.size()),
894940
.pPoolSizes = poolSize.data()
895941
};
896942
descriptorPool = vk::raii::DescriptorPool(device, poolInfo);
897943
}
898944

899945
void createDescriptorSets() {
900-
std::vector<vk::DescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
901-
vk::DescriptorSetAllocateInfo allocInfo{
946+
// Global descriptor sets (per frame)
947+
std::vector<vk::DescriptorSetLayout> globalLayouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayoutGlobal);
948+
949+
vk::DescriptorSetAllocateInfo allocInfoGlobal{
902950
.descriptorPool = descriptorPool,
903-
.descriptorSetCount = static_cast<uint32_t>(layouts.size()),
904-
.pSetLayouts = layouts.data()
951+
.descriptorSetCount = static_cast<uint32_t>(globalLayouts.size()),
952+
.pSetLayouts = globalLayouts.data()
905953
};
906954

907-
descriptorSets.clear();
908-
descriptorSets = device.allocateDescriptorSets(allocInfo);
955+
globalDescriptorSets.clear();
956+
globalDescriptorSets = device.allocateDescriptorSets(allocInfoGlobal);
909957

910958
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
959+
// Uniform buffer
911960
vk::DescriptorBufferInfo bufferInfo{
912961
.buffer = uniformBuffers[i],
913962
.offset = 0,
914963
.range = sizeof(UniformBufferObject)
915964
};
965+
966+
vk::WriteDescriptorSet bufferWrite{
967+
.dstSet = globalDescriptorSets[i],
968+
.dstBinding = 0,
969+
.dstArrayElement = 0,
970+
.descriptorCount = 1,
971+
.descriptorType = vk::DescriptorType::eUniformBuffer,
972+
.pBufferInfo = &bufferInfo
973+
};
974+
975+
std::array<vk::WriteDescriptorSet, 1> descriptorWrites{bufferWrite};
976+
977+
device.updateDescriptorSets(descriptorWrites, {});
978+
}
979+
980+
// Material descriptor sets (per material)
981+
std::vector<uint32_t> variableCounts = { static_cast<uint32_t>(textureImageViews.size()) };
982+
vk::DescriptorSetVariableDescriptorCountAllocateInfo variableCountInfo{
983+
.descriptorSetCount = 1,
984+
.pDescriptorCounts = variableCounts.data()
985+
};
986+
987+
std::vector<vk::DescriptorSetLayout> layouts{ *descriptorSetLayoutMaterial };
988+
989+
vk::DescriptorSetAllocateInfo allocInfo {
990+
.pNext = &variableCountInfo,
991+
.descriptorPool = descriptorPool,
992+
.descriptorSetCount = static_cast<uint32_t>(layouts.size()),
993+
.pSetLayouts = layouts.data()
994+
};
995+
996+
materialDescriptorSets = device.allocateDescriptorSets(allocInfo);
997+
998+
// Sampler
999+
vk::DescriptorImageInfo samplerInfo{
1000+
.sampler = textureSampler
1001+
};
1002+
1003+
vk::WriteDescriptorSet samplerWrite{
1004+
.dstSet = materialDescriptorSets[0],
1005+
.dstBinding = 0,
1006+
.dstArrayElement = 0,
1007+
.descriptorCount = 1,
1008+
.descriptorType = vk::DescriptorType::eSampler,
1009+
.pImageInfo = &samplerInfo
1010+
};
1011+
1012+
device.updateDescriptorSets({samplerWrite}, {});
1013+
1014+
// Textures
1015+
std::vector<vk::DescriptorImageInfo> imageInfos;
1016+
imageInfos.reserve(textureImageViews.size());
1017+
for (auto& iv : textureImageViews) {
9161018
vk::DescriptorImageInfo imageInfo{
917-
.sampler = textureSampler,
918-
.imageView = textureImageViews[0],
1019+
.imageView = iv,
9191020
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal
9201021
};
921-
std::array descriptorWrites{
922-
vk::WriteDescriptorSet{
923-
.dstSet = descriptorSets[i],
924-
.dstBinding = 0,
925-
.dstArrayElement = 0,
926-
.descriptorCount = 1,
927-
.descriptorType = vk::DescriptorType::eUniformBuffer,
928-
.pBufferInfo = &bufferInfo
929-
},
930-
vk::WriteDescriptorSet{
931-
.dstSet = descriptorSets[i],
932-
.dstBinding = 1,
933-
.dstArrayElement = 0,
934-
.descriptorCount = 1,
935-
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
936-
.pImageInfo = &imageInfo
937-
}
938-
};
939-
device.updateDescriptorSets(descriptorWrites, {});
1022+
imageInfos.push_back(imageInfo);
9401023
}
1024+
1025+
vk::WriteDescriptorSet materialWrite{
1026+
.dstSet = materialDescriptorSets[0],
1027+
.dstBinding = 1,
1028+
.dstArrayElement = 0,
1029+
.descriptorCount = static_cast<uint32_t>(imageInfos.size()),
1030+
.descriptorType = vk::DescriptorType::eSampledImage,
1031+
.pImageInfo = imageInfos.data()
1032+
};
1033+
1034+
device.updateDescriptorSets({materialWrite}, {});
9411035
}
9421036

9431037
void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::raii::Buffer& buffer, vk::raii::DeviceMemory& bufferMemory) {
@@ -1079,7 +1173,8 @@ class HelloTriangleApplication {
10791173
commandBuffers[currentFrame].setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent));
10801174
commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0});
10811175
commandBuffers[currentFrame].bindIndexBuffer( *indexBuffer, 0, vk::IndexType::eUint32 );
1082-
commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr);
1176+
commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *globalDescriptorSets[currentFrame], nullptr);
1177+
commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, *materialDescriptorSets[0], nullptr);
10831178

10841179
for (auto& sub : submeshes) {
10851180
uint32_t idx = sub.materialID < 0 ? 0u : static_cast<uint32_t>(sub.materialID);

attachments/38_ray_tracing.slang

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct UniformBuffer {
99
float4x4 view;
1010
float4x4 proj;
1111
};
12+
[[vk::binding(0,0)]]
1213
ConstantBuffer<UniformBuffer> ubo;
1314

1415
struct VSOutput
@@ -27,9 +28,19 @@ VSOutput vertMain(VSInput input) {
2728
return output;
2829
}
2930

30-
Sampler2D texture;
31+
[[vk::binding(0,1)]]
32+
SamplerState textureSampler;
33+
34+
[[vk::binding(1,1)]]
35+
Texture2D<float4> textures[];
36+
37+
struct PushConstant {
38+
uint materialIndex;
39+
};
40+
[push_constant]
41+
PushConstant pc;
3142

3243
[shader("fragment")]
3344
float4 fragMain(VSOutput vertIn) : SV_TARGET {
34-
return texture.Sample(vertIn.fragTexCoord);
45+
return textures[pc.materialIndex].Sample(textureSampler, vertIn.fragTexCoord);
3546
}

0 commit comments

Comments
 (0)