refractored descriptor sets to properly handle multiple sets for a given shader

This commit is contained in:
ecker 2026-05-15 14:18:50 -05:00
parent e35806bb04
commit f132f5d6d2
14 changed files with 408 additions and 330 deletions

View File

@ -110,7 +110,8 @@
"invariant": {
"default stage buffers": true,
"default defer buffer destroy": true,
"default command buffer immediate": true,
"default command buffer immediate": false,
"n-buffered uniform": false,
"multithreaded recording": true
},
"pipelines": {
@ -118,9 +119,9 @@
"gui": true,
"vsync": true, // vsync on vulkan side rather than engine-side
"hdr": true,
"vxgi": true, // to-do: fix issues
"vxgi": false, // to-do: fix issues
"culling": false,
"bloom": false,
"bloom": true,
"dof": false,
"rt": false,
"fsr": false,

View File

@ -18,7 +18,7 @@
[ 0, 0, 0, 0 ]
],
"shader": {
"mode": 0,
"mode": 10,
"scalar": 16,
"parameters": [ 0, 0, 0, "time" ]
}

View File

@ -26,33 +26,33 @@ layout (constant_id = 1) const uint CUBEMAPS = 128;
#endif
#if !MULTISAMPLING
layout(binding = 0) uniform utexture2DArray samplerId;
layout(binding = 0, set = 0) uniform utexture2DArray samplerId;
#if BARYCENTRIC
#if !BARYCENTRIC_CALCULATE
layout(binding = 1) uniform texture2DArray samplerBary;
layout(binding = 1, set = 0) uniform texture2DArray samplerBary;
#endif
#else
layout(binding = 1) uniform texture2DArray samplerUv;
layout(binding = 2) uniform texture2DArray samplerNormal;
layout(binding = 1, set = 0) uniform texture2DArray samplerUv;
layout(binding = 2, set = 0) uniform texture2DArray samplerNormal;
#endif
layout(binding = 3) uniform texture2DArray samplerDepth;
layout(binding = 3, set = 0) uniform texture2DArray samplerDepth;
#else
layout(binding = 0) uniform utexture2DMSArray samplerId;
layout(binding = 0, set = 0) uniform utexture2DMSArray samplerId;
#if BARYCENTRIC
#if !BARYCENTRIC_CALCULATE
layout(binding = 1) uniform texture2DMSArray samplerBary;
layout(binding = 1, set = 0) uniform texture2DMSArray samplerBary;
#endif
#else
layout(binding = 1) uniform texture2DMSArray samplerUv;
layout(binding = 2) uniform texture2DMSArray samplerNormal;
layout(binding = 1, set = 0) uniform texture2DMSArray samplerUv;
layout(binding = 2, set = 0) uniform texture2DMSArray samplerNormal;
#endif
layout(binding = 3) uniform texture2DMSArray samplerDepth;
layout(binding = 3, set = 0) uniform texture2DMSArray samplerDepth;
#endif
layout(binding = 7, rgba16f) uniform writeonly image2DArray imageColor;
layout(binding = 8, rgba16f) uniform writeonly image2DArray imageBright;
layout(binding = 9, rg16f) uniform writeonly image2DArray imageMotion;
layout(binding = 7, set = 0, rgba16f) uniform writeonly image2DArray imageColor;
layout(binding = 8, set = 0, rgba16f) uniform writeonly image2DArray imageBright;
layout(binding = 9, set = 0, rg16f) uniform writeonly image2DArray imageMotion;
layout( push_constant ) uniform PushBlock {
uint pass;
@ -61,46 +61,46 @@ layout( push_constant ) uniform PushBlock {
#include "../../../common/structs.h"
layout (binding = 10) uniform Camera {
layout (binding = 10, set = 0) uniform Camera {
Viewport viewport[2];
} camera;
layout (binding = 11) uniform UBO {
layout (binding = 11, set = 0) uniform UBO {
EyeMatrices eyes[2];
Settings settings;
} ubo;
layout (std140, binding = 12) readonly buffer DrawCommands {
layout (std140, binding = 12, set = 0) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 13) readonly buffer Instances {
layout (std140, binding = 13, set = 0) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 14) readonly buffer InstanceAddresseses {
layout (std140, binding = 14, set = 0) readonly buffer InstanceAddresseses {
InstanceAddresses instanceAddresses[];
};
layout (std140, binding = 15) readonly buffer Objects {
layout (std140, binding = 15, set = 0) readonly buffer Objects {
Object objects[];
};
layout (std140, binding = 16) readonly buffer Materials {
layout (std140, binding = 16, set = 0) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 17) readonly buffer Textures {
layout (std140, binding = 17, set = 0) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 18) readonly buffer Lights {
layout (std140, binding = 18, set = 0) readonly buffer Lights {
Light lights[];
};
layout (binding = 19) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 20) uniform samplerCube samplerCubemaps[CUBEMAPS];
layout (binding = 21) uniform sampler3D samplerNoise;
layout (binding = 19, set = 1) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 20, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
layout (binding = 21, set = 0) uniform sampler3D samplerNoise;
#if VXGI
layout (binding = 22) uniform sampler3D voxelOutput[CASCADES];
layout (binding = 22, set = 0) uniform sampler3D voxelOutput[CASCADES];
#endif
#if RT
layout (binding = 23) uniform accelerationStructureEXT tlas;
layout (binding = 23, set = 0) uniform accelerationStructureEXT tlas;
#endif
#if BUFFER_REFERENCE
@ -284,7 +284,7 @@ void directLighting() {
if ( ubo.settings.mode.type == 0x000A ) {
Ray ray;
ray.direction = surface.ray.direction;
ray.origin = surface.ray.origin;
ray.origin = surface.position.world;
ray.origin -= ray.direction;
vec4 radiance = voxelConeTrace( ray, 0 );

View File

@ -20,7 +20,7 @@ namespace ext {
VkPipeline pipeline = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
uf::stl::vector<VkDescriptorSetLayout> descriptorSetLayouts;
GraphicDescriptor descriptor = {};
uf::stl::vector<VkStridedDeviceAddressRegionKHR> sbtEntries;
@ -31,12 +31,12 @@ namespace ext {
void destroy();
};
struct UF_API DescriptorSet : public Buffers {
struct UF_API DescriptorSets : public Buffers {
bool aliased = false;
Device* device = NULL;
VkDescriptorSet descriptorSet = {};
uf::stl::vector<VkDescriptorSet> descriptorSets;
GraphicDescriptor descriptor = {};
struct {
@ -47,7 +47,7 @@ namespace ext {
void initialize( const Graphic& graphic );
void initialize( const Graphic& graphic, const GraphicDescriptor& descriptor );
void update( const Graphic& graphic );
void update( const Graphic& graphic, const GraphicDescriptor& descriptor );
void update( const Graphic& graphic, const GraphicDescriptor& descriptor, const uf::stl::vector<Shader::Metadata::Definition>& = {} );
void record( const Graphic& graphic, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const;
void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const;
void destroy();
@ -94,7 +94,7 @@ namespace ext {
Material material = {};
uf::stl::unordered_map<GraphicDescriptor, Pipeline> pipelines;
uf::stl::unordered_map<GraphicDescriptor, DescriptorSet> descriptorSets;
uf::stl::unordered_map<GraphicDescriptor, DescriptorSets> descriptorSets;
struct {
uf::stl::unordered_map<uf::stl::string, size_t> buffers;
@ -129,12 +129,12 @@ namespace ext {
const Pipeline& getPipeline( const GraphicDescriptor& descriptor ) const;
void initializeDescriptorSet();
DescriptorSet& initializeDescriptorSet( const GraphicDescriptor& descriptor );
DescriptorSets& initializeDescriptorSet( const GraphicDescriptor& descriptor );
bool hasDescriptorSet( const GraphicDescriptor& descriptor ) const;
DescriptorSet& getDescriptorSet();
const DescriptorSet& getDescriptorSet() const;
DescriptorSet& getDescriptorSet( const GraphicDescriptor& descriptor );
const DescriptorSet& getDescriptorSet( const GraphicDescriptor& descriptor ) const;
DescriptorSets& getDescriptorSet();
const DescriptorSets& getDescriptorSet() const;
DescriptorSets& getDescriptorSet( const GraphicDescriptor& descriptor );
const DescriptorSets& getDescriptorSet( const GraphicDescriptor& descriptor ) const;
void record( VkCommandBuffer commandBuffer, size_t pass = 0, size_t draw = 0, size_t offset = 0 ) const;
void record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0, size_t offset = 0 ) const;

View File

@ -29,7 +29,7 @@ namespace ext {
VkShaderModule module = VK_NULL_HANDLE;
VkPipelineShaderStageCreateInfo descriptor = {};
uf::stl::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
uf::stl::map<size_t, uf::stl::vector<VkDescriptorSetLayoutBinding>> descriptorSetLayoutBindings;
uf::stl::vector<VkSpecializationMapEntry> specializationMapEntries;
VkSpecializationInfo specializationInfo = {};
@ -42,48 +42,23 @@ namespace ext {
bool autoInitializeUniformUserdatas = false;
struct Definition {
struct InOut {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
// int32_t buffer = -1;
ext::vulkan::enums::Image::viewType_t type{};
};
struct Texture {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
ext::vulkan::enums::Image::viewType_t type{};
};
struct Uniform {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
// int32_t buffer = -1;
};
struct Storage {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
// int32_t buffer = -1;
};
struct AccelerationStructure {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
// int32_t buffer = -1;
};
struct PushConstant {
uf::stl::string name = "";
uint32_t index = 0;
uint32_t binding = 0;
uint32_t size = 0;
};
uf::stl::string name = "";
uint32_t index = 0;
uint32_t set = 0;
uint32_t binding = 0;
uint32_t size = 0;
// int32_t buffer = -1;
ext::vulkan::enums::Image::viewType_t type{};
};
struct Definitions {
// unused?
typedef Metadata::Definition InOut;
typedef Metadata::Definition Texture;
typedef Metadata::Definition Uniform;
typedef Metadata::Definition Storage;
typedef Metadata::Definition AccelerationStructure;
typedef Metadata::Definition PushConstant;
struct SpecializationConstants {
uf::stl::string name = "";
uint32_t index = 0;
@ -95,9 +70,10 @@ namespace ext {
float f;
} value;
};
uf::stl::unordered_map<size_t, Texture> textures;
uf::stl::unordered_map<uf::stl::string, InOut> inputs;
uf::stl::unordered_map<uf::stl::string, InOut> outputs;
uf::stl::unordered_map<uf::stl::string, Texture> textures;
uf::stl::unordered_map<uf::stl::string, Uniform> uniforms;
uf::stl::unordered_map<uf::stl::string, Storage> storage;
uf::stl::unordered_map<uf::stl::string, AccelerationStructure> accelerationStructure;
@ -179,6 +155,8 @@ namespace ext {
void setSpecializationConstants( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
void setDescriptorCounts( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
Metadata::Definition getDefinition( const uf::stl::string& );
/*
uf::Serializer getUniformJson( const uf::stl::string& name, bool cache = true );
bool updateUniform( const uf::stl::string& name, const ext::json::Value& payload );

View File

@ -22,7 +22,7 @@
#define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers
#define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy
#define VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ext::vulkan::settings::defaultCommandBufferImmediate
#define VK_UBO_USE_N_BUFFERS 1
#define VK_UBO_USE_N_BUFFERS ext::vulkan::settings::nBufferedUbos
#define VK_USE_MULTIVIEW 1
namespace ext {
@ -31,6 +31,7 @@ namespace ext {
extern UF_API bool defaultStageBuffers;
extern UF_API bool defaultDeferBufferDestroy;
extern UF_API bool defaultCommandBufferImmediate;
extern UF_API bool nBufferedUbos;
}
}
}

View File

@ -143,7 +143,7 @@
#define UF_MSG(...) {}
#endif
#if 1
#if 0
#define STATIC_THREAD_LOCAL(T, name) T name;
#else
#define STATIC_THREAD_LOCAL(T, name) static thread_local T name; name.clear();

View File

@ -238,12 +238,13 @@ void UF_API uf::load( ext::json::Value& json ) {
#if UF_USE_VULKAN
uf::renderer::settings::defaultStageBuffers = configRenderInvariantJson["default stage buffers"].as( uf::renderer::settings::defaultStageBuffers );
uf::renderer::settings::defaultDeferBufferDestroy = configRenderInvariantJson["default defer buffer destroy"].as( uf::renderer::settings::defaultDeferBufferDestroy );
#if 1
#if 0
uf::renderer::settings::defaultCommandBufferImmediate = true;
/*global*/::requestDeferredCommandBufferSubmit = !configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
#else
uf::renderer::settings::defaultCommandBufferImmediate = configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
#endif
uf::renderer::settings::nBufferedUbos = configRenderInvariantJson["n-buffered uniform"].as( uf::renderer::settings::nBufferedUbos );
#endif
#if 1
uf::renderer::settings::experimental::dedicatedThread = false;

View File

@ -1273,19 +1273,26 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
for ( uint32_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) {
if ( previousTextures[i] != graphic.material.textures[i].image ) shouldUpdate = true;
}
/*
if ( shouldUpdate ) {
// graphic.updatePipelines();
graphic.update();
renderMode.rebuild = true;
metadata.shader.invalidated = false;
}
*/
if ( !graphic.material.hasShader(shaderType, shaderPipeline) ) {
return;
}
if ( !graphic.material.hasShader(shaderType, shaderPipeline) ) return;
auto& shader = graphic.material.getShader(shaderType, shaderPipeline);
if ( shouldUpdate ) {
auto samplerTexturesDefinition = shader.getDefinition("samplerTextures");
auto samplerCubemapsDefinition = shader.getDefinition("samplerCubemaps");
auto descriptor = graphic.descriptor;
auto& descriptorSets = graphic.getDescriptorSet( descriptor );
descriptorSets.update( graphic, descriptor, { samplerTexturesDefinition, samplerCubemapsDefinition } );
}
if ( !shader.hasUniform("UBO") ) return;
//UF_MSG_DEBUG( "{}: {} {} // {}", uf::string::toString( self ), shaderType, shaderPipeline, uf::string::toString( uf::scene::getCurrentScene() ) );

View File

@ -1961,7 +1961,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
// necessary for OpenGL because recorded descriptors have invalidated pointers
// Vulkan doesn't care about the CPU-side mesh data
#if 1 || UF_USE_OPENGL
#if UF_USE_OPENGL
uf::renderer::states::rebuild = true;
#endif

View File

@ -129,13 +129,11 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB
// assume all UBOs are dynamic
auto totalLength = length;
#if VK_UBO_USE_N_BUFFERS
if ( usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {
if ( VK_UBO_USE_N_BUFFERS && usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {
this->count = ext::vulkan::swapchain.buffers;
this->alignment = device->properties.limits.minUniformBufferOffsetAlignment;
totalLength = ALIGNED_SIZE( length, this->alignment ) * this->count;
}
#endif
VK_CHECK_RESULT(device->createBuffer( nullptr, totalLength, usage, memoryProperties, *this ));
if ( length != totalLength ) this->updateDescriptor( length, 0 );
@ -181,11 +179,9 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length ) const
region.size = length;
region.srcOffset = 0;
region.dstOffset = 0;
#if VK_UBO_USE_N_BUFFERS
if ( this->count == ext::vulkan::swapchain.buffers ) {
if ( VK_UBO_USE_N_BUFFERS && this->count == ext::vulkan::swapchain.buffers ) {
region.dstOffset = this->getOffset( states::currentBuffer );
}
#endif
}
if ( !VK_DEFAULT_STAGE_BUFFERS ) {

View File

@ -60,28 +60,50 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
uf::stl::vector<VkVertexInputBindingDescription> inputBindingDescriptions;
uf::stl::vector<VkVertexInputAttributeDescription> attributeDescriptions;
uf::stl::map<uint32_t, uf::stl::vector<VkDescriptorSetLayoutBinding>> pipelineBindingsBySet;
uf::stl::map<uint32_t, uf::stl::vector<VkDescriptorBindingFlags>> pipelineBindingFlagsBySet;
{
uf::stl::vector<VkDescriptorBindingFlags> bindingFlags;
uint32_t maxSetIndex = 0;
bool hasDynamicBuffer = false;
for ( auto* shader : shaders ) {
for ( auto& binding : shader->descriptorSetLayoutBindings ) {
switch ( binding.descriptorType ) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
hasDynamicBuffer = true;
break;
for ( const auto& [setIndex, bindings] : shader->descriptorSetLayoutBindings ) {
for ( auto& binding : bindings ) {
switch ( binding.descriptorType ) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
hasDynamicBuffer = true;
break;
}
}
}
}
for ( auto* shader : shaders ) {
for ( auto& binding : shader->descriptorSetLayoutBindings ) {
descriptorSetLayoutBindings.emplace_back( binding );
auto& flags = bindingFlags.emplace_back();
for ( const auto& [setIndex, bindings] : shader->descriptorSetLayoutBindings ) {
maxSetIndex = MAX(maxSetIndex, setIndex);
flags |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT;
if ( !hasDynamicBuffer ) flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
auto& pipelineBindings = pipelineBindingsBySet[setIndex];
auto& pipelineFlags = pipelineBindingFlagsBySet[setIndex];
for ( auto& binding : bindings ) {
// Check if we already added this binding (e.g. Vertex and Fragment both use Set 0 Binding 0)
auto it = std::find_if(pipelineBindings.begin(), pipelineBindings.end(),
[&](const VkDescriptorSetLayoutBinding& b) { return b.binding == binding.binding; });
if ( it != pipelineBindings.end() ) {
// Merge stage flags so the single layout knows it's used in both stages
it->stageFlags |= binding.stageFlags;
} else {
// New binding
pipelineBindings.emplace_back( binding );
auto& flags = pipelineFlags.emplace_back();
flags |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT;
if ( !hasDynamicBuffer ) flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
}
}
}
size_t offset = 0;
@ -101,26 +123,35 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
}
}
VkDescriptorSetLayoutBindingFlagsCreateInfo layoutBindingFlags = {};
layoutBindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
layoutBindingFlags.bindingCount = bindingFlags.size();
layoutBindingFlags.pBindingFlags = bindingFlags.data();
descriptorSetLayouts.clear();
descriptorSetLayouts.resize(maxSetIndex + 1, VK_NULL_HANDLE);
VkDescriptorSetLayoutCreateInfo descriptorLayout = ext::vulkan::initializers::descriptorSetLayoutCreateInfo(
descriptorSetLayoutBindings.data(),
descriptorSetLayoutBindings.size()
);
for ( uint32_t set = 0; set <= maxSetIndex; ++set ) {
auto& bindings = pipelineBindingsBySet[set];
auto& bindingFlags = pipelineBindingFlagsBySet[set];
descriptorLayout.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
descriptorLayout.pNext = &layoutBindingFlags;
VkDescriptorSetLayoutBindingFlagsCreateInfo layoutBindingFlags = {};
layoutBindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
layoutBindingFlags.bindingCount = bindingFlags.size();
layoutBindingFlags.pBindingFlags = bindingFlags.data();
VK_CHECK_RESULT(vkCreateDescriptorSetLayout( device, &descriptorLayout, nullptr, &descriptorSetLayout ));
VK_REGISTER_HANDLE( descriptorSetLayout );
VkDescriptorSetLayoutCreateInfo descriptorLayout = ext::vulkan::initializers::descriptorSetLayoutCreateInfo(
bindings.data(),
bindings.size()
);
descriptorLayout.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
descriptorLayout.pNext = &layoutBindingFlags;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout( device, &descriptorLayout, nullptr, &descriptorSetLayouts[set] ));
VK_REGISTER_HANDLE( descriptorSetLayouts[set] );
}
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = ext::vulkan::initializers::pipelineLayoutCreateInfo(
&descriptorSetLayout,
1
descriptorSetLayouts.data(),
descriptorSetLayouts.size()
);
pPipelineLayoutCreateInfo.pushConstantRangeCount = pushConstantRanges.size();
pPipelineLayoutCreateInfo.pPushConstantRanges = pushConstantRanges.data();
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
@ -469,11 +500,13 @@ void ext::vulkan::Pipeline::destroy() {
VK_UNREGISTER_HANDLE( pipeline );
pipeline = VK_NULL_HANDLE;
}
if ( descriptorSetLayout != VK_NULL_HANDLE ) {
vkDestroyDescriptorSetLayout( *device, descriptorSetLayout, nullptr );
VK_UNREGISTER_HANDLE( descriptorSetLayout );
descriptorSetLayout = VK_NULL_HANDLE;
for ( auto descriptorSetLayout : descriptorSetLayouts ) {
if ( descriptorSetLayout != VK_NULL_HANDLE ) {
vkDestroyDescriptorSetLayout( *device, descriptorSetLayout, nullptr );
VK_UNREGISTER_HANDLE( descriptorSetLayout );
}
}
descriptorSetLayouts.clear();
// if ( settings::experimental::dedicatedThread ) ext::vulkan::states::rebuild = true;
/*
@ -484,22 +517,27 @@ void ext::vulkan::Pipeline::destroy() {
*/
}
void ext::vulkan::DescriptorSet::initialize( const Graphic& graphic ) {
void ext::vulkan::DescriptorSets::initialize( const Graphic& graphic ) {
initialize( graphic, graphic.descriptor );
}
void ext::vulkan::DescriptorSet::initialize( const Graphic& graphic, const GraphicDescriptor& descriptor ) {
if ( descriptorSet != VK_NULL_HANDLE ) return;
void ext::vulkan::DescriptorSets::initialize( const Graphic& graphic, const GraphicDescriptor& descriptor ) {
if ( !descriptorSets.empty() ) return;
this->device = graphic.device;
this->descriptor = descriptor;
auto& pipeline = graphic.getPipeline( descriptor );
UF_ASSERT(device->descriptorAllocator.allocate( &descriptorSet, pipeline.descriptorSetLayout ));
descriptorSets.resize(pipeline.descriptorSetLayouts.size());
for( auto i = 0; i < pipeline.descriptorSetLayouts.size(); ++i ) {
if ( pipeline.descriptorSetLayouts[i] == VK_NULL_HANDLE ) continue;
UF_ASSERT(device->descriptorAllocator.allocate( &descriptorSets[i], pipeline.descriptorSetLayouts[i] ));
}
}
void ext::vulkan::DescriptorSet::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
void ext::vulkan::DescriptorSets::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
return record( graphic, descriptor, commandBuffer, pass, draw, offset );
}
void ext::vulkan::DescriptorSet::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
void ext::vulkan::DescriptorSets::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
auto shaders = graphic.material.getShaders( descriptor.pipeline );
auto& pipeline = graphic.getPipeline( descriptor );
@ -530,9 +568,8 @@ void ext::vulkan::DescriptorSet::record( const Graphic& graphic, const GraphicDe
else continue;
}
#if VK_UBO_USE_N_BUFFERS
dynamicOffsets.insert( dynamicOffsets.end(), shader->metadata.dynamicRanges.begin(), shader->metadata.dynamicRanges.end() );
#endif
if ( VK_UBO_USE_N_BUFFERS )
dynamicOffsets.insert( dynamicOffsets.end(), shader->metadata.dynamicRanges.begin(), shader->metadata.dynamicRanges.end() );
}
for ( auto& dynamicOffset : dynamicOffsets ) {
@ -545,22 +582,22 @@ void ext::vulkan::DescriptorSet::record( const Graphic& graphic, const GraphicDe
}
// Bind descriptor sets describing shader binding points
vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipeline.pipelineLayout, 0, 1, &descriptorSet, dynamicOffsets.size(), dynamicOffsets.data());
vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipeline.pipelineLayout, 0, descriptorSets.size(), descriptorSets.data(), dynamicOffsets.size(), dynamicOffsets.data());
}
void ext::vulkan::DescriptorSet::update( const Graphic& graphic ) {
void ext::vulkan::DescriptorSets::update( const Graphic& graphic ) {
return this->update( graphic, descriptor );
}
void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDescriptor& descriptor ) {
void ext::vulkan::DescriptorSets::update( const Graphic& graphic, const GraphicDescriptor& descriptor, const uf::stl::vector<Shader::Metadata::Definition>& filter ) {
//
if ( descriptorSet == VK_NULL_HANDLE ) this->initialize( graphic, descriptor );
if ( descriptorSets.empty() ) this->initialize( graphic, descriptor );
this->descriptor = descriptor;
RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true);
auto& renderTarget = renderMode.getRenderTarget(/*descriptor.renderTarget*/);
auto shaders = graphic.material.getShaders( descriptor.pipeline );
uf::stl::vector<VkWriteDescriptorSet> writeDescriptorSets;
uf::stl::vector<uf::renderer::AccelerationStructure> tlases;
STATIC_THREAD_LOCAL(uf::stl::vector<VkWriteDescriptorSet>, writeDescriptorSets);
struct Infos {
uf::stl::vector<VkDescriptorBufferInfo> uniform;
@ -577,12 +614,15 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
uf::stl::vector<VkDescriptorImageInfo> sampler;
uf::stl::vector<VkDescriptorImageInfo> input;
uf::stl::vector<uf::renderer::AccelerationStructure> tlases;
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> texture_types;
};
uf::stl::vector<Infos> INFOS; INFOS.reserve( shaders.size() );
STATIC_THREAD_LOCAL(uf::stl::vector<Infos>, INFOS);
INFOS.reserve( shaders.size() );
for ( auto* shader : shaders ) {
auto& infos = INFOS.emplace_back();
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> types;
this->collectBuffers( *shader, renderMode, graphic, [&]( const Buffer& buffer ){
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
@ -665,17 +705,22 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
// check if we can even consume that many infos
size_t consumes = 0;
for ( auto& layout : shader->descriptorSetLayoutBindings ) {
switch ( layout.descriptorType ) {
// consume an texture image info
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
consumes += layout.descriptorCount;
ext::vulkan::enums::Image::viewType_t imageType = shader->metadata.definitions.textures.at(layout.binding).type;
types.reserve(consumes);
for ( size_t i = 0; i < layout.descriptorCount; ++i ) types.emplace_back(imageType);
} break;
for ( const auto& [setIndex, bindings] : shader->descriptorSetLayoutBindings ) {
for ( auto& layout : bindings ) {
switch ( layout.descriptorType ) {
// consume an texture image info
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
consumes += layout.descriptorCount;
for ( auto& [ _, def ] : shader->metadata.definitions.textures ) {
if ( def.set != setIndex || def.binding != layout.binding ) continue;
infos.texture_types.reserve(consumes);
for ( size_t i = 0; i < layout.descriptorCount; ++i ) infos.texture_types.emplace_back(def.type);
break;
}
} break;
}
}
}
@ -684,7 +729,7 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
size_t maxTextures3D = 0;
size_t maxTexturesCube = 0;
size_t maxTexturesUnknown = 0;
for ( auto& type : types ) {
for ( auto& type : infos.texture_types ) {
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) ++maxTextures3D;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) ++maxTexturesCube;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) ++maxTextures2D;
@ -699,7 +744,7 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor);
for ( size_t i = infos.image.size(); i < consumes; ++i ) {
ext::vulkan::enums::Image::viewType_t type = i < types.size() ? types[i] : ext::vulkan::enums::Image::viewType_t{};
ext::vulkan::enums::Image::viewType_t type = i < infos.texture_types.size() ? infos.texture_types[i] : ext::vulkan::enums::Image::viewType_t{};
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) infos.image.emplace_back(Texture3D::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) infos.image.emplace_back(TextureCube::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) infos.image.emplace_back(Texture2D::empty.descriptor);
@ -708,18 +753,18 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
if ( !graphic.accelerationStructures.tops.empty() ) {
auto tlas = graphic.accelerationStructures.tops.front();
if ( tlas.handle != VK_NULL_HANDLE ) tlases.emplace_back(tlas);
if ( tlas.handle != VK_NULL_HANDLE ) infos.tlases.emplace_back(tlas);
}
if ( infos.accelerationStructure.empty() ) {
uf::stl::string renderModeName = uf::renderer::hasRenderMode("Compute:RT", true) ? "Compute:RT" : "";
auto& blitter = uf::renderer::getRenderMode(renderModeName, true).getBlitter();
if ( !blitter.accelerationStructures.tops.empty() ) {
tlases.emplace_back(blitter.accelerationStructures.tops.front());
infos.tlases.emplace_back(blitter.accelerationStructures.tops.front());
}
}
for ( auto& tlas : tlases ) {
for ( auto& tlas : infos.tlases ) {
infos.accelerationStructure.emplace_back(tlas.buffer.descriptor);
auto& descriptorAccelerationStructureInfo = infos.accelerationStructureInfos.emplace_back();
@ -743,125 +788,142 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
auto samplerInfo = infos.sampler.begin();
auto inputInfo = infos.input.begin();
for ( auto& layout : shader->descriptorSetLayoutBindings ) {
switch ( layout.descriptorType ) {
// consume an texture image info
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
ext::vulkan::enums::Image::viewType_t imageType = shader->metadata.definitions.textures.at(layout.binding).type;
if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_2D ) {
UF_ASSERT_BREAK_MSG( image2DInfo != infos.image2D.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image2DInfo),
layout.descriptorCount
));
image2DInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_2D_ARRAY ) {
UF_ASSERT_BREAK_MSG( image2DAInfo != infos.image2DA.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image2DAInfo),
layout.descriptorCount
));
image2DAInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) {
UF_ASSERT_BREAK_MSG( imageCubeInfo != infos.imageCube.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*imageCubeInfo),
layout.descriptorCount
));
imageCubeInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_3D ) {
UF_ASSERT_BREAK_MSG( image3DInfo != infos.image3D.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image3DInfo),
layout.descriptorCount
));
image3DInfo += layout.descriptorCount;
} else {
UF_ASSERT_BREAK_MSG( imageUnknownInfo != infos.imageUnknown.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*imageUnknownInfo),
layout.descriptorCount
));
imageUnknownInfo += layout.descriptorCount;
}
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
UF_ASSERT_BREAK_MSG( inputInfo != infos.input.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*inputInfo),
layout.descriptorCount
));
inputInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_SAMPLER: {
UF_ASSERT_BREAK_MSG( samplerInfo != infos.sampler.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*samplerInfo),
layout.descriptorCount
));
samplerInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
UF_ASSERT_BREAK_MSG( uniformBufferInfo != infos.uniform.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*uniformBufferInfo),
layout.descriptorCount
));
uniformBufferInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
UF_ASSERT_BREAK_MSG( storageBufferInfo != infos.storage.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*storageBufferInfo),
layout.descriptorCount
));
storageBufferInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
UF_ASSERT_BREAK_MSG( accelerationStructureInfo != infos.accelerationStructure.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
auto& writeDescriptorSet = writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*accelerationStructureInfo),
layout.descriptorCount
));
writeDescriptorSet.pNext = &(*accelerationStructureInfos);
for ( const auto& [setIndex, bindings] : shader->descriptorSetLayoutBindings ) {
VkDescriptorSet descriptorSet = descriptorSets[setIndex];
UF_ASSERT( descriptorSet != VK_NULL_HANDLE );
accelerationStructureInfo += layout.descriptorCount;
accelerationStructureInfos += layout.descriptorCount;
} break;
for ( auto& layout : bindings ) {
bool shouldWrite = filter.empty() || filter.end() != std::find_if( filter.begin(), filter.end(), [&]( auto d ) {
return d.set == setIndex && d.binding == layout.binding;
});
switch ( layout.descriptorType ) {
// consume an texture image info
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
ext::vulkan::enums::Image::viewType_t imageType = {};
for ( auto& [ _, def ] : shader->metadata.definitions.textures ) {
if ( def.set != setIndex || def.binding != layout.binding ) continue;
imageType = def.type;
break;
}
if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_2D ) {
UF_ASSERT_BREAK_MSG( image2DInfo != infos.image2D.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image2DInfo),
layout.descriptorCount
));
image2DInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_2D_ARRAY ) {
UF_ASSERT_BREAK_MSG( image2DAInfo != infos.image2DA.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image2DAInfo),
layout.descriptorCount
));
image2DAInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) {
UF_ASSERT_BREAK_MSG( imageCubeInfo != infos.imageCube.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*imageCubeInfo),
layout.descriptorCount
));
imageCubeInfo += layout.descriptorCount;
} else if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_3D ) {
UF_ASSERT_BREAK_MSG( image3DInfo != infos.image3D.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*image3DInfo),
layout.descriptorCount
));
image3DInfo += layout.descriptorCount;
} else {
UF_ASSERT_BREAK_MSG( imageUnknownInfo != infos.imageUnknown.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*imageUnknownInfo),
layout.descriptorCount
));
imageUnknownInfo += layout.descriptorCount;
}
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
UF_ASSERT_BREAK_MSG( inputInfo != infos.input.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*inputInfo),
layout.descriptorCount
));
inputInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_SAMPLER: {
UF_ASSERT_BREAK_MSG( samplerInfo != infos.sampler.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*samplerInfo),
layout.descriptorCount
));
samplerInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
UF_ASSERT_BREAK_MSG( uniformBufferInfo != infos.uniform.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*uniformBufferInfo),
layout.descriptorCount
));
uniformBufferInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
UF_ASSERT_BREAK_MSG( storageBufferInfo != infos.storage.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*storageBufferInfo),
layout.descriptorCount
));
storageBufferInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
UF_ASSERT_BREAK_MSG( accelerationStructureInfo != infos.accelerationStructure.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
if ( shouldWrite ) {
auto& writeDescriptorSet = writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&(*accelerationStructureInfo),
layout.descriptorCount
));
writeDescriptorSet.pNext = &(*accelerationStructureInfos);
}
accelerationStructureInfo += layout.descriptorCount;
accelerationStructureInfos += layout.descriptorCount;
} break;
}
}
}
}
@ -883,12 +945,16 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
) {
if ( descriptor.pImageInfo[i].imageView == VK_NULL_HANDLE || descriptor.pImageInfo[i].imageLayout == VK_IMAGE_LAYOUT_UNDEFINED ) {
VK_DEBUG_VALIDATION_MESSAGE("Null image view or layout is undefined, replacing with fallback texture...");
#if 0
auto pointer = const_cast<VkDescriptorImageInfo*>(&descriptor.pImageInfo[i]);
ext::vulkan::enums::Image::viewType_t imageType{};
for ( auto* shader : shaders ) {
if ( shader->metadata.definitions.textures.count(descriptor.dstBinding) == 0 ) continue;
imageType = shader->metadata.definitions.textures.at(descriptor.dstBinding).type;
break;
for ( auto& [ _, def ] : shader->metadata.definitions.textures ) {
// to-do: fix
if ( def.set != descriptor.dstSet || def.binding != descriptor.dstBinding ) continue;
imageType = def.type;
break;
}
}
if ( imageType == ext::vulkan::enums::Image::VIEW_TYPE_3D ) {
*pointer = Texture3D::empty.descriptor;
@ -897,6 +963,7 @@ void ext::vulkan::DescriptorSet::update( const Graphic& graphic, const GraphicDe
} else {
*pointer = Texture2D::empty.descriptor;
}
#endif
}
#if 0
if ( descriptor.pImageInfo[i].layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) {
@ -938,7 +1005,7 @@ PIPELINE_UPDATE_INVALID:
});
return;
}
void ext::vulkan::DescriptorSet::collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const {
void ext::vulkan::DescriptorSets::collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const {
// add aliased-by-name buffers
for ( auto& descriptor : shader.metadata.aliases.buffers ) {
auto matches = uf::string::match(descriptor.name, R"(/^(.+?)\[(\d+)\]$/)");
@ -968,7 +1035,7 @@ void ext::vulkan::DescriptorSet::collectBuffers( const Shader& shader, const Ren
for ( auto& buffer : graphic.buffers ) lambda( buffer );
}
void ext::vulkan::DescriptorSet::destroy() {
void ext::vulkan::DescriptorSets::destroy() {
// no-op
}
@ -1020,11 +1087,13 @@ void ext::vulkan::Material::attachShader( const uf::stl::string& filename, VkSha
}
// check how many samplers requested
/*
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER ) continue;
Sampler& sampler = samplers.emplace_back();
sampler.initialize( *device );
}
*/
uf::stl::string type = "unknown";
switch ( stage ) {
@ -1871,7 +1940,7 @@ bool ext::vulkan::Graphic::hasDescriptorSet( const GraphicDescriptor& descriptor
void ext::vulkan::Graphic::initializeDescriptorSet() {
initializeDescriptorSet( this->descriptor );
}
ext::vulkan::DescriptorSet& ext::vulkan::Graphic::initializeDescriptorSet( const GraphicDescriptor& descriptor ) {
ext::vulkan::DescriptorSets& ext::vulkan::Graphic::initializeDescriptorSet( const GraphicDescriptor& descriptor ) {
auto& pipeline = getPipeline();
auto& descriptorSet = descriptorSets[descriptor];
@ -1884,17 +1953,17 @@ ext::vulkan::DescriptorSet& ext::vulkan::Graphic::initializeDescriptorSet( const
return descriptorSet;
}
ext::vulkan::DescriptorSet& ext::vulkan::Graphic::getDescriptorSet() {
ext::vulkan::DescriptorSets& ext::vulkan::Graphic::getDescriptorSet() {
return getDescriptorSet( descriptor );
}
const ext::vulkan::DescriptorSet& ext::vulkan::Graphic::getDescriptorSet() const {
const ext::vulkan::DescriptorSets& ext::vulkan::Graphic::getDescriptorSet() const {
return getDescriptorSet( descriptor );
}
ext::vulkan::DescriptorSet& ext::vulkan::Graphic::getDescriptorSet( const GraphicDescriptor& descriptor ) {
ext::vulkan::DescriptorSets& ext::vulkan::Graphic::getDescriptorSet( const GraphicDescriptor& descriptor ) {
if ( !hasDescriptorSet(descriptor) ) return initializeDescriptorSet( descriptor );
return descriptorSets[descriptor];
}
const ext::vulkan::DescriptorSet& ext::vulkan::Graphic::getDescriptorSet( const GraphicDescriptor& descriptor ) const {
const ext::vulkan::DescriptorSets& ext::vulkan::Graphic::getDescriptorSet( const GraphicDescriptor& descriptor ) const {
if ( !hasDescriptorSet(descriptor) ) UF_EXCEPTION("does not have descriptor set");
return descriptorSets.at(descriptor);
}

View File

@ -15,7 +15,7 @@
#define VK_DEBUG_VALIDATION_MESSAGE(...)\
//VK_VALIDATION_MESSAGE(__VA_ARGS__);
#define IS_DYNAMIC(name) name == "UBO_d"
#define IS_DYNAMIC(name) true // name == "UBO"
#define UF_SHADER_PARSE_AS_JSON 0
#if UF_SHADER_PARSE_AS_JSON
@ -447,7 +447,9 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType, size_t index ) {
const auto& type = comp.get_type(resource.type_id);
const auto& base_type = comp.get_type(resource.base_type_id);
const size_t binding = comp.get_decoration(resource.id, spv::DecorationBinding);
const auto set = comp.get_decoration(resource.id, spv::DecorationDescriptorSet);
const auto binding = comp.get_decoration(resource.id, spv::DecorationBinding);
const uf::stl::string name = resource.name;
size_t arraySize = 1;
if ( !type.array.empty() ) {
@ -473,17 +475,19 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
#if UF_SHADER_PARSE_AS_JSON
metadata.json["definitions"]["textures"][key]["name"] = name;
metadata.json["definitions"]["textures"][key]["index"] = index;
metadata.json["definitions"]["textures"][key]["set"] = set;
metadata.json["definitions"]["textures"][key]["binding"] = binding;
metadata.json["definitions"]["textures"][key]["size"] = arraySize;
metadata.json["definitions"]["textures"][key]["type"] = tname;
#endif
metadata.definitions.textures[binding] = Shader::Metadata::Definition::Texture{
name,
index,
binding,
arraySize,
etype,
metadata.definitions.textures[name] = Shader::Metadata::Definition/*::Texture*/{
.name = name,
.index = index,
.set = set,
.binding = binding,
.size = arraySize,
.type = etype,
};
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
@ -507,17 +511,19 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
{
metadata.json["definitions"]["uniforms"][name]["name"] = name;
metadata.json["definitions"]["uniforms"][name]["index"] = index;
metadata.json["definitions"]["uniforms"][name]["set"] = set;
metadata.json["definitions"]["uniforms"][name]["binding"] = binding;
metadata.json["definitions"]["uniforms"][name]["size"] = bufferSize;
metadata.json["definitions"]["uniforms"][name]["members"] = parseMembers(resource.type_id);
}
#endif
// generate definition to unordered_map
metadata.definitions.uniforms[name] = Shader::Metadata::Definition::Uniform{
name,
index,
binding,
bufferSize,
metadata.definitions.uniforms[name] = Shader::Metadata::Definition/*::Uniform*/{
.name = name,
.index = index,
.set = set,
.binding = binding,
.size = bufferSize,
};
if ( descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ) {
@ -534,15 +540,17 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
{
metadata.json["definitions"]["storage"][name]["name"] = name;
metadata.json["definitions"]["storage"][name]["index"] = index;
metadata.json["definitions"]["storage"][name]["set"] = set;
metadata.json["definitions"]["storage"][name]["binding"] = binding;
// metadata.json["definitions"]["storage"][name]["size"] = bufferSize;
metadata.json["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id);
}
#endif
metadata.definitions.storage[name] = Shader::Metadata::Definition::Storage{
name,
index,
binding
metadata.definitions.storage[name] = Shader::Metadata::Definition/*::Storage*/{
.name = name,
.index = index,
.set = set,
.binding = binding
};
} break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
@ -551,18 +559,20 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
{
metadata.json["definitions"]["accelerationStructure"][name]["name"] = name;
metadata.json["definitions"]["accelerationStructure"][name]["index"] = index;
metadata.json["definitions"]["accelerationStructure"][name]["set"] = set;
metadata.json["definitions"]["accelerationStructure"][name]["binding"] = binding;
metadata.json["definitions"]["accelerationStructure"][name]["members"] = parseMembers(resource.type_id);
}
#endif
metadata.definitions.accelerationStructure[name] = Shader::Metadata::Definition::AccelerationStructure{
name,
index,
binding
metadata.definitions.accelerationStructure[name] = Shader::Metadata::Definition/*::AccelerationStructure*/{
.name = name,
.index = index,
.set = set,
.binding = binding
};
} break;
}
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, binding, arraySize ) );
descriptorSetLayoutBindings[set].push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, binding, arraySize ) );
};
//for ( const auto& resource : res.key ) {
@ -577,11 +587,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
LOOP_RESOURCES( storage_images, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE );
LOOP_RESOURCES( separate_samplers, VK_DESCRIPTOR_TYPE_SAMPLER );
LOOP_RESOURCES( subpass_inputs, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT );
#if VK_UBO_USE_N_BUFFERS
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC );
#else
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER );
#endif
LOOP_RESOURCES( uniform_buffers, VK_UBO_USE_N_BUFFERS ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER );
LOOP_RESOURCES( storage_buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER );
LOOP_RESOURCES( acceleration_structures, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR );
#undef LOOP_RESOURCES
@ -628,7 +634,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
#endif
// generate definition to unordered_map
{
metadata.definitions.inputs[name] = Shader::Metadata::Definition::InOut{
metadata.definitions.inputs[name] = Shader::Metadata::Definition/*::InOut*/{
name,
i,
binding,
@ -655,7 +661,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
#endif
// generate definition to unordered_map
{
metadata.definitions.outputs[name] = Shader::Metadata::Definition::InOut{
metadata.definitions.outputs[name] = Shader::Metadata::Definition/*::InOut*/{
name,
i,
binding,
@ -699,7 +705,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
#endif
// generate definition to unordered_map
{
metadata.definitions.pushConstants[name] = Shader::Metadata::Definition::PushConstant{
metadata.definitions.pushConstants[name] = Shader::Metadata::Definition/*::PushConstant*/{
name,
pushConstants.size() - 1,
binding,
@ -834,9 +840,11 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
}
// organize layouts
std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){
return l.binding < r.binding;
} );
for ( auto& [setIndex, bindings] : descriptorSetLayoutBindings ) {
std::sort( bindings.begin(), bindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){
return l.binding < r.binding;
} );
}
}
void ext::vulkan::Shader::destroy() {
@ -982,16 +990,32 @@ void ext::vulkan::Shader::setSpecializationConstants( const uf::stl::unordered_m
}
}
void ext::vulkan::Shader::setDescriptorCounts( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values ) {
for ( auto pair : this->metadata.definitions.textures ) {
auto& tx = pair.second;
// to-do: expand for all descriptors, but technically only textures are used for this
for ( auto& [ _, tx ] : this->metadata.definitions.textures ) {
if ( values.count(tx.name) == 0 ) continue;
for ( auto& layout : this->descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
layout.descriptorCount = values.at(tx.name);
for ( auto& [setIndex, bindings] : this->descriptorSetLayoutBindings ) {
for ( auto& layout : bindings ) {
if ( layout.binding != tx.binding ) continue;
layout.descriptorCount = values.at(tx.name);
}
}
}
}
ext::vulkan::Shader::Metadata::Definition ext::vulkan::Shader::getDefinition( const uf::stl::string& name ) {
#define SEARCH_DEFINITION(definition) for ( auto& [ _, def ] : definition ) if ( def.name == name ) return def;
SEARCH_DEFINITION(metadata.definitions.inputs);
SEARCH_DEFINITION(metadata.definitions.outputs);
SEARCH_DEFINITION(metadata.definitions.textures);
SEARCH_DEFINITION(metadata.definitions.uniforms);
SEARCH_DEFINITION(metadata.definitions.storage);
SEARCH_DEFINITION(metadata.definitions.accelerationStructure);
SEARCH_DEFINITION(metadata.definitions.pushConstants);
return {};
}
// JSON shit
#if 0 && UF_SHADER_PARSE_AS_JSON
uf::Serializer ext::vulkan::Shader::getUniformJson( const uf::stl::string& name, bool cache ) {

View File

@ -40,6 +40,7 @@ uint8_t ext::vulkan::settings::msaa = 1;
bool ext::vulkan::settings::defaultStageBuffers = true;
bool ext::vulkan::settings::defaultDeferBufferDestroy = true;
bool ext::vulkan::settings::defaultCommandBufferImmediate = true;
bool ext::vulkan::settings::nBufferedUbos = true;
size_t ext::vulkan::settings::defaultTimeout = UINT64_MAX; // 100000000000;
size_t ext::vulkan::settings::viewCount = 2;