diff --git a/Source/Base/Base/Math/Math.h b/Source/Base/Base/Math/Math.h index 1ccec7cd..939ee744 100644 --- a/Source/Base/Base/Math/Math.h +++ b/Source/Base/Base/Math/Math.h @@ -123,6 +123,16 @@ namespace Math return (a >= b) ? a : b; } + inline u32 Min(u32 a, u32 b) + { + return (a <= b) ? a : b; + } + + inline u32 Max(u32 a, u32 b) + { + return (a >= b) ? a : b; + } + inline size_t Min(size_t a, size_t b) { return (a <= b) ? a : b; @@ -143,6 +153,11 @@ namespace Math return Max(Min(x, max), min); } + inline u32 Clamp(u32 x, u32 min, u32 max) + { + return Max(Min(x, max), min); + } + inline size_t Clamp(size_t x, size_t min, size_t max) { return Max(Min(x, max), min); diff --git a/Source/Base/Base/Memory/Bytebuffer.cpp b/Source/Base/Base/Memory/Bytebuffer.cpp index ad6effdf..86cf8b10 100644 --- a/Source/Base/Base/Memory/Bytebuffer.cpp +++ b/Source/Base/Base/Memory/Bytebuffer.cpp @@ -15,6 +15,7 @@ SharedPool Bytebuffer::_byteBuffer524288; SharedPool Bytebuffer::_byteBuffer1048576; SharedPool Bytebuffer::_byteBuffer8388608; SharedPool Bytebuffer::_byteBuffer16777216; +SharedPool Bytebuffer::_byteBuffer67108864; SharedPool Bytebuffer::_byteBuffer209715200; std::shared_ptr Bytebuffer::BorrowRuntime(size_t size) diff --git a/Source/Base/Base/Memory/Bytebuffer.h b/Source/Base/Base/Memory/Bytebuffer.h index 4afab063..afaadefa 100644 --- a/Source/Base/Base/Memory/Bytebuffer.h +++ b/Source/Base/Base/Memory/Bytebuffer.h @@ -692,6 +692,14 @@ class Bytebuffer return buffer; } + else if constexpr (size <= 67108864) + { + std::shared_ptr buffer = _byteBuffer67108864.acquireOrCreate(nullptr, 67108864); + buffer->size = size; + buffer->Reset(); + + return buffer; + } else if constexpr (size <= 209715200) // This is used for the Data Extractor, largest observed file in WOTLK is 65MB, however in BFA this has been observed to be 150MB { std::shared_ptr buffer = _byteBuffer209715200.acquireOrCreate(nullptr, 209715200); @@ -721,7 +729,8 @@ class Bytebuffer static SharedPool _byteBuffer524288; static SharedPool _byteBuffer1048576; static SharedPool _byteBuffer8388608; - static SharedPool _byteBuffer16777216; + static SharedPool _byteBuffer16777216; + static SharedPool _byteBuffer67108864; static SharedPool _byteBuffer209715200; class RuntimePool diff --git a/Source/Base/Base/Platform.h b/Source/Base/Base/Platform.h index a3d06a71..b734db86 100644 --- a/Source/Base/Base/Platform.h +++ b/Source/Base/Base/Platform.h @@ -68,5 +68,11 @@ static_assert(false, "Please add PRAGMA_ENABLE_OPTIMIZATION/PRAGMA_DISABLE_OPTIM #ifndef strcpy_s #define strcpy_s(dest, count) strcpy((dest), (count)) #endif // strcpy_s -#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(arr[0])) #endif + +#ifndef ARRAY_COUNT +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(arr[0])) +#endif + +#define STATIC_ASSERT_MATCHING_ARRAY(arrA, arrB) static_assert(ARRAY_COUNT(arrA) == ARRAY_COUNT(arrB), "Array count mismatch: " #arrA " and " #arrB) +#define STATIC_ASSERT_MATCHING_ENUM_ARRAY(enumType, arr) static_assert((static_cast(enumType::COUNT) + 1) == ARRAY_COUNT(arr), "Enum and array count mismatch: " #enumType " and " #arr) \ No newline at end of file diff --git a/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.cpp b/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.cpp index ba2886bd..ca50e80d 100644 --- a/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.cpp +++ b/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.cpp @@ -7,6 +7,31 @@ namespace FileFormat { + std::string DescriptorReflection::ToString() const + { + std::string result = "DescriptorReflection: { "; + result += "Binding: " + std::to_string(binding) + ", "; + result += "Name: " + name + ", "; + result += "Type: " + std::string(DescriptorTypeReflectionNames[static_cast(type)]) + ", "; + result += "SubType: " + std::string(DescriptorTypeReflectionNames[static_cast(subType)]) + ", "; + result += "Count: " + std::to_string(count); + result += " }"; + return result; + } + + DescriptorSetReflection& ShaderReflection::GetDescriptorSetBySlot(u32 slot) + { + if (!descriptorSets.contains(slot)) + { + DescriptorSetReflection descriptorSetReflection; + descriptorSetReflection.slot = slot; + + descriptorSets[slot] = descriptorSetReflection; + } + + return descriptorSets[slot]; + } + ShaderRef* ShaderPack::GetShaderRef(std::shared_ptr& buffer, u32 shaderIndex) { if (shaderIndex >= manifest.numShaders) @@ -18,6 +43,79 @@ namespace FileFormat return shaderRef; } + bool ShaderPack::GetShaderReflection(std::shared_ptr& buffer, u32 shaderIndex, ShaderReflection& reflection) + { + ShaderRef* shaderRef = GetShaderRef(buffer, shaderIndex); + if (shaderRef == nullptr || shaderRef->reflectionOffset == 0 || shaderRef->reflectionSize == 0) + return false; + + u64 readOffset = buffer->readData; + + buffer->readData = shaderRef->reflectionOffset; + u8 numDescriptorSets; + if (!buffer->GetU8(numDescriptorSets)) + return false; + + reflection.descriptorSets.reserve(numDescriptorSets); + + for(u32 i = 0; i < numDescriptorSets; i++) + { + u8 setSlot; + u8 numDescriptors; + + if (!buffer->GetU8(setSlot)) + return false; + + if (!buffer->GetU8(numDescriptors)) + return false; + + DescriptorSetReflection& descriptorSet = reflection.descriptorSets[setSlot]; + descriptorSet.slot = setSlot; + descriptorSet.descriptors.reserve(numDescriptors); + + for (u32 j = 0; j < numDescriptors; j++) + { + u8 binding; + std::string name; + u8 type; + u8 subType; + u16 count; + u8 accessType; + bool isUsed; + u32 byteOffset; + u32 byteSize; + + bool failed = false; + failed |= !buffer->GetU8(binding); + failed |= !buffer->GetString(name); + failed |= !buffer->GetU8(type); + failed |= !buffer->GetU8(subType); + failed |= !buffer->GetU16(count); + failed |= !buffer->GetU8(accessType); + failed |= !buffer->Get(isUsed); + failed |= !buffer->GetU32(byteOffset); + failed |= !buffer->GetU32(byteSize); + + if (failed) + return false; + + DescriptorReflection& descriptor = descriptorSet.descriptors[binding]; + descriptor.binding = binding; + descriptor.name = std::move(name); + descriptor.type = static_cast(type); + descriptor.subType = static_cast(subType); + descriptor.count = count; + descriptor.accessType = static_cast(accessType); + descriptor.isUsed = isUsed; + descriptor.byteOffset = byteOffset; + descriptor.byteSize = byteSize; + } + } + + buffer->readData = readOffset; + return true; + } + u8* ShaderPack::GetShaderDataPtr(std::shared_ptr& buffer, u32 shaderOffset) { if (shaderOffset >= buffer->writtenData) @@ -39,12 +137,16 @@ namespace FileFormat manifest.numShaders = static_cast(shaders.size()); NC_ASSERT(shaders.size() > 0, "ShaderPack must have at least one shader"); - // Write the Header and manifest to file - output.write(reinterpret_cast(&header), sizeof(header)); - output.write(reinterpret_cast(&manifest), sizeof(manifest)); + std::shared_ptr buffer = Bytebuffer::Borrow<67108864>(); + + // Write the Header and manifest to buffer + buffer->Put(header); + buffer->Put(manifest); // Write the ShaderRefs to file - u64 dataOffset = static_cast(output.tellp()) + (sizeof(ShaderRef) * manifest.numShaders); + u64 baseShaderRefOffset = buffer->writtenData; + u64 dataOffset = baseShaderRefOffset + (sizeof(ShaderRef) * manifest.numShaders); + ShaderRef shaderRef; for (u32 i = 0; i < shaders.size(); i++) { @@ -52,16 +154,57 @@ namespace FileFormat shaderRef.dataOffset = dataOffset; shaderRef.dataSize = shaders[i].size; - output.write(reinterpret_cast(&shaderRef), sizeof(ShaderRef)); + buffer->Put(shaderRef); dataOffset += shaders[i].size; } // Write the shader blobs to file for (u32 i = 0; i < shaders.size(); i++) { - output.write(reinterpret_cast(shaders[i].data), shaders[i].size); + buffer->PutBytes(shaders[i].data, shaders[i].size); } + // Write the reflection data to file + for (u32 i = 0; i < shaders.size(); i++) + { + u64 reflectionDataStartOffset = static_cast(buffer->writtenData); + + const ShaderInMemory& shader = shaders[i]; + + // Write reflection data + u8 numDescriptorSets = static_cast(shader.reflection.descriptorSets.size()); + buffer->PutU8(numDescriptorSets); + for(const auto& [setSlot, descriptorSet] : shader.reflection.descriptorSets) + { + buffer->PutU8(descriptorSet.slot); + + u8 numDescriptors = static_cast(descriptorSet.descriptors.size()); + buffer->PutU8(numDescriptors); + for (const auto& [binding, descriptor] : descriptorSet.descriptors) + { + buffer->PutU8(descriptor.binding); + buffer->PutString(descriptor.name); + buffer->PutU8(static_cast(descriptor.type)); + buffer->PutU8(static_cast(descriptor.subType)); + buffer->PutU16(descriptor.count); + buffer->PutU8(static_cast(descriptor.accessType)); + buffer->Put(descriptor.isUsed); + buffer->PutU32(descriptor.byteOffset); + buffer->PutU32(descriptor.byteSize); + } + } + + u64 reflectionDataEndOffset = static_cast(buffer->writtenData); + + // Patch ShaderRef with reflection data offset and size + u64 shaderRefOffset = baseShaderRefOffset + (i * sizeof(ShaderRef)); + ShaderRef* shaderRefInBuffer = reinterpret_cast(buffer->GetDataPointer() + shaderRefOffset); + shaderRefInBuffer->reflectionOffset = reflectionDataStartOffset; + shaderRefInBuffer->reflectionSize = static_cast(reflectionDataEndOffset - reflectionDataStartOffset); + } + + output.write(reinterpret_cast(buffer->GetDataPointer()), buffer->writtenData); + output.close(); return true; diff --git a/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.h b/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.h index 3af23b6e..d56a9254 100644 --- a/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.h +++ b/Source/FileFormat/FileFormat/Novus/ShaderPack/ShaderPack.h @@ -5,11 +5,105 @@ #include #include +#include #include namespace FileFormat { static const std::string SHADER_PACK_EXTENSION = ".shaderpack"; + enum class DescriptorTypeReflection : u8 + { + Unknown, + + Array, // If this is the type, we have a subType that tells us what type of array it is + + ByteAddressBuffer, + ConstantBuffer, + SamplerState, + StructuredBuffer, + Texture, + TextureArray, + + COUNT + }; + inline const char* DescriptorTypeReflectionNames[] = + { + "Unknown", + + "Array", + + "ByteAddressBuffer", + "ConstantBuffer", + "SamplerState", + "StructuredBuffer", + "Texture", + "TextureArray", + + "COUNT" + }; + STATIC_ASSERT_MATCHING_ENUM_ARRAY(DescriptorTypeReflection, DescriptorTypeReflectionNames); + + enum class DescriptorAccessTypeReflection : u8 + { + None, + Read, + ReadWrite, + RasterOrdered, + Append, + Consume, + Write, + Feedback, + + COUNT + }; + inline const char* DescriptorAccessTypeReflectionNames[] = + { + "None", + "Read", + "ReadWrite", + "RasterOrdered", + "Append", + "Consume", + "Write", + "ResourceAccessFeedback", + + "COUNT" + }; + STATIC_ASSERT_MATCHING_ENUM_ARRAY(DescriptorAccessTypeReflection, DescriptorAccessTypeReflectionNames); + + struct DescriptorReflection + { + public: + std::string ToString() const; + + public: + u32 binding; + std::string name; + DescriptorTypeReflection type; + DescriptorTypeReflection subType; // For arrays + u32 count; // For arrays + + DescriptorAccessTypeReflection accessType; + bool isUsed; + u32 byteOffset; + u32 byteSize; + }; + + struct DescriptorSetReflection + { + public: + u32 slot; + robin_hood::unordered_map descriptors; + }; + + struct ShaderReflection + { + DescriptorSetReflection& GetDescriptorSetBySlot(u32 slot); + + public: + robin_hood::unordered_map descriptorSets; + }; + struct ShaderPackManifest { public: @@ -30,6 +124,9 @@ namespace FileFormat u64 dataOffset = 0; u32 dataSize = 0; + + u64 reflectionOffset = 0; + u32 reflectionSize = 0; }; struct ShaderInMemory @@ -37,6 +134,8 @@ namespace FileFormat public: u32 permutationNameHash; + ShaderReflection reflection; + u8* data = nullptr; u32 size = 0; }; @@ -50,6 +149,7 @@ namespace FileFormat u32 GetNumShaders() const { return manifest.numShaders; } ShaderRef* GetShaderRef(std::shared_ptr& buffer, u32 shaderIndex); + bool GetShaderReflection(std::shared_ptr& buffer, u32 shaderIndex, ShaderReflection& reflection); u8* GetShaderDataPtr(std::shared_ptr& buffer, u32 shaderIndex); public: diff --git a/Source/Renderer/Renderer/BackendDispatch.cpp b/Source/Renderer/Renderer/BackendDispatch.cpp index 4b8becfe..b977277b 100644 --- a/Source/Renderer/Renderer/BackendDispatch.cpp +++ b/Source/Renderer/Renderer/BackendDispatch.cpp @@ -246,7 +246,7 @@ namespace Renderer { ZoneScopedC(tracy::Color::Red3); const Commands::BindDescriptorSet* actualData = static_cast(data); - renderer->BindDescriptorSet(commandList, actualData->slot, actualData->descriptors, actualData->numDescriptors, actualData->bufferPermissions); + renderer->BindDescriptorSet(commandList, actualData->set, actualData->bufferPermissions); } void BackendDispatch::SetDepthBias(Renderer* renderer, CommandListID commandList, const void* data) diff --git a/Source/Renderer/Renderer/CommandList.cpp b/Source/Renderer/Renderer/CommandList.cpp index 5ba9791b..e52f8fb6 100644 --- a/Source/Renderer/Renderer/CommandList.cpp +++ b/Source/Renderer/Renderer/CommandList.cpp @@ -290,23 +290,13 @@ namespace Renderer Commands::EndTimeQuery::DISPATCH_FUNCTION(_renderer, _immediateCommandList, command); #endif } - - void CommandList::BindDescriptorSet(DescriptorSetSlot slot, DescriptorSetResource resource, u32 frameIndex) + + void CommandList::BindDescriptorSet(DescriptorSetResource resource, u32 frameIndex) { DescriptorSet* descriptorSet = _resources->GetDescriptorSet(resource.GetID()); - const std::vector& descriptors = descriptorSet->GetDescriptors(); - size_t numDescriptors = descriptors.size(); - Commands::BindDescriptorSet* command = AddCommand(); - command->slot = slot; - - // Make a copy of the current state of this DescriptorSets descriptors, this uses our per-frame stack allocator so it's gonna be fast and not leak - command->descriptors = Memory::Allocator::NewArray(_allocator, numDescriptors); - memcpy(command->descriptors, descriptors.data(), sizeof(Descriptor) * numDescriptors); - - command->numDescriptors = static_cast(numDescriptors); - + command->set = descriptorSet; command->bufferPermissions = &_resources->GetBufferPermissions(_currentPassIndex); #if COMMANDLIST_DEBUG_IMMEDIATE_MODE diff --git a/Source/Renderer/Renderer/CommandList.h b/Source/Renderer/Renderer/CommandList.h index a4f126d8..6e7095a9 100644 --- a/Source/Renderer/Renderer/CommandList.h +++ b/Source/Renderer/Renderer/CommandList.h @@ -86,7 +86,7 @@ namespace Renderer void BeginTimeQuery(TimeQueryID timeQueryID); void EndTimeQuery(TimeQueryID timeQueryID); - void BindDescriptorSet(DescriptorSetSlot slot, DescriptorSetResource resource, u32 frameIndex); + void BindDescriptorSet(DescriptorSetResource resource, u32 frameIndex); void SetDepthBias(f32 constantFactor, f32 clamp, f32 slopeFactor); void SetScissorRect(u32 left, u32 right, u32 top, u32 bottom); diff --git a/Source/Renderer/Renderer/Commands/BindDescriptorSet.h b/Source/Renderer/Renderer/Commands/BindDescriptorSet.h index b2f41292..7f528e4d 100644 --- a/Source/Renderer/Renderer/Commands/BindDescriptorSet.h +++ b/Source/Renderer/Renderer/Commands/BindDescriptorSet.h @@ -13,9 +13,7 @@ namespace Renderer { static const BackendDispatchFunction DISPATCH_FUNCTION; - DescriptorSetSlot slot; - Descriptor* descriptors; - u32 numDescriptors; + DescriptorSet* set; const TrackedBufferBitSets* bufferPermissions; }; diff --git a/Source/Renderer/Renderer/DescriptorSet.cpp b/Source/Renderer/Renderer/DescriptorSet.cpp index 558f2040..be1c8a1a 100644 --- a/Source/Renderer/Renderer/DescriptorSet.cpp +++ b/Source/Renderer/Renderer/DescriptorSet.cpp @@ -1,143 +1,240 @@ #include "DescriptorSet.h" -#include "RenderGraphResources.h" +#include "DescriptorType.h" #include "Renderer.h" +#include "RenderGraphResources.h" + +#include namespace Renderer { - void DescriptorSet::RegisterPipeline(Renderer* renderer, ComputePipelineID pipelineID) + void VerifyDescriptorMatch(const FileFormat::DescriptorReflection& a, const FileFormat::DescriptorReflection& b) { - renderer->GetDescriptorMetaFromPipeline(_metaInfo, pipelineID, _slot); + if (a.name != b.name) + { + NC_LOG_CRITICAL("Descriptor name mismatch in combined descriptor set reflection: '{}' != '{}'", a.name, b.name); + } + if (a.type != b.type) + { + NC_LOG_CRITICAL("Descriptor type mismatch in combined descriptor set reflection for descriptor '{}'", a.name); + } + if (a.subType != b.subType) + { + NC_LOG_CRITICAL("Descriptor subType mismatch in combined descriptor set reflection for descriptor '{}'", a.name); + } + if (a.count != b.count) + { + NC_LOG_CRITICAL("Descriptor count mismatch in combined descriptor set reflection for descriptor '{}'", a.name); + } } - void DescriptorSet::RegisterPipeline(Renderer* renderer, GraphicsPipelineID pipelineID) + void DescriptorSet::RegisterPipeline(Renderer* renderer, ComputePipelineID pipelineID) { - renderer->GetDescriptorMetaFromPipeline(_metaInfo, pipelineID, _slot); - } + ZoneScoped; + u32 slotIndex = static_cast(_slot); - void DescriptorSet::Bind(StringUtils::StringHash nameHash, BufferID bufferID) - { - NC_ASSERT(!_locked, "DescriptorSet : Tried to Bind a BufferID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + const ComputePipelineDesc& pipelineDesc = renderer->GetDesc(pipelineID); + const ComputeShaderDesc& shaderDesc = renderer->GetDesc(pipelineDesc.computeShader); + + const FileFormat::ShaderReflection& reflection = shaderDesc.shaderEntry->reflection; - for (u32 i = 0; i < _boundDescriptors.size(); i++) + if (!reflection.descriptorSets.contains(slotIndex)) { - if (nameHash == _boundDescriptors[i].nameHash) + return; + } + + const FileFormat::DescriptorSetReflection& descriptorSet = reflection.descriptorSets.at(slotIndex); + for(const auto& [bindingIndex, descriptor] : descriptorSet.descriptors) + { + if (_combinedReflection.descriptors.contains(bindingIndex)) + { + VerifyDescriptorMatch(_combinedReflection.descriptors[bindingIndex], descriptor); + } + else { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER; - _boundDescriptors[i].bufferID = bufferID; - return; + _combinedReflection.descriptors[bindingIndex] = descriptor; + u32 nameHash = StringUtils::fnv1a_32(descriptor.name.c_str(), descriptor.name.size()); + _nameHashToBindingIndex[nameHash] = bindingIndex; } } - - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER; - boundDescriptor.bufferID = bufferID; } - void DescriptorSet::BindArray(StringUtils::StringHash nameHash, BufferID bufferID, u32 arrayIndex) + void DescriptorSet::RegisterPipeline(Renderer* renderer, GraphicsPipelineID pipelineID) { - NC_ASSERT(!_locked, "DescriptorSet : Tried to BindArray a BufferID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + ZoneScoped; + u32 slotIndex = static_cast(_slot); - for (u32 i = 0; i < _boundDescriptors.size(); i++) + const GraphicsPipelineDesc& pipelineDesc = renderer->GetDesc(pipelineID); + + // Vertex { - if (nameHash == _boundDescriptors[i].nameHash && arrayIndex == _boundDescriptors[i].arrayIndex) + const VertexShaderDesc& shaderDesc = renderer->GetDesc(pipelineDesc.states.vertexShader); + const FileFormat::ShaderReflection& reflection = shaderDesc.shaderEntry->reflection; + if (reflection.descriptorSets.contains(slotIndex)) { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER_ARRAY; - _boundDescriptors[i].bufferID = bufferID; - _boundDescriptors[i].arrayIndex = arrayIndex; - - return; + const FileFormat::DescriptorSetReflection& descriptorSet = reflection.descriptorSets.at(slotIndex); + for (const auto& [bindingIndex, descriptor] : descriptorSet.descriptors) + { + if (_combinedReflection.descriptors.contains(bindingIndex)) + { + VerifyDescriptorMatch(_combinedReflection.descriptors[bindingIndex], descriptor); + } + else + { + _combinedReflection.descriptors[bindingIndex] = descriptor; + u32 nameHash = StringUtils::fnv1a_32(descriptor.name.c_str(), descriptor.name.size()); + _nameHashToBindingIndex[nameHash] = bindingIndex; + } + } + } + } + + // Pixel + if (pipelineDesc.states.pixelShader != PixelShaderID::Invalid()) + { + const PixelShaderDesc& shaderDesc = renderer->GetDesc(pipelineDesc.states.pixelShader); + const FileFormat::ShaderReflection& reflection = shaderDesc.shaderEntry->reflection; + if (reflection.descriptorSets.contains(slotIndex)) + { + const FileFormat::DescriptorSetReflection& descriptorSet = reflection.descriptorSets.at(slotIndex); + for (const auto& [bindingIndex, descriptor] : descriptorSet.descriptors) + { + if (_combinedReflection.descriptors.contains(bindingIndex)) + { + VerifyDescriptorMatch(_combinedReflection.descriptors[bindingIndex], descriptor); + } + else + { + _combinedReflection.descriptors[bindingIndex] = descriptor; + u32 nameHash = StringUtils::fnv1a_32(descriptor.name.c_str(), descriptor.name.size()); + _nameHashToBindingIndex[nameHash] = bindingIndex; + } + } } } + } + + void DescriptorSet::Init(Renderer* renderer) + { + ZoneScoped; + _renderer = renderer; - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER_ARRAY; - boundDescriptor.bufferID = bufferID; - boundDescriptor.arrayIndex = arrayIndex; + DescriptorSetDesc desc; + desc.reflection = &_combinedReflection; + + _descriptorSetID = renderer->CreateDescriptorSet(desc); + _initialized = true; } - void DescriptorSet::Bind(StringUtils::StringHash nameHash, SamplerID samplerID) + void DescriptorSet::Bind(StringUtils::StringHash nameHash, BufferID bufferID, bool optional) { - NC_ASSERT(!_locked, "DescriptorSet : Tried to Bind a SamplerID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + ZoneScoped; + if (!_initialized) + { + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); + } - for (u32 i = 0; i < _boundDescriptors.size(); i++) + if (optional && !HasBinding(nameHash)) { - if (nameHash == _boundDescriptors[i].nameHash) - { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_SAMPLER; - _boundDescriptors[i].samplerID = samplerID; - return; - } + return; } - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_SAMPLER; - boundDescriptor.samplerID = samplerID; + u32 bindingIndex = GetBindingIndex(nameHash); + FileFormat::DescriptorReflection& descriptorReflection = GetDescriptorReflection(bindingIndex); // TODO: Add verification stuff + + u32 frameIndexCount = _renderer->GetFrameIndexCount(); + for(u32 i = 0; i < frameIndexCount; i++) + { + _renderer->BindDescriptor(_descriptorSetID, bindingIndex, bufferID, DescriptorType::StorageBuffer, i); + } } - void DescriptorSet::BindArray(StringUtils::StringHash nameHash, SamplerID samplerID, u32 arrayIndex) + void DescriptorSet::Bind(StringUtils::StringHash nameHash, SamplerID samplerID, bool optional) { - NC_ASSERT(!_locked, "DescriptorSet : Tried to BindArray a SamplerID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + ZoneScoped; + if (!_initialized) + { + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); + } - for (u32 i = 0; i < _boundDescriptors.size(); i++) + if (optional && !HasBinding(nameHash)) { - if (nameHash == _boundDescriptors[i].nameHash && arrayIndex == _boundDescriptors[i].arrayIndex) - { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_SAMPLER_ARRAY; - _boundDescriptors[i].samplerID = samplerID; - _boundDescriptors[i].arrayIndex = arrayIndex; + return; + } - return; - } + u32 bindingIndex = GetBindingIndex(nameHash); + //FileFormat::DescriptorReflection& descriptorReflection = GetDescriptorReflection(bindingIndex); // TODO: Add verification stuff + + u32 frameIndexCount = _renderer->GetFrameIndexCount(); + for (u32 i = 0; i < frameIndexCount; i++) + { + _renderer->BindDescriptor(_descriptorSetID, bindingIndex, samplerID, i); + } + } + + void DescriptorSet::BindArray(StringUtils::StringHash nameHash, SamplerID samplerID, u32 arrayIndex, bool optional) + { + ZoneScoped; + if (!_initialized) + { + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); + } + + if (optional && !HasBinding(nameHash)) + { + return; } - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_SAMPLER_ARRAY; - boundDescriptor.samplerID = samplerID; - boundDescriptor.arrayIndex = arrayIndex; + u32 bindingIndex = GetBindingIndex(nameHash); + //FileFormat::DescriptorReflection& descriptorReflection = GetDescriptorReflection(bindingIndex); // TODO: Add verification stuff + + u32 frameIndexCount = _renderer->GetFrameIndexCount(); + for (u32 i = 0; i < frameIndexCount; i++) + { + _renderer->BindDescriptorArray(_descriptorSetID, bindingIndex, samplerID, arrayIndex, i); + } } - void DescriptorSet::Bind(StringUtils::StringHash nameHash, TextureID textureID) + void DescriptorSet::Bind(StringUtils::StringHash nameHash, TextureArrayID textureArrayID, bool optional) { - NC_ASSERT(!_locked, "DescriptorSet : Tried to Bind a TextureID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + ZoneScoped; + if (!_initialized) + { + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); + } - for (u32 i = 0; i < _boundDescriptors.size(); i++) + if (optional && !HasBinding(nameHash)) { - if (nameHash == _boundDescriptors[i].nameHash) - { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_TEXTURE; - _boundDescriptors[i].textureID = textureID; - return; - } + return; } - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_TEXTURE; - boundDescriptor.textureID = textureID; + u32 bindingIndex = GetBindingIndex(nameHash); + FileFormat::DescriptorReflection& descriptorReflection = GetDescriptorReflection(bindingIndex); // TODO: Add verification stuff + + _renderer->BindDescriptor(_descriptorSetID, bindingIndex, textureArrayID); } - void DescriptorSet::Bind(StringUtils::StringHash nameHash, TextureArrayID textureArrayID) + bool DescriptorSet::HasBinding(StringUtils::StringHash nameHash) const { - NC_ASSERT(!_locked, "DescriptorSet : Tried to Bind a TextureArrayID to a DescriptorSet that is currently in use by a RenderPass. Please use the DescriptorSetResource"); + return _nameHashToBindingIndex.find(nameHash.computedHash) != _nameHashToBindingIndex.end(); + } - for (u32 i = 0; i < _boundDescriptors.size(); i++) + u32 DescriptorSet::GetBindingIndex(StringUtils::StringHash nameHash) const + { + if (!HasBinding(nameHash)) { - if (nameHash == _boundDescriptors[i].nameHash) - { - _boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_TEXTURE_ARRAY; - _boundDescriptors[i].textureArrayID = textureArrayID; + NC_LOG_CRITICAL("DescriptorSet::Bind: Tried to bind to a descriptor namehash '{}' that does not exist in the combined reflection for this DescriptorSet, are you trying to bind to a non existing binding in the shader?", nameHash.computedHash); + } - return; - } + return _nameHashToBindingIndex.at(nameHash.computedHash); + } + + FileFormat::DescriptorReflection& DescriptorSet::GetDescriptorReflection(u32 bindingIndex) + { + if (_combinedReflection.descriptors.find(bindingIndex) == _combinedReflection.descriptors.end()) + { + NC_LOG_CRITICAL("DescriptorSet::GetDescriptorReflection: Tried to get descriptor reflection for binding index '{}' that does not exist in the combined reflection for this DescriptorSet", bindingIndex); } - Descriptor& boundDescriptor = _boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_TEXTURE_ARRAY; - boundDescriptor.textureArrayID = textureArrayID; + return _combinedReflection.descriptors[bindingIndex]; } } \ No newline at end of file diff --git a/Source/Renderer/Renderer/DescriptorSet.h b/Source/Renderer/Renderer/DescriptorSet.h index 9036d2d5..eecc5dc1 100644 --- a/Source/Renderer/Renderer/DescriptorSet.h +++ b/Source/Renderer/Renderer/DescriptorSet.h @@ -4,6 +4,7 @@ #include "Descriptors/BufferDesc.h" #include "Descriptors/ComputePipelineDesc.h" #include "Descriptors/DepthImageDesc.h" +#include "Descriptors/DescriptorSetDesc.h" #include "Descriptors/GraphicsPipelineDesc.h" #include "Descriptors/ImageDesc.h" #include "Descriptors/SamplerDesc.h" @@ -13,50 +14,18 @@ #include #include +#include + namespace Renderer { class Renderer; class RenderGraphResources; - enum DescriptorType - { - DESCRIPTOR_TYPE_BUFFER, - DESCRIPTOR_TYPE_BUFFER_ARRAY, - DESCRIPTOR_TYPE_SAMPLER, - DESCRIPTOR_TYPE_SAMPLER_ARRAY, - DESCRIPTOR_TYPE_TEXTURE, - DESCRIPTOR_TYPE_TEXTURE_ARRAY, - DESCRIPTOR_TYPE_TEXTURE_WRITE, - DESCRIPTOR_TYPE_TEXTURE_READ_WRITE, - DESCRIPTOR_TYPE_IMAGE, - DESCRIPTOR_TYPE_IMAGE_ARRAY, - DESCRIPTOR_TYPE_DEPTH_IMAGE, - DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY, - DESCRIPTOR_TYPE_STORAGE_IMAGE, - DESCRIPTOR_TYPE_STORAGE_IMAGE_ARRAY, - }; - - struct Descriptor - { - u32 nameHash; - u32 imageMipLevel; - u32 count = 1; - u32 arrayIndex = 0; - DescriptorType descriptorType; - - TextureID textureID; - ImageID imageID; - DepthImageID depthImageID; - SamplerID samplerID; - TextureArrayID textureArrayID; - BufferID bufferID; - }; - enum DescriptorSetSlot { - DEBUG, + // 1 indexed because we let 0 be the push constants, it's not technically correct but we get nice error checking if we do this + DEBUG = 1, GLOBAL, - TILES, LIGHT, TERRAIN, MODEL, @@ -70,7 +39,6 @@ namespace Renderer { case DEBUG: return "DEBUG"; case GLOBAL: return "GLOBAL"; - case TILES: return "TILES"; case LIGHT: return "LIGHT"; case TERRAIN: return "TERRAIN"; case MODEL: return "MODEL"; @@ -87,34 +55,45 @@ namespace Renderer public: public: - DescriptorSet(DescriptorSetSlot slot) : _slot(slot) {}; + DescriptorSet(DescriptorSetSlot slot) : _slot(slot) + { + _combinedReflection.slot = static_cast(slot); + }; void RegisterPipeline(Renderer* renderer, ComputePipelineID pipelineID); void RegisterPipeline(Renderer* renderer, GraphicsPipelineID pipelineID); + void Init(Renderer* renderer); + bool IsInitialized() const { return _initialized; } - void Bind(StringUtils::StringHash nameHash, BufferID bufferID); - void BindArray(StringUtils::StringHash nameHash, BufferID bufferID, u32 arrayIndex); - - void Bind(StringUtils::StringHash nameHash, SamplerID samplerID); - void BindArray(StringUtils::StringHash nameHash, SamplerID samplerID, u32 arrayIndex); + void Bind(StringUtils::StringHash nameHash, BufferID bufferID, bool optional = false); - void Bind(StringUtils::StringHash nameHash, TextureID textureID); + void Bind(StringUtils::StringHash nameHash, SamplerID samplerID, bool optional = false); + void BindArray(StringUtils::StringHash nameHash, SamplerID samplerID, u32 arrayIndex, bool optional = false); - void Bind(StringUtils::StringHash nameHash, TextureArrayID textureArrayID); + void Bind(StringUtils::StringHash nameHash, TextureArrayID textureArrayID, bool optional = false); - const std::vector& GetDescriptors() const { return _boundDescriptors; } + DescriptorSetID GetID() const { return _descriptorSetID; } + DescriptorSetSlot GetSlot() const { return _slot; } private: - std::vector& GetMutableDescriptors() { return _boundDescriptors; } + bool HasBinding(StringUtils::StringHash nameHash) const; + u32 GetBindingIndex(StringUtils::StringHash nameHash) const; + FileFormat::DescriptorReflection& GetDescriptorReflection(u32 bindingIndex); void Lock() { _locked = true; } void Unlock() { _locked = false; } private: + Renderer* _renderer = nullptr; + bool _initialized = false; + DescriptorSetSlot _slot; DescriptorMetaInfo _metaInfo; - std::vector _boundDescriptors; + FileFormat::DescriptorSetReflection _combinedReflection; + robin_hood::unordered_map _nameHashToBindingIndex; + DescriptorSetID _descriptorSetID; + bool _locked = false; friend class DescriptorSetResource; diff --git a/Source/Renderer/Renderer/DescriptorSetResource.cpp b/Source/Renderer/Renderer/DescriptorSetResource.cpp index cc8aca61..524eb9dd 100644 --- a/Source/Renderer/Renderer/DescriptorSetResource.cpp +++ b/Source/Renderer/Renderer/DescriptorSetResource.cpp @@ -1,18 +1,21 @@ #include "DescriptorSetResource.h" -#include #include +#include +#include + +#include namespace Renderer { DescriptorSetResource::DescriptorSetResource() - : _id(DescriptorSetID::Invalid()) + : _id(DescriptorSetResourceID::Invalid()) , _renderGraphResources(nullptr) { } - DescriptorSetResource::DescriptorSetResource(DescriptorSetID id, RenderGraphResources& renderGraphResources) + DescriptorSetResource::DescriptorSetResource(DescriptorSetResourceID id, RenderGraphResources& renderGraphResources) : _id(id) , _renderGraphResources(&renderGraphResources) { @@ -21,427 +24,217 @@ namespace Renderer void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, ImageResource resource, u32 mipLevel) const { + ZoneScoped; ImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_IMAGE; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_IMAGE; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; - } - - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, ImageResource resource, u32 mipLevel, u32 arrayIndex) const - { - ImageID imageID = _renderGraphResources->GetImage(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) + // Verify non-mutable access type + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + if (descriptorReflection.accessType != FileFormat::DescriptorAccessTypeReflection::Read) { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_IMAGE_ARRAY; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } + NC_LOG_CRITICAL("DescriptorSetResource::Bind: Tried to bind non-mutable ImageResources to a descriptor namehash '{}' that is not a read-only descriptor", nameHash.computedHash); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_IMAGE_ARRAY; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; - boundDescriptor.arrayIndex = arrayIndex; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, imageID, mipLevel, DescriptorType::SampledImage, frameIndex); } void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel) const { + ZoneScoped; ImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_IMAGE; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_IMAGE; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; + DescriptorSetID descriptorSetID = descriptorSet->GetID(); + + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); + + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + DescriptorType descriptorType = (descriptorReflection.accessType == FileFormat::DescriptorAccessTypeReflection::Read) ? DescriptorType::SampledImage : DescriptorType::StorageImage; + + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, imageID, mipLevel, descriptorType, frameIndex); } - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 arrayIndex) const + void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 mipCount) const { + ZoneScoped; ImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_IMAGE_ARRAY; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_IMAGE_ARRAY; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; - boundDescriptor.arrayIndex = arrayIndex; + DescriptorSetID descriptorSetID = descriptorSet->GetID(); + + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); + + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + DescriptorType descriptorType = (descriptorReflection.accessType == FileFormat::DescriptorAccessTypeReflection::Read) ? DescriptorType::SampledImage : DescriptorType::StorageImage; + + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptorArray(descriptorSetID, bindingIndex, imageID, mipLevel, mipCount, descriptorType, frameIndex); } void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, DepthImageResource resource) const { + ZoneScoped; DepthImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE; - boundDescriptors[i].depthImageID = imageID; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_DEPTH_IMAGE; - boundDescriptor.depthImageID = imageID; - } - - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, DepthImageResource resource, u32 arrayIndex) const - { - DepthImageID imageID = _renderGraphResources->GetImage(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) + // Verify non-mutable access type + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + if (descriptorReflection.accessType != FileFormat::DescriptorAccessTypeReflection::Read) { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY; - boundDescriptors[i].depthImageID = imageID; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } + NC_LOG_CRITICAL("DescriptorSetResource::Bind: Tried to bind non-mutable DepthImageResource to a descriptor namehash '{}' that is not a read-only descriptor", nameHash.computedHash); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY; - boundDescriptor.depthImageID = imageID; - boundDescriptor.arrayIndex = arrayIndex; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, imageID, DescriptorType::SampledImage, frameIndex); } - void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, DepthImageMutableResource resource) const + void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, DepthImageResource resource, u32 arrayIndex) const { + ZoneScoped; DepthImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE; - boundDescriptors[i].depthImageID = imageID; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_DEPTH_IMAGE; - boundDescriptor.depthImageID = imageID; - } + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, DepthImageMutableResource resource, u32 arrayIndex) const - { - DepthImageID imageID = _renderGraphResources->GetImage(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) + // Verify non-mutable access type + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + if (descriptorReflection.accessType != FileFormat::DescriptorAccessTypeReflection::Read) { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY; - boundDescriptors[i].depthImageID = imageID; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } + NC_LOG_CRITICAL("DescriptorSetResource::Bind: Tried to bind non-mutable DepthImageResource to a descriptor namehash '{}' that is not a read-only descriptor", nameHash.computedHash); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY; - boundDescriptor.depthImageID = imageID; - boundDescriptor.arrayIndex = arrayIndex; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptorArray(descriptorSetID, bindingIndex, imageID, arrayIndex, DescriptorType::SampledImage, frameIndex); } - void DescriptorSetResource::BindStorage(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 mipCount) const + void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, DepthImageMutableResource resource, u32 arrayIndex) const { - ImageID imageID = _renderGraphResources->GetImage(resource); + ZoneScoped; + DepthImageID imageID = _renderGraphResources->GetImage(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_STORAGE_IMAGE; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - boundDescriptors[i].count = mipCount; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_STORAGE_IMAGE; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; - boundDescriptor.count = mipCount; - } - - void DescriptorSetResource::BindStorageArray(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 mipCount) const - { - ImageID imageID = _renderGraphResources->GetImage(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) - { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_STORAGE_IMAGE_ARRAY; - boundDescriptors[i].imageID = imageID; - boundDescriptors[i].imageMipLevel = mipLevel; - boundDescriptors[i].count = mipCount; - return; - } - } + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + DescriptorType descriptorType = (descriptorReflection.accessType == FileFormat::DescriptorAccessTypeReflection::Read) ? DescriptorType::SampledImage : DescriptorType::StorageImage; - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_STORAGE_IMAGE_ARRAY; - boundDescriptor.imageID = imageID; - boundDescriptor.imageMipLevel = mipLevel; - boundDescriptor.count = mipCount; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptorArray(descriptorSetID, bindingIndex, imageID, arrayIndex, descriptorType, frameIndex); } void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, BufferResource resource) { + ZoneScoped; BufferID bufferID = _renderGraphResources->GetBuffer(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER; - boundDescriptors[i].bufferID = bufferID; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER; - boundDescriptor.bufferID = bufferID; - } - - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, BufferResource resource, u32 arrayIndex) - { - BufferID bufferID = _renderGraphResources->GetBuffer(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) - { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER_ARRAY; - boundDescriptors[i].bufferID = bufferID; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } - } + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER_ARRAY; - boundDescriptor.bufferID = bufferID; - boundDescriptor.arrayIndex = arrayIndex; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, bufferID, DescriptorType::StorageBuffer, frameIndex); } void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, BufferMutableResource resource) { + ZoneScoped; BufferID bufferID = _renderGraphResources->GetBuffer(resource); DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER; - boundDescriptors[i].bufferID = bufferID; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER; - boundDescriptor.bufferID = bufferID; - } - - void DescriptorSetResource::BindArray(StringUtils::StringHash nameHash, BufferMutableResource resource, u32 arrayIndex) - { - BufferID bufferID = _renderGraphResources->GetBuffer(resource); - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); - for (u32 i = 0; i < boundDescriptors.size(); i++) - { - if (nameHash == boundDescriptors[i].nameHash && arrayIndex == boundDescriptors[i].arrayIndex) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_BUFFER_ARRAY; - boundDescriptors[i].bufferID = bufferID; - boundDescriptors[i].arrayIndex = arrayIndex; - - return; - } - } + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_BUFFER_ARRAY; - boundDescriptor.bufferID = bufferID; - boundDescriptor.arrayIndex = arrayIndex; + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, bufferID, DescriptorType::StorageBuffer, frameIndex); } - void DescriptorSetResource::BindRead(StringUtils::StringHash nameHash, TextureID textureID) + void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel) { + ZoneScoped; DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_TEXTURE; - boundDescriptors[i].textureID = textureID; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_TEXTURE; - boundDescriptor.textureID = textureID; - } + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); - void DescriptorSetResource::BindReadWrite(StringUtils::StringHash nameHash, TextureID textureID) - { - DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); + DescriptorType descriptorType = (descriptorReflection.accessType == FileFormat::DescriptorAccessTypeReflection::Read) ? DescriptorType::SampledImage : DescriptorType::StorageImage; - for (u32 i = 0; i < boundDescriptors.size(); i++) - { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_TEXTURE_READ_WRITE; - boundDescriptors[i].textureID = textureID; - return; - } - } - - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_TEXTURE_READ_WRITE; - boundDescriptor.textureID = textureID; + DescriptorSetID descriptorSetID = descriptorSet->GetID(); + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptor(descriptorSetID, bindingIndex, textureID, mipLevel, descriptorType, frameIndex); } - void DescriptorSetResource::BindWrite(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel, u32 mipCount) + void DescriptorSetResource::Bind(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel, u32 mipCount) { + ZoneScoped; DescriptorSet* descriptorSet = _renderGraphResources->GetDescriptorSet(_id); - - std::vector& boundDescriptors = descriptorSet->GetMutableDescriptors(); - - for (u32 i = 0; i < boundDescriptors.size(); i++) + if (!descriptorSet->_initialized) { - if (nameHash == boundDescriptors[i].nameHash) - { - boundDescriptors[i].descriptorType = DescriptorType::DESCRIPTOR_TYPE_TEXTURE_WRITE; - boundDescriptors[i].textureID = textureID; - boundDescriptors[i].imageMipLevel = mipLevel; - boundDescriptors[i].count = mipCount; - return; - } + NC_LOG_CRITICAL("DescriptorSet : Tried to Bind to a DescriptorSet that has not been initialized yet."); } - Descriptor& boundDescriptor = boundDescriptors.emplace_back(); - boundDescriptor.nameHash = nameHash; - boundDescriptor.descriptorType = DESCRIPTOR_TYPE_TEXTURE_WRITE; - boundDescriptor.textureID = textureID; - boundDescriptor.imageMipLevel = mipLevel; - boundDescriptor.count = mipCount; + u32 bindingIndex = descriptorSet->GetBindingIndex(nameHash.computedHash); + FileFormat::DescriptorReflection& descriptorReflection = descriptorSet->GetDescriptorReflection(bindingIndex); + + DescriptorType descriptorType = (descriptorReflection.accessType == FileFormat::DescriptorAccessTypeReflection::Read) ? DescriptorType::SampledImage : DescriptorType::StorageImage; + + DescriptorSetID descriptorSetID = descriptorSet->GetID(); + u32 frameIndex = descriptorSet->_renderer->GetCurrentFrameIndex(); + descriptorSet->_renderer->BindDescriptorArray(descriptorSetID, bindingIndex, textureID, mipLevel, mipCount, descriptorType, frameIndex); } } \ No newline at end of file diff --git a/Source/Renderer/Renderer/DescriptorSetResource.h b/Source/Renderer/Renderer/DescriptorSetResource.h index 6f69193d..6d436cf4 100644 --- a/Source/Renderer/Renderer/DescriptorSetResource.h +++ b/Source/Renderer/Renderer/DescriptorSetResource.h @@ -11,46 +11,38 @@ namespace Renderer class DescriptorSet; class RenderGraphResources; - STRONG_TYPEDEF(DescriptorSetID, u16); + STRONG_TYPEDEF(DescriptorSetResourceID, u16); class DescriptorSetResource { public: DescriptorSetResource(); - DescriptorSetResource(DescriptorSetID id, RenderGraphResources& renderGraphResources); + DescriptorSetResource(DescriptorSetResourceID id, RenderGraphResources& renderGraphResources); // Image resources void Bind(StringUtils::StringHash nameHash, ImageResource resource, u32 mipLevel = 0) const; - void BindArray(StringUtils::StringHash nameHash, ImageResource resource, u32 mipLevel, u32 arrayIndex) const; void Bind(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel = 0) const; - void BindArray(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 arrayIndex) const; + void Bind(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel, u32 mipCount) const; void Bind(StringUtils::StringHash nameHash, DepthImageResource resource) const; void BindArray(StringUtils::StringHash nameHash, DepthImageResource resource, u32 arrayIndex) const; - void Bind(StringUtils::StringHash nameHash, DepthImageMutableResource resource) const; void BindArray(StringUtils::StringHash nameHash, DepthImageMutableResource resource, u32 arrayIndex) const; - void BindStorage(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel = 0, u32 mipCount = 1) const; - void BindStorageArray(StringUtils::StringHash nameHash, ImageMutableResource resource, u32 mipLevel = 0, u32 mipCount = 1) const; - // Buffer resources void Bind(StringUtils::StringHash nameHash, BufferResource resource); - void BindArray(StringUtils::StringHash nameHash, BufferResource resource, u32 arrayIndex); void Bind(StringUtils::StringHash nameHash, BufferMutableResource resource); - void BindArray(StringUtils::StringHash nameHash, BufferMutableResource resource, u32 arrayIndex); // Texture - void BindRead(StringUtils::StringHash nameHash, TextureID textureID); - void BindReadWrite(StringUtils::StringHash nameHash, TextureID textureID); - void BindWrite(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel = 0, u32 mipCount = 1); + void Bind(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel = 0); + void Bind(StringUtils::StringHash nameHash, TextureID textureID, u32 mipLevel, u32 mipCount); - DescriptorSetID GetID() { return _id; } + DescriptorSetResourceID GetID() { return _id; } private: - DescriptorSetID _id; + DescriptorSetResourceID _id; RenderGraphResources* _renderGraphResources; }; diff --git a/Source/Renderer/Renderer/DescriptorType.h b/Source/Renderer/Renderer/DescriptorType.h new file mode 100644 index 00000000..203482b2 --- /dev/null +++ b/Source/Renderer/Renderer/DescriptorType.h @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace Renderer +{ + enum class DescriptorType : u8 + { + UniformBuffer, + StorageBuffer, + + SampledImage, + StorageImage, // Writeable + }; +} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Descriptors/ComputeShaderDesc.h b/Source/Renderer/Renderer/Descriptors/ComputeShaderDesc.h index 626aadab..d76abebd 100644 --- a/Source/Renderer/Renderer/Descriptors/ComputeShaderDesc.h +++ b/Source/Renderer/Renderer/Descriptors/ComputeShaderDesc.h @@ -10,7 +10,7 @@ namespace Renderer struct ComputeShaderDesc { // Load already in memory - ShaderEntry shaderEntry; + const ShaderEntry* shaderEntry = nullptr; // Load by file void AddPermutationField(const std::string& key, const std::string& value) diff --git a/Source/Renderer/Renderer/Descriptors/DescriptorSetDesc.h b/Source/Renderer/Renderer/Descriptors/DescriptorSetDesc.h new file mode 100644 index 00000000..065a914e --- /dev/null +++ b/Source/Renderer/Renderer/Descriptors/DescriptorSetDesc.h @@ -0,0 +1,17 @@ +#pragma once +#include + +#include + +#include + +namespace Renderer +{ + struct DescriptorSetDesc + { + FileFormat::DescriptorSetReflection* reflection; + }; + + // Lets strong-typedef an ID type with the underlying type of u16 + STRONG_TYPEDEF(DescriptorSetID, u16); +} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Descriptors/ModelDesc.h b/Source/Renderer/Renderer/Descriptors/ModelDesc.h deleted file mode 100644 index ae47e2b0..00000000 --- a/Source/Renderer/Renderer/Descriptors/ModelDesc.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include -#include - -#include - -namespace Renderer -{ - struct Vertex - { - vec3 pos; - vec3 normal; - vec2 texCoord; - }; - - struct ModelDesc - { - std::string path; - }; - - struct PrimitiveModelDesc - { - std::vector vertices; - std::vector indices; - - std::string debugName; - }; - - // Lets strong-typedef an ID type with the underlying type of u16 - STRONG_TYPEDEF(ModelID, u16); - -} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Descriptors/PixelShaderDesc.h b/Source/Renderer/Renderer/Descriptors/PixelShaderDesc.h index afd5b937..bf295099 100644 --- a/Source/Renderer/Renderer/Descriptors/PixelShaderDesc.h +++ b/Source/Renderer/Renderer/Descriptors/PixelShaderDesc.h @@ -10,7 +10,7 @@ namespace Renderer struct PixelShaderDesc { // Load already in memory - ShaderEntry shaderEntry; + const ShaderEntry* shaderEntry = nullptr; // Load by file void AddPermutationField(const std::string& key, const std::string& value) diff --git a/Source/Renderer/Renderer/Descriptors/VertexShaderDesc.h b/Source/Renderer/Renderer/Descriptors/VertexShaderDesc.h index 2f10eec6..fc25580f 100644 --- a/Source/Renderer/Renderer/Descriptors/VertexShaderDesc.h +++ b/Source/Renderer/Renderer/Descriptors/VertexShaderDesc.h @@ -10,7 +10,7 @@ namespace Renderer struct VertexShaderDesc { // Load already in memory - ShaderEntry shaderEntry; + const ShaderEntry* shaderEntry = nullptr; // Load by file void AddPermutationField(const std::string& key, const std::string& value) diff --git a/Source/Renderer/Renderer/RenderGraphBuilder.cpp b/Source/Renderer/Renderer/RenderGraphBuilder.cpp index 0d5cfd5f..fb1cf78a 100644 --- a/Source/Renderer/Renderer/RenderGraphBuilder.cpp +++ b/Source/Renderer/Renderer/RenderGraphBuilder.cpp @@ -64,7 +64,7 @@ namespace Renderer for (ImageMutableResource resource : colorClears) { ImageID imageID = _resources.GetImage(resource); - const ImageDesc& imageDesc = _renderer->GetImageDesc(imageID); + const ImageDesc& imageDesc = _renderer->GetDesc(imageID); ImageComponentType imageComponentType = ToImageComponentType(imageDesc.format); @@ -94,7 +94,7 @@ namespace Renderer { DepthImageID imageID = _resources.GetImage(resource); - const DepthImageDesc& imageDesc = _renderer->GetImageDesc(imageID); + const DepthImageDesc& imageDesc = _renderer->GetDesc(imageID); commandList.Clear(resource, imageDesc.depthClearValue); commandList.ImageBarrier(resource); @@ -296,8 +296,8 @@ namespace Renderer } // Lock the DescriptorSets so we have to go through the DescriptorSetResource - const DynamicArray& usedDescriptorSets = _resources.GetUsedDescriptorSetIDs(currentPassIndex); - for (DescriptorSetID descriptorSetID : usedDescriptorSets) + const DynamicArray& usedDescriptorSets = _resources.GetUsedDescriptorSetIDs(currentPassIndex); + for (DescriptorSetResourceID descriptorSetID : usedDescriptorSets) { DescriptorSet* descriptorSet = _resources.GetDescriptorSet(descriptorSetID); descriptorSet->Lock(); @@ -309,8 +309,8 @@ namespace Renderer void RenderGraphBuilder::PostPass(CommandList& /*commandList*/, u32 currentPassIndex, const std::string& passName) { // Unlock the DescriptorSets so we can use them again - const DynamicArray& usedDescriptorSets = _resources.GetUsedDescriptorSetIDs(currentPassIndex); - for (DescriptorSetID descriptorSetID : usedDescriptorSets) + const DynamicArray& usedDescriptorSets = _resources.GetUsedDescriptorSetIDs(currentPassIndex); + for (DescriptorSetResourceID descriptorSetID : usedDescriptorSets) { DescriptorSet* descriptorSet = _resources.GetDescriptorSet(descriptorSetID); descriptorSet->Unlock(); diff --git a/Source/Renderer/Renderer/RenderGraphResources.cpp b/Source/Renderer/Renderer/RenderGraphResources.cpp index 2e1f40aa..70d597d5 100644 --- a/Source/Renderer/Renderer/RenderGraphResources.cpp +++ b/Source/Renderer/Renderer/RenderGraphResources.cpp @@ -31,7 +31,7 @@ namespace Renderer TrackedBufferBitSets bufferPermissions; - DynamicArray descriptorSetIDs; + DynamicArray descriptorSetIDs; }; struct RenderGraphResourcesData : IRenderGraphResourcesData @@ -121,22 +121,22 @@ namespace Renderer const ImageDesc& RenderGraphResources::GetImageDesc(ImageResource resource) { ImageID imageID = GetImage(resource); - return _renderer->GetImageDesc(imageID); + return _renderer->GetDesc(imageID); } const ImageDesc& RenderGraphResources::GetImageDesc(ImageMutableResource resource) { ImageID imageID = GetImage(resource); - return _renderer->GetImageDesc(imageID); + return _renderer->GetDesc(imageID); } const DepthImageDesc& RenderGraphResources::GetImageDesc(DepthImageResource resource) { DepthImageID imageID = GetImage(resource); - return _renderer->GetImageDesc(imageID); + return _renderer->GetDesc(imageID); } const DepthImageDesc& RenderGraphResources::GetImageDesc(DepthImageMutableResource resource) { DepthImageID imageID = GetImage(resource); - return _renderer->GetImageDesc(imageID); + return _renderer->GetDesc(imageID); } uvec2 RenderGraphResources::GetImageDimensions(ImageResource resource, u32 mipLevel) @@ -204,9 +204,9 @@ namespace Renderer return data->trackedBuffers[static_cast(resource)]; } - DescriptorSet* RenderGraphResources::GetDescriptorSet(DescriptorSetID descriptorSetID) + DescriptorSet* RenderGraphResources::GetDescriptorSet(DescriptorSetResourceID descriptorSetID) { - NC_ASSERT(descriptorSetID != DescriptorSetID::Invalid(), "RenderGraphResources : GetDescriptorSet tried to get image of invalid DescriptorSetResourceID"); + NC_ASSERT(descriptorSetID != DescriptorSetResourceID::Invalid(), "RenderGraphResources : GetDescriptorSet tried to get image of invalid DescriptorSetResourceID"); RenderGraphResourcesData* data = static_cast(_data); return data->trackedDescriptorSets[static_cast(descriptorSetID)]; @@ -266,21 +266,21 @@ namespace Renderer { RenderGraphResourcesData* data = static_cast(_data); - DescriptorSetID id = DescriptorSetID::Invalid(); + DescriptorSetResourceID id = DescriptorSetResourceID::Invalid(); for (u32 i = 0; i < data->trackedDescriptorSets.Count(); i++) { DescriptorSet* trackedDescriptorSet = data->trackedDescriptorSets[i]; if (trackedDescriptorSet == &descriptorSet) { - id = DescriptorSetID(i); + id = DescriptorSetResourceID(i); break; } } - if (id == DescriptorSetID::Invalid()) + if (id == DescriptorSetResourceID::Invalid()) { - id = DescriptorSetID(static_cast(data->trackedDescriptorSets.Count())); + id = DescriptorSetResourceID(static_cast(data->trackedDescriptorSets.Count())); data->trackedDescriptorSets.Insert(&descriptorSet); } @@ -616,7 +616,7 @@ namespace Renderer return data->trackedPasses[passIndex].bufferPermissions; } - const DynamicArray& RenderGraphResources::GetUsedDescriptorSetIDs(u32 passIndex) + const DynamicArray& RenderGraphResources::GetUsedDescriptorSetIDs(u32 passIndex) { RenderGraphResourcesData* data = static_cast(_data); diff --git a/Source/Renderer/Renderer/RenderGraphResources.h b/Source/Renderer/Renderer/RenderGraphResources.h index 0fc0cef4..d9a7b0b0 100644 --- a/Source/Renderer/Renderer/RenderGraphResources.h +++ b/Source/Renderer/Renderer/RenderGraphResources.h @@ -100,7 +100,7 @@ namespace Renderer BufferID GetBuffer(BufferResource resource); BufferID GetBuffer(BufferMutableResource resource); - DescriptorSet* GetDescriptorSet(DescriptorSetID resource); + DescriptorSet* GetDescriptorSet(DescriptorSetResourceID resource); ImageResource GetResource(ImageID id); DepthImageResource GetResource(DepthImageID id); @@ -131,7 +131,7 @@ namespace Renderer const TrackedBufferBitSets& GetBufferPermissions(u32 passIndex); - const DynamicArray& GetUsedDescriptorSetIDs(u32 passIndex); + const DynamicArray& GetUsedDescriptorSetIDs(u32 passIndex); const DynamicArray& GetPassAccesses(ImageID imageID); const DynamicArray& GetPassAccesses(DepthImageID imageID); diff --git a/Source/Renderer/Renderer/Renderer.cpp b/Source/Renderer/Renderer/Renderer.cpp index 988d8939..84401942 100644 --- a/Source/Renderer/Renderer/Renderer.cpp +++ b/Source/Renderer/Renderer/Renderer.cpp @@ -4,24 +4,26 @@ #include +#include + namespace Renderer { Renderer::~Renderer() { } - void Renderer::SetGetShaderEntryCallback(const std::function& callback) + void Renderer::SetGetShaderEntryCallback(const std::function& callback) { _getShaderEntryCallback = callback; } - const ShaderEntry& Renderer::GetShaderEntry(u32 shaderNameHash) + const ShaderEntry* Renderer::GetShaderEntry(u32 shaderNameHash, const std::string& debugName) { if (!_getShaderEntryCallback) { NC_LOG_CRITICAL("Renderer::GetShaderEntry called but no callback is set!"); } - return _getShaderEntryCallback(shaderNameHash); + return _getShaderEntryCallback(shaderNameHash, debugName); } void Renderer::SetGetBlitPipelineCallback(const std::function& callback) diff --git a/Source/Renderer/Renderer/Renderer.h b/Source/Renderer/Renderer/Renderer.h index dd9c3913..f4f4804e 100644 --- a/Source/Renderer/Renderer/Renderer.h +++ b/Source/Renderer/Renderer/Renderer.h @@ -3,6 +3,7 @@ #include "DescriptorMeta.h" #include "DescriptorSet.h" +#include "DescriptorType.h" #include "RenderStates.h" #include "ShaderEntry.h" @@ -12,6 +13,7 @@ #include "Descriptors/ComputePipelineDesc.h" #include "Descriptors/ComputeShaderDesc.h" #include "Descriptors/DepthImageDesc.h" +#include "Descriptors/DescriptorSetDesc.h" #include "Descriptors/GraphicsPipelineDesc.h" #include "Descriptors/ImageDesc.h" #include "Descriptors/PixelShaderDesc.h" @@ -24,6 +26,16 @@ #include "Descriptors/UploadBuffer.h" #include "Descriptors/VertexShaderDesc.h" +namespace FileFormat +{ + struct ShaderReflection; +} + +namespace Memory +{ + class Allocator; +} + namespace Novus { class Window; @@ -34,11 +46,6 @@ namespace tracy struct SourceLocationData; } -namespace Memory -{ - class Allocator; -} - struct FfxInterface; struct FfxCacaoContext; @@ -58,7 +65,7 @@ namespace Renderer virtual void Deinit() = 0; virtual void SetShaderSourceDirectory(const std::string& path) = 0; - virtual void SetGetShaderEntryCallback(const std::function& callback); + virtual void SetGetShaderEntryCallback(const std::function& callback); virtual void SetGetBlitPipelineCallback(const std::function& callback); virtual void ReloadShaders(bool forceRecompileAll) = 0; virtual void ClearUploadBuffers() = 0; @@ -84,6 +91,8 @@ namespace Renderer virtual SamplerID CreateSampler(SamplerDesc& sampler) = 0; virtual SemaphoreID CreateNSemaphore() = 0; + virtual DescriptorSetID CreateDescriptorSet(const DescriptorSetDesc& desc) = 0; + virtual GraphicsPipelineID CreatePipeline(GraphicsPipelineDesc& desc) = 0; virtual ComputePipelineID CreatePipeline(ComputePipelineDesc& desc) = 0; @@ -106,8 +115,21 @@ namespace Renderer virtual void UnloadTexture(TextureID textureID) = 0; virtual void UnloadTexturesInArray(TextureArrayID textureArrayID, u32 unloadStartIndex) = 0; + // Descriptor binding + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, BufferID bufferID, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, u32 arrayIndex, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 frameIndex) = 0; + virtual void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 arrayIndex, u32 frameIndex) = 0; + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) = 0; + virtual void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureArrayID textureArrayID) = 0; + // Misc virtual u32 AddTextureToArray(TextureID textureID, TextureArrayID textureArrayID) = 0; + virtual void FlushTextureArrayDescriptors(TextureArrayID textureArrayID) = 0; // Command List Functions virtual CommandListID BeginCommandList() = 0; @@ -154,7 +176,7 @@ namespace Renderer virtual void SetIndexBuffer(CommandListID commandListID, BufferID bufferID, IndexFormat indexFormat) = 0; virtual void SetBuffer(CommandListID commandListID, u32 slot, BufferID buffer) = 0; - virtual void BindDescriptorSet(CommandListID commandListID, DescriptorSetSlot slot, Descriptor* descriptors, u32 numDescriptors, const TrackedBufferBitSets* bufferPermissions) = 0; + virtual void BindDescriptorSet(CommandListID commandListID, DescriptorSet* descriptorSet, const TrackedBufferBitSets* bufferPermissions) = 0; virtual void MarkFrameStart(CommandListID commandListID, u32 frameIndex) = 0; virtual void BeginTrace(CommandListID commandListID, const tracy::SourceLocationData* sourceLocation) = 0; @@ -207,17 +229,29 @@ namespace Renderer const std::vector& GetFrameTimeQueries() { return _frameTimeQueries; } + // ID to Descriptor + virtual TextureBaseDesc GetDesc(TextureID textureID) = 0; + + virtual const ImageDesc& GetDesc(ImageID ID) = 0; + virtual const DepthImageDesc& GetDesc(DepthImageID ID) = 0; + + virtual const ComputePipelineDesc& GetDesc(ComputePipelineID ID) = 0; + virtual const GraphicsPipelineDesc& GetDesc(GraphicsPipelineID ID) = 0; + + virtual const ComputeShaderDesc& GetDesc(ComputeShaderID ID) = 0; + virtual const VertexShaderDesc& GetDesc(VertexShaderID ID) = 0; + virtual const PixelShaderDesc& GetDesc(PixelShaderID ID) = 0; + // Utils virtual void FlushGPU() = 0; virtual f32 FlipFrame(u32 frameIndex) = 0; // Returns time waited in seconds + virtual u32 GetCurrentFrameIndex() = 0; + virtual u32 GetFrameIndexCount() = 0; + virtual void ResetTimeQueries(u32 frameIndex) = 0; virtual TextureID GetTextureID(TextureArrayID textureArrayID, u32 index) = 0; - virtual TextureBaseDesc GetTextureDesc(TextureID textureID) = 0; - - virtual const ImageDesc& GetImageDesc(ImageID ID) = 0; - virtual const DepthImageDesc& GetImageDesc(DepthImageID ID) = 0; virtual uvec2 GetImageDimensions(const ImageID id, u32 mipLevel = 0) = 0; virtual uvec2 GetImageDimensions(const DepthImageID id) = 0; @@ -241,13 +275,11 @@ namespace Renderer virtual bool HasExtendedTextureSupport() = 0; - virtual void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, GraphicsPipelineID pipeline, DescriptorSetSlot slot) = 0; - virtual void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, ComputePipelineID pipeline, DescriptorSetSlot slot) = 0; + const ShaderEntry* GetShaderEntry(u32 shaderNameHash, const std::string& debugName); protected: Renderer() {}; // Pure virtual class, disallow creation of it - const ShaderEntry& GetShaderEntry(u32 shaderNameHash); const GraphicsPipelineID GetBlitPipeline(u32 shaderNameHash); void BeginExecutingCommandlist() { _isExecutingCommandlist = true; }; @@ -258,7 +290,7 @@ namespace Renderer std::vector _frameTimeQueries; std::vector> _onRenderSizeChangedCallbacks; - std::function _getShaderEntryCallback; + std::function _getShaderEntryCallback; std::function _getBlitPipelineCallback; friend class RenderGraph; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.cpp deleted file mode 100644 index 6c934ea7..00000000 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "DescriptorAllocatorVK.h" -#include "RenderDeviceVK.h" - -#include - -#include -#include -#include - -namespace Renderer -{ - namespace Backend - { - bool IsMemoryError(VkResult result) - { - switch (result) - { - case VK_ERROR_FRAGMENTED_POOL: - case VK_ERROR_OUT_OF_POOL_MEMORY: - return true; - - default: - return false; - } - } - - struct DescriptorAllocatorVK - { - VkDescriptorPool pool; - }; - - struct PoolStorage - { - std::vector _usableAllocators; - std::vector _fullAllocators; - }; - - struct PoolSize - { - VkDescriptorType type; - f32 multiplier; - }; - - struct PoolSizes - { - std::vector sizes = - { - { VK_DESCRIPTOR_TYPE_SAMPLER, 4.0f}, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1.0f}, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 10.0f}, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1.0f}, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1.0f}, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1.0f}, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2.0f}, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2.0f}, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1.0f}, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1.0f}, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1.0f} - }; - }; - - class DescriptorAllocatorPoolVKImpl : public DescriptorAllocatorPoolVK - { - public: - virtual ~DescriptorAllocatorPoolVKImpl(); - - void SetPoolSizeMultiplier(VkDescriptorType type, f32 multiplier) override final; - void Flip() override final; - DescriptorAllocatorHandleVK GetAllocator() override final; - - void ReturnAllocator(DescriptorAllocatorHandleVK& handle, bool isFull); - VkDescriptorPool CreatePool(i32 count, VkDescriptorPoolCreateFlags flags); - - RenderDeviceVK* _device; - PoolSizes _poolSizes; - - i32 _frameIndex; - i32 _numFrames; - - std::mutex _poolMutex; - - // Zero is for static pool, next is for frame indexing - std::vector> _descriptorPools; - - // Fully cleared allocators - std::vector _clearAllocators; - }; - - DescriptorAllocatorPoolVK* DescriptorAllocatorPoolVK::Create(RenderDeviceVK* device, i32 numFrames) - { - DescriptorAllocatorPoolVKImpl* impl = new DescriptorAllocatorPoolVKImpl(); - - impl->_device = device; - impl->_frameIndex = 0; - impl->_numFrames = numFrames; - - for (i32 i = 0; i < numFrames; i++) - { - impl->_descriptorPools.push_back(std::make_unique()); - } - - return impl; - } - - DescriptorAllocatorHandleVK::~DescriptorAllocatorHandleVK() - { - DescriptorAllocatorPoolVKImpl* implPool = static_cast(ownerPool); - if (implPool) - { - implPool->ReturnAllocator(*this, false); - } - } - - DescriptorAllocatorHandleVK::DescriptorAllocatorHandleVK(DescriptorAllocatorHandleVK&& other) - { - Return(); - - vkPool = other.vkPool; - poolID = other.poolID; - ownerPool = other.ownerPool; - - other.ownerPool = nullptr; - other.poolID = -1; - other.vkPool = VkDescriptorPool(); - } - - DescriptorAllocatorHandleVK& DescriptorAllocatorHandleVK::operator=(DescriptorAllocatorHandleVK&& other) - { - Return(); - - vkPool = other.vkPool; - poolID = other.poolID; - ownerPool = other.ownerPool; - - other.ownerPool = nullptr; - other.poolID = -1; - other.vkPool = VkDescriptorPool(); - - return *this; - } - - void DescriptorAllocatorHandleVK::Return() - { - DescriptorAllocatorPoolVKImpl* implPool = static_cast(ownerPool); - if (implPool) - { - implPool->ReturnAllocator(*this, false); - } - - vkPool = VkDescriptorPool{}; - poolID = -1; - ownerPool = nullptr; - } - - bool DescriptorAllocatorHandleVK::Allocate(const VkDescriptorSetLayout& layout, VkDescriptorSet& set, void* next) - { - DescriptorAllocatorPoolVKImpl* implPool = static_cast(ownerPool); - - VkDescriptorSetAllocateInfo allocInfo; - allocInfo.pNext = next; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = vkPool; - allocInfo.descriptorSetCount = 1; - allocInfo.pSetLayouts = &layout; - - VkResult result = vkAllocateDescriptorSets(implPool->_device->_device, &allocInfo, &set); - if (result != VK_SUCCESS) - { - // We allocate pools on memory error - if (IsMemoryError(result)) - { - // Out of space, we need to reallocate - implPool->ReturnAllocator(*this, true); - - DescriptorAllocatorHandleVK newHandle = implPool->GetAllocator(); - - vkPool = newHandle.vkPool; - poolID = newHandle.poolID; - - newHandle.vkPool = VkDescriptorPool{}; - newHandle.poolID = -1; - newHandle.ownerPool = nullptr; - - return Allocate(layout, set); - } - else - { - NC_LOG_CRITICAL("Could not allocate descriptor set"); - return false; - } - } - - return true; - } - - VkDescriptorPool DescriptorAllocatorPoolVKImpl::CreatePool(i32 count, VkDescriptorPoolCreateFlags flags) - { - std::vector sizes; - sizes.reserve(_poolSizes.sizes.size()); - - for (auto size : _poolSizes.sizes) - { - sizes.push_back({ size.type, u32(size.multiplier * count) }); - } - - VkDescriptorPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.flags = flags; - poolInfo.maxSets = count; - poolInfo.poolSizeCount = static_cast(sizes.size()); - poolInfo.pPoolSizes = sizes.data(); - - VkDescriptorPool descriptorPool; - VkResult result = vkCreateDescriptorPool(_device->_device, &poolInfo, nullptr, &descriptorPool); - - if (result != VK_SUCCESS) - { - NC_LOG_CRITICAL("Could not create descriptor pool"); - } - - return descriptorPool; - } - - DescriptorAllocatorPoolVKImpl::~DescriptorAllocatorPoolVKImpl() - { - for (DescriptorAllocatorVK allocator : _clearAllocators) - { - vkDestroyDescriptorPool(_device->_device, allocator.pool, nullptr); - } - for (auto&& storage : _descriptorPools) - { - for (DescriptorAllocatorVK allocator : storage->_fullAllocators) - { - vkDestroyDescriptorPool(_device->_device, allocator.pool, nullptr); - } - for (DescriptorAllocatorVK allocator : storage->_usableAllocators) - { - vkDestroyDescriptorPool(_device->_device, allocator.pool, nullptr); - } - } - } - - void DescriptorAllocatorPoolVKImpl::Flip() - { - _frameIndex = (_frameIndex + 1) % _numFrames; - - for (auto allocator : _descriptorPools[_frameIndex]->_fullAllocators) - { - vkResetDescriptorPool(_device->_device, allocator.pool, VkDescriptorPoolResetFlags{ 0 }); - - _clearAllocators.push_back(allocator); - } - - for (auto allocator : _descriptorPools[_frameIndex]->_usableAllocators) - { - vkResetDescriptorPool(_device->_device, allocator.pool, VkDescriptorPoolResetFlags{ 0 }); - - _clearAllocators.push_back(allocator); - } - - _descriptorPools[_frameIndex]->_fullAllocators.clear(); - _descriptorPools[_frameIndex]->_usableAllocators.clear(); - } - - void DescriptorAllocatorPoolVKImpl::SetPoolSizeMultiplier(VkDescriptorType type, f32 multiplier) - { - for (auto& size : _poolSizes.sizes) - { - if (size.type == type) - { - size.multiplier = multiplier; - return; - } - } - - // Not found, so add it - PoolSize newSize; - newSize.type = type; - newSize.multiplier = multiplier; - _poolSizes.sizes.push_back(newSize); - } - - void DescriptorAllocatorPoolVKImpl::ReturnAllocator(DescriptorAllocatorHandleVK& handle, bool isFull) - { - std::lock_guard lock(_poolMutex); - - if (isFull) - { - _descriptorPools[handle.poolID]->_fullAllocators.push_back(DescriptorAllocatorVK{ handle.vkPool }); - } - else - { - _descriptorPools[handle.poolID]->_usableAllocators.push_back(DescriptorAllocatorVK{ handle.vkPool }); - } - } - - DescriptorAllocatorHandleVK DescriptorAllocatorPoolVKImpl::GetAllocator() - { - std::lock_guard lock(_poolMutex); - - bool foundAllocator = false; - i32 poolIndex = _frameIndex; - - DescriptorAllocatorVK allocator; - - // Try to reuse an allocated pool - if (_clearAllocators.size() != 0) - { - allocator = _clearAllocators.back(); - _clearAllocators.pop_back(); - foundAllocator = true; - } - else - { - if (_descriptorPools[poolIndex]->_usableAllocators.size() > 0) - { - allocator = _descriptorPools[poolIndex]->_usableAllocators.back(); - _descriptorPools[poolIndex]->_usableAllocators.pop_back(); - foundAllocator = true; - } - } - - // Need a new pool - if (!foundAllocator) - { - // Static pool has to be free-able - VkDescriptorPoolCreateFlags flags = 0; - if (poolIndex == 0) - { - flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - } - - VkDescriptorPool newPool = CreatePool(2000, flags); - allocator.pool = newPool; - - foundAllocator = true; - } - - DescriptorAllocatorHandleVK newHandle; - newHandle.ownerPool = this; - newHandle.poolID = poolIndex; - newHandle.vkPool = allocator.pool; - - return newHandle; - } - - } -} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.h deleted file mode 100644 index 13760f4a..00000000 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorAllocatorVK.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include - -#include - -namespace Renderer -{ - namespace Backend - { - class RenderDeviceVK; - class DescriptorAllocatorPoolVK; - - struct DescriptorAllocatorHandleVK - { - friend struct DescriptorAllocatorVK; - DescriptorAllocatorHandleVK() = default; - DescriptorAllocatorHandleVK& operator=(const DescriptorAllocatorHandleVK&) = delete; - - ~DescriptorAllocatorHandleVK(); - DescriptorAllocatorHandleVK(DescriptorAllocatorHandleVK&& other); - DescriptorAllocatorHandleVK& operator=(DescriptorAllocatorHandleVK&& other); - - // Return this handle to the pool, will make this handle orphaned - void Return(); - - // Allocate new descriptor, handle has to be valid - // Will mutate the handle if it requires a new vkDescriptorPool - bool Allocate(const VkDescriptorSetLayout& layout, VkDescriptorSet& set, void* pNext = nullptr); - - DescriptorAllocatorPoolVK* ownerPool{ nullptr }; - VkDescriptorPool vkPool; - i8 poolID; - }; - - class DescriptorAllocatorPoolVK - { - public: - static DescriptorAllocatorPoolVK* Create(RenderDeviceVK* device, i32 numFrames = 3); - - virtual void SetPoolSizeMultiplier(VkDescriptorType type, f32 multiplier) = 0; - - virtual void Flip() = 0; - virtual DescriptorAllocatorHandleVK GetAllocator() = 0; - }; - } -} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.cpp new file mode 100644 index 00000000..4ac8c389 --- /dev/null +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.cpp @@ -0,0 +1,387 @@ +#include "DescriptorHandlerVK.h" +#include "TextureHandlerVK.h" +#include "RenderDeviceVK.h" +#include "FormatConverterVK.h" + +#include +#include + +#include + +namespace Renderer +{ + namespace Backend + { + VkDescriptorPoolSize poolSizes[] = + { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 40000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLER, 100 } + }; + constexpr u32 maxDescriptorSets = 128; + + struct DescriptorSet + { + DescriptorSetDesc desc; + + VkDescriptorSet sets[RenderDeviceVK::FRAME_INDEX_COUNT]; + VkDescriptorSetLayout layout; + }; + + struct DescriptorHandlerData : public IDescriptorHandlerData + { + // Pool data + VkDescriptorPool permanentPool; + //VkDescriptorPool framePools[RenderDeviceVK::FRAME_INDEX_COUNT]; // TODO + + std::vector descriptorSets; + }; + + void DescriptorHandlerVK::Init(RenderDeviceVK* device, TextureHandlerVK* textureHandler) + { + ZoneScoped; + _device = device; + _textureHandler = textureHandler; + _data = new DescriptorHandlerData(); + + CreateDescriptorPool(); + } + + DescriptorSetID DescriptorHandlerVK::CreateDescriptorSet(const DescriptorSetDesc& desc) + { + ZoneScoped; + DescriptorHandlerData& data = *static_cast(_data); + + DescriptorSetID id = DescriptorSetID(static_cast(data.descriptorSets.size())); + DescriptorSet& descriptorSet = data.descriptorSets.emplace_back(); + descriptorSet.desc = desc; + + CreateDescriptorSet(descriptorSet); + + return id; + } + + VkDescriptorSet DescriptorHandlerVK::GetVkDescriptorSet(DescriptorSetID descriptorSetID, u32 frameIndex) + { + DescriptorHandlerData& data = *static_cast(_data); + + DescriptorSetID::type id = static_cast(descriptorSetID); + if (id >= data.descriptorSets.size()) + { + NC_LOG_CRITICAL("DescriptorHandlerVK::GetVkDescriptorSet: Invalid DescriptorSetID {}", id); + } + + return data.descriptorSets[id].sets[frameIndex]; + } + + VkDescriptorSetLayout DescriptorHandlerVK::GetVkDescriptorSetLayout(DescriptorSetID descriptorSetID) + { + DescriptorHandlerData& data = *static_cast(_data); + + DescriptorSetID::type id = static_cast(descriptorSetID); + if (id >= data.descriptorSets.size()) + { + NC_LOG_CRITICAL("DescriptorHandlerVK::GetVkDescriptorSetLayout: Invalid DescriptorSetID {}", id); + } + + return data.descriptorSets[id].layout; + } + + void DescriptorHandlerVK::CreateDescriptorPool() + { + ZoneScoped; + DescriptorHandlerData& data = *static_cast(_data); + + VkDescriptorPoolCreateInfo poolInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + poolInfo.maxSets = maxDescriptorSets; + poolInfo.poolSizeCount = ARRAY_COUNT(poolSizes); + poolInfo.pPoolSizes = poolSizes; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + + vkCreateDescriptorPool(_device->_device, &poolInfo, nullptr, &data.permanentPool); + } + + void DescriptorHandlerVK::CreateDescriptorSet(DescriptorSet& descriptorSet) + { + ZoneScoped; + DescriptorHandlerData& data = *static_cast(_data); + u32 numSupportedTextures = _device->HasExtendedTextureSupport() ? 8192 : 4096; + + // Init bindings + u32 numReflectedDescriptors = static_cast(descriptorSet.desc.reflection->descriptors.size()); + std::vector bindings; + bindings.reserve(numReflectedDescriptors); + + std::vector bindingFlags; + bindingFlags.reserve(numReflectedDescriptors); + + bool hasVariableBinding = false; + + for (auto& [_, descriptor] : descriptorSet.desc.reflection->descriptors) + { + VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + u32 count = descriptor.count; + + VkDescriptorType vkDescType = FormatConverterVK::ToVkDescriptorType(descriptor); + bool isTextureType = vkDescType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || vkDescType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bool isTextureArray = isTextureType && (count != 1); + + if (isTextureArray) + { + flags |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + + if (count == 0) + { + count = numSupportedTextures; + hasVariableBinding = true; + flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT; + } + } + + VkDescriptorSetLayoutBinding binding{}; + binding.binding = descriptor.binding; + binding.descriptorType = FormatConverterVK::ToVkDescriptorType(descriptor); + binding.descriptorCount = count; + binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; + binding.pImmutableSamplers = nullptr; + bindings.push_back(binding); + bindingFlags.push_back(flags); + } + + // Create layout + VkDescriptorSetLayoutBindingFlagsCreateInfo flagsInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO }; + flagsInfo.bindingCount = static_cast(bindingFlags.size()); + flagsInfo.pBindingFlags = bindingFlags.data(); + + VkDescriptorSetLayoutCreateInfo layoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + layoutInfo.pNext = &flagsInfo; + layoutInfo.bindingCount = static_cast(bindings.size()); + layoutInfo.pBindings = bindings.data(); + layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + + VkResult result = vkCreateDescriptorSetLayout(_device->_device, &layoutInfo, nullptr, &descriptorSet.layout); + if (result != VK_SUCCESS) + { + NC_LOG_CRITICAL("DescriptorHandlerVK::CreateDescriptorSet: Failed to create descriptor set layout!"); + } + + // Create descriptor set + VkDescriptorSetVariableDescriptorCountAllocateInfo variableCountInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO }; + variableCountInfo.descriptorSetCount = 1; + variableCountInfo.pDescriptorCounts = &numSupportedTextures; + + VkDescriptorSetAllocateInfo allocInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + if (hasVariableBinding) + { + allocInfo.pNext = &variableCountInfo; + } + allocInfo.descriptorPool = data.permanentPool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &descriptorSet.layout; + + for (u32 i = 0; i < RenderDeviceVK::FRAME_INDEX_COUNT; i++) + { + result = vkAllocateDescriptorSets(_device->_device, &allocInfo, &descriptorSet.sets[i]); + if (result != VK_SUCCESS) + { + NC_LOG_CRITICAL("DescriptorHandlerVK::CreateDescriptorSet: Failed to allocate descriptor set! You probably need to increase maxDescriptorSets."); + } + } + } + + void DescriptorHandlerVK::BindDescriptor(DescriptorSetID setID, u32 binding, VkBuffer buffer, DescriptorType type, u32 frameIndex) + { + ZoneScoped; + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = buffer; + bufferInfo.offset = 0; + bufferInfo.range = VK_WHOLE_SIZE; + + VkWriteDescriptorSet descriptorWrite{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descriptorWrite.dstSet = GetVkDescriptorSet(setID, frameIndex); + descriptorWrite.dstBinding = binding; + descriptorWrite.descriptorCount = 1; + descriptorWrite.descriptorType = FormatConverterVK::ToVkDescriptorType(type); + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(_device->_device, 1, &descriptorWrite, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptor(DescriptorSetID setID, u32 binding, VkImageView image, DescriptorType type, bool isRT, u32 frameIndex) + { + ZoneScoped; + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageView = image; + imageInfo.imageLayout = (!isRT && type == DescriptorType::SampledImage) ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; + + VkWriteDescriptorSet write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, frameIndex); + write.dstBinding = binding; + write.descriptorCount = 1; + write.descriptorType = FormatConverterVK::ToVkDescriptorType(type); + write.pImageInfo = &imageInfo; + + vkUpdateDescriptorSets(_device->_device, 1, &write, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptorArray(DescriptorSetID setID, u32 binding, VkImageView image, u32 arrayOffset, DescriptorType type, bool isRT, u32 frameIndex) + { + ZoneScoped; + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageView = image; + imageInfo.imageLayout = (!isRT && type == DescriptorType::SampledImage) ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; + + VkWriteDescriptorSet write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, frameIndex); + write.dstBinding = binding; + write.dstArrayElement = arrayOffset; + write.descriptorCount = 1; + write.descriptorType = FormatConverterVK::ToVkDescriptorType(type); + write.pImageInfo = &imageInfo; + + vkUpdateDescriptorSets(_device->_device, 1, &write, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptorArray(DescriptorSetID setID, u32 binding, std::vector& images, u32 arrayOffset, DescriptorType type, bool isRT, u32 frameIndex) + { + ZoneScoped; + u32 count = static_cast(images.size()); + + VkImageLayout layout = (!isRT && type == DescriptorType::SampledImage) + ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + : VK_IMAGE_LAYOUT_GENERAL; + + std::vector imageInfos(count); + for (u32 i = 0; i < count; ++i) + { + imageInfos[i].sampler = VK_NULL_HANDLE; + imageInfos[i].imageView = images[i]; + imageInfos[i].imageLayout = layout; + } + + VkWriteDescriptorSet write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, frameIndex); + write.dstBinding = binding; + write.dstArrayElement = arrayOffset; + write.descriptorCount = count; + write.descriptorType = FormatConverterVK::ToVkDescriptorType(type); + write.pImageInfo = imageInfos.data(); + + vkUpdateDescriptorSets(_device->_device, 1, &write, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptor(DescriptorSetID setID, u32 binding, VkSampler sampler, u32 frameIndex) + { + ZoneScoped; + VkDescriptorImageInfo samplerInfo{}; + samplerInfo.sampler = sampler; + + VkWriteDescriptorSet write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, frameIndex); + write.dstBinding = binding; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + write.pImageInfo = &samplerInfo; + + vkUpdateDescriptorSets(_device->_device, 1, &write, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptorArray(DescriptorSetID setID, u32 binding, VkSampler sampler, u32 arrayIndex, u32 frameIndex) + { + ZoneScoped; + VkDescriptorImageInfo samplerInfo{}; + samplerInfo.sampler = sampler; + + VkWriteDescriptorSet write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, frameIndex); + write.dstBinding = binding; + write.dstArrayElement = arrayIndex; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + write.pImageInfo = &samplerInfo; + + vkUpdateDescriptorSets(_device->_device, 1, &write, 0, nullptr); + } + + void DescriptorHandlerVK::BindDescriptor(DescriptorSetID setID, u32 binding, TextureArrayID textureArrayID) + { + ZoneScoped; + // Register this binding so future texture array updates can propagate to this descriptor set + _textureHandler->RegisterTextureArrayBinding(textureArrayID, setID, binding); + + const SafeVector& textureIDs = _textureHandler->GetTextureIDsInArray(textureArrayID); + + u32 numTextures = static_cast(textureIDs.Size()); + + // Only update the descriptor if there are textures in the array + if (numTextures == 0) + { + return; + } + + std::vector imageInfos(numTextures); + + for(u32 i = 0; i < numTextures; i++) + { + TextureID textureID = textureIDs.ReadGetUnsafe(i); + VkImageView imageView = _textureHandler->GetImageView(textureID); + + imageInfos[i].imageView = imageView; + imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfos[i].sampler = VK_NULL_HANDLE; + } + + std::vector writes(RenderDeviceVK::FRAME_INDEX_COUNT); + for(u32 i = 0; i < RenderDeviceVK::FRAME_INDEX_COUNT; i++) + { + VkWriteDescriptorSet& write = writes[i]; + write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, i); + write.dstBinding = binding; + write.dstArrayElement = 0; + write.descriptorCount = numTextures; + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + write.pImageInfo = imageInfos.data(); + } + + vkUpdateDescriptorSets(_device->_device, static_cast(writes.size()), writes.data(), 0, nullptr); + } + + void DescriptorHandlerVK::UpdateTextureArrayDescriptors(DescriptorSetID setID, u32 binding, const TextureID* textureIDs, u32 startIndex, u32 count) + { + ZoneScoped; + if (count == 0) + { + return; + } + + std::vector imageInfos(count); + + for (u32 i = 0; i < count; i++) + { + VkImageView imageView = _textureHandler->GetImageView(textureIDs[i]); + + imageInfos[i].imageView = imageView; + imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfos[i].sampler = VK_NULL_HANDLE; + } + + std::vector writes(RenderDeviceVK::FRAME_INDEX_COUNT); + for (u32 i = 0; i < RenderDeviceVK::FRAME_INDEX_COUNT; i++) + { + VkWriteDescriptorSet& write = writes[i]; + write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = GetVkDescriptorSet(setID, i); + write.dstBinding = binding; + write.dstArrayElement = startIndex; + write.descriptorCount = count; + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + write.pImageInfo = imageInfos.data(); + } + + vkUpdateDescriptorSets(_device->_device, static_cast(writes.size()), writes.data(), 0, nullptr); + } + } +} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.h new file mode 100644 index 00000000..bc956580 --- /dev/null +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorHandlerVK.h @@ -0,0 +1,55 @@ +#pragma once +#include "Renderer/Descriptors/DescriptorSetDesc.h" +#include "Renderer/Descriptors/TextureDesc.h" +#include "Renderer/Descriptors/TextureArrayDesc.h" +#include "Renderer/DescriptorType.h" + +#include +#include + +#include + +namespace Renderer +{ + namespace Backend + { + class RenderDeviceVK; + class TextureHandlerVK; + struct DescriptorSet; + + struct IDescriptorHandlerData {}; + + class DescriptorHandlerVK + { + public: + void Init(RenderDeviceVK* device, TextureHandlerVK* textureHandler); + + DescriptorSetID CreateDescriptorSet(const DescriptorSetDesc& desc); + + void BindDescriptor(DescriptorSetID setID, u32 binding, VkBuffer buffer, DescriptorType type, u32 frameIndex); + void BindDescriptor(DescriptorSetID setID, u32 binding, VkImageView image, DescriptorType type, bool isRT, u32 frameIndex); + void BindDescriptorArray(DescriptorSetID setID, u32 binding, VkImageView image, u32 arrayOffset, DescriptorType type, bool isRT, u32 frameIndex); + void BindDescriptorArray(DescriptorSetID setID, u32 binding, std::vector& images, u32 arrayOffset, DescriptorType type, bool isRT, u32 frameIndex); + void BindDescriptor(DescriptorSetID setID, u32 binding, VkSampler sampler, u32 frameIndex); + void BindDescriptorArray(DescriptorSetID setID, u32 binding, VkSampler sampler, u32 arrayIndex, u32 frameIndex); + void BindDescriptor(DescriptorSetID setID, u32 binding, TextureArrayID textureArrayID); // Texture arrays don't take a frameIndex for simplicity, we don't expect them to change per-frame + + // Updates only a range of descriptors in a texture array binding (for incremental updates) + void UpdateTextureArrayDescriptors(DescriptorSetID setID, u32 binding, const TextureID* textureIDs, u32 startIndex, u32 count); + + VkDescriptorSet GetVkDescriptorSet(DescriptorSetID descriptorSetID, u32 frameIndex); + VkDescriptorSetLayout GetVkDescriptorSetLayout(DescriptorSetID descriptorSetID); + + private: + void CreateDescriptorPool(); + + void CreateDescriptorSet(DescriptorSet& descriptorSet); + + private: + RenderDeviceVK* _device; + TextureHandlerVK* _textureHandler; + + IDescriptorHandlerData* _data; + }; + } +} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.cpp deleted file mode 100644 index d5e42879..00000000 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.cpp +++ /dev/null @@ -1,763 +0,0 @@ -#include "DescriptorSetBuilderVK.h" -#include "BufferHandlerVK.h" -#include "PipelineHandlerVK.h" -#include "RenderDeviceVK.h" -#include "ShaderHandlerVK.h" -#include "Renderer/RenderSettings.h" -#include "Renderer/TrackedBufferBitSets.h" - -#include -#include - -#include -#include - -namespace Renderer -{ - namespace Backend - { - DescriptorSetBuilderVK::DescriptorSetBuilderVK(Memory::Allocator* allocator, GraphicsPipelineID pipelineID, PipelineHandlerVK* pipelineHandler, ShaderHandlerVK* shaderHandler, BufferHandlerVK* bufferHandler, DescriptorMegaPoolVK* parentPool) - : _allocator(allocator) - { - _pipelineType = PipelineType::Graphics; - _pipelineHandler = pipelineHandler; - _shaderHandler = shaderHandler; - _bufferHandler = bufferHandler; - _parentPool = parentPool; - _graphicsPipelineID = pipelineID; - } - - DescriptorSetBuilderVK::DescriptorSetBuilderVK(Memory::Allocator* allocator, ComputePipelineID pipelineID, PipelineHandlerVK* pipelineHandler, ShaderHandlerVK* shaderHandler, BufferHandlerVK* bufferHandler, DescriptorMegaPoolVK* parentPool) - : _allocator(allocator) - { - _pipelineType = PipelineType::Compute; - _pipelineHandler = pipelineHandler; - _shaderHandler = shaderHandler; - _bufferHandler = bufferHandler; - _parentPool = parentPool; - _computePipelineID = pipelineID; - } - - void DescriptorSetBuilderVK::InitReflectData() - { - ZoneScoped; - - if (_pipelineType == PipelineType::Graphics) - { - // Graphics pipeline - GraphicsPipelineDesc desc = _pipelineHandler->GetDescriptor(_graphicsPipelineID); - - if (desc.states.vertexShader != VertexShaderID::Invalid()) - { - const Backend::BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.states.vertexShader); - _bindInfos.insert(_bindInfos.end(), bindReflection.dataBindings.begin(), bindReflection.dataBindings.end()); - } - if (desc.states.pixelShader != PixelShaderID::Invalid()) - { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.states.pixelShader); - - // Loop over all new databindings - for (const BindInfo& dataBinding : bindReflection.dataBindings) - { - bool found = false; - // Loop over our current databindings - for (BindInfo& bindInfo : _bindInfos) - { - // If they occupy the same descriptor space - if (dataBinding.set == bindInfo.set && - dataBinding.binding == bindInfo.binding) - { - // If the name, descriptorType and count matches as well we assume it matches and is fine - if (dataBinding.nameHash == bindInfo.nameHash && - dataBinding.descriptorType == bindInfo.descriptorType && - dataBinding.count == bindInfo.count) - { - // Just add our stageflags to it - bindInfo.stageFlags |= dataBinding.stageFlags; - } - else - { - // Else somethings is really bad, lets fatal log - NC_LOG_CRITICAL("Vertex Shader and Pixel Shader tries to use the same descriptor set and binding, but they don't seem to match"); - } - found = true; - break; - } - } - - // If we didn't find a match, add it to our bindInfos - if (!found) - { - _bindInfos.push_back(dataBinding); - } - } - } - } - else - { - // Compute pipeline - ComputePipelineDesc desc = _pipelineHandler->GetDescriptor(_computePipelineID); - - const Backend::BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.computeShader); - _bindInfos.insert(_bindInfos.end(), bindReflection.dataBindings.begin(), bindReflection.dataBindings.end()); - } - - for(u32 i = 0; i < _bindInfos.size(); i++) - { - _hashedNameToBindInfoIndex.insert_or_assign(_bindInfos[i].nameHash, i); - } - - } - - void DescriptorSetBuilderVK::SetBufferPermissions(const TrackedBufferBitSets* bufferPermissions) - { - ZoneScoped; - - _bufferPermissions = bufferPermissions; - - u32 numBitSets = _bufferPermissions->GetNumBufferSets(); - _bufferReadAccesses = Memory::Allocator::New(_allocator, _allocator, numBitSets); - _bufferWriteAccesses = Memory::Allocator::New(_allocator, _allocator, numBitSets); - _bufferAccesses = Memory::Allocator::New(_allocator, _allocator, numBitSets); - } - - void DescriptorSetBuilderVK::BindSampler(i32 set, i32 binding, VkDescriptorImageInfo& imageInfo) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageInfo = imageInfo; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - newWrite.imageInfo = imageInfo; - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindSampler(u32 nameHash, VkDescriptorImageInfo& imageInfo) - { - ZoneScoped; - - NC_ASSERT(imageInfo.sampler != nullptr, "DescriptorSetBuilderVK : BindSampler was passed an imageInfo with a nullptr sampler"); - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindSampler(bindInfo.set, bindInfo.binding, imageInfo); - } - - void DescriptorSetBuilderVK::BindSamplerArrayIndex(i32 set, i32 binding, u32 arrayIndex, VkDescriptorImageInfo& imageInfo) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set && imageWrite.dstArrayIndex == arrayIndex) - { - imageWrite.imageInfo = imageInfo; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.dstArrayIndex = arrayIndex; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - newWrite.imageInfo = imageInfo; - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindSamplerArrayIndex(u32 nameHash, VkDescriptorImageInfo& imageInfo, u32 arrayIndex) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindSamplerArrayIndex(bindInfo.set, bindInfo.binding, arrayIndex, imageInfo); - } - - void DescriptorSetBuilderVK::BindImage(i32 set, i32 binding, const VkDescriptorImageInfo& imageInfo, bool imageWrite) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageInfo = imageInfo; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - newWrite.imageInfo = imageInfo; - if (imageWrite) - { - newWrite.imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindImage(u32 nameHash, const VkDescriptorImageInfo& imageInfo) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindImage(bindInfo.set, bindInfo.binding, imageInfo); - } - - void DescriptorSetBuilderVK::BindImageArray(i32 set, i32 binding, VkDescriptorImageInfo* images, i32 count) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageArray = images; - imageWrite.imageCount = count; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - newWrite.imageArray = images; - newWrite.imageCount = count; - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindImageArray(u32 nameHash, VkDescriptorImageInfo* images, i32 count) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindImageArray(bindInfo.set, bindInfo.binding, images, count); - } - - void DescriptorSetBuilderVK::BindImageArrayIndex(i32 set, i32 binding, u32 arrayIndex, const VkDescriptorImageInfo& imageInfo, bool imageWrite) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set && imageWrite.dstArrayIndex == arrayIndex) - { - imageWrite.imageInfo = imageInfo; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.dstArrayIndex = arrayIndex; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - newWrite.imageInfo = imageInfo; - if (imageWrite) - { - newWrite.imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindImageArrayIndex(u32 nameHash, const VkDescriptorImageInfo& imageInfo, u32 arrayIndex) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindImageArrayIndex(bindInfo.set, bindInfo.binding, arrayIndex, imageInfo); - } - - void DescriptorSetBuilderVK::BindStorageImage(i32 set, i32 binding, VkDescriptorImageInfo* imageInfos, i32 count) - { - ZoneScoped; - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - - if (count == 1) - { - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageInfo = imageInfos[0]; - return; - } - } - - newWrite.imageInfo = imageInfos[0]; - } - else - { - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageArray = imageInfos; - newWrite.imageCount = count; - return; - } - } - - newWrite.imageArray = imageInfos; - newWrite.imageCount = count; - } - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindStorageImage(u32 nameHash, VkDescriptorImageInfo* imageInfos, i32 count) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindStorageImage(bindInfo.set, bindInfo.binding, imageInfos, count); - } - - void DescriptorSetBuilderVK::BindStorageImageArray(u32 nameHash, VkDescriptorImageInfo* imageInfos, i32 count) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindStorageImageArray(bindInfo.set, bindInfo.binding, imageInfos, count); - } - - void DescriptorSetBuilderVK::BindStorageImageArray(i32 set, i32 binding, VkDescriptorImageInfo* imageInfos, i32 count) - { - ZoneScoped; - - for (auto& imageWrite : _imageWrites) - { - if (imageWrite.dstBinding == binding && imageWrite.dstSet == set) - { - imageWrite.imageArray = imageInfos; - imageWrite.imageCount = count; - return; - } - } - - ImageWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - newWrite.imageArray = imageInfos; - newWrite.imageCount = count; - - _imageWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindBuffer(i32 set, i32 binding, const VkDescriptorBufferInfo& bufferInfo, VkDescriptorType bufferType) - { - ZoneScoped; - - for (auto& bufferWrite : _bufferWrites) - { - if (bufferWrite.dstBinding == binding && bufferWrite.dstSet == set) - { - bufferWrite.bufferInfo = bufferInfo; - bufferWrite.descriptorType = bufferType; - return; - } - } - - BufferWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = bufferType; - newWrite.bufferInfo = bufferInfo; - - _bufferWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindBuffer(u32 nameHash, const VkDescriptorBufferInfo& bufferInfo, BufferID bufferID) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindBuffer(bindInfo.set, bindInfo.binding, bufferInfo, bindInfo.descriptorType); - - BufferID::type bufferIndex = static_cast(bufferID); - - _bufferAccesses->Set(bufferIndex); - if (bindInfo.isWrite) - { - _bufferWriteAccesses->Set(bufferIndex); - } - else - { - _bufferReadAccesses->Set(bufferIndex); - } - - _bufferIndexToBindInfoIndex[bufferIndex] = bindInfoIndex; - } - - void DescriptorSetBuilderVK::BindBufferArrayIndex(i32 set, i32 binding, u32 arrayIndex, const VkDescriptorBufferInfo& bufferInfo, VkDescriptorType bufferType) - { - ZoneScoped; - - for (auto& bufferWrite : _bufferWrites) - { - if (bufferWrite.dstBinding == binding && bufferWrite.dstSet == set && bufferWrite.dstArrayIndex == arrayIndex) - { - bufferWrite.bufferInfo = bufferInfo; - bufferWrite.descriptorType = bufferType; - return; - } - } - - BufferWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.dstArrayIndex = arrayIndex; - newWrite.descriptorType = bufferType; - newWrite.bufferInfo = bufferInfo; - - _bufferWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindBufferArrayIndex(u32 nameHash, const VkDescriptorBufferInfo& bufferInfo, u32 arrayIndex, BufferID bufferID) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindBufferArrayIndex(bindInfo.set, bindInfo.binding, arrayIndex, bufferInfo, bindInfo.descriptorType); - - BufferID::type bufferIndex = static_cast(bufferID); - - _bufferAccesses->Set(bufferIndex); - if (bindInfo.isWrite) - { - _bufferWriteAccesses->Set(bufferIndex); - } - else - { - _bufferReadAccesses->Set(bufferIndex); - } - - _bufferIndexToBindInfoIndex[bufferIndex] = bindInfoIndex; - } - - void DescriptorSetBuilderVK::BindRayStructure(i32 set, i32 binding, const VkWriteDescriptorSetAccelerationStructureKHR& info) - { - ZoneScoped; - - for (auto& bufferWrite : _bufferWrites) - { - if (bufferWrite.dstBinding == binding && bufferWrite.dstSet == set) - { - bufferWrite.accelinfo = info; - return; - } - } - - BufferWriteDescriptor newWrite; - newWrite.dstSet = set; - newWrite.dstBinding = binding; - newWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - newWrite.accelinfo = info; - - _bufferWrites.push_back(newWrite); - } - - void DescriptorSetBuilderVK::BindRayStructure(u32 nameHash, const VkWriteDescriptorSetAccelerationStructureKHR& info) - { - ZoneScoped; - - if (!_hashedNameToBindInfoIndex.contains(nameHash)) - return; - - u32 bindInfoIndex = _hashedNameToBindInfoIndex[nameHash]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - BindRayStructure(bindInfo.set, bindInfo.binding, info); - } - - void DescriptorSetBuilderVK::UpdateDescriptorSet(i32 set, VkDescriptorSet& descriptor, RenderDeviceVK& device) - { - ZoneScoped; - - std::vector descriptorWrites; - descriptorWrites.reserve(20); - - for (ImageWriteDescriptor& imageWrite : _imageWrites) - { - if (imageWrite.dstSet == set) - { - VkWriteDescriptorSet newWrite = {}; - newWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - newWrite.pNext = nullptr; - - newWrite.dstBinding = imageWrite.dstBinding; - newWrite.dstSet = descriptor; - newWrite.descriptorCount = 1; - newWrite.descriptorType = imageWrite.descriptorType; - newWrite.pImageInfo = &imageWrite.imageInfo; - - //special case for the image arrays - if (imageWrite.imageArray != nullptr) - { - newWrite.descriptorCount = imageWrite.imageCount; - newWrite.pImageInfo = imageWrite.imageArray; - } - // special case for image arrays that only write to individual indices - if (imageWrite.dstArrayIndex != -1) - { - newWrite.dstArrayElement = imageWrite.dstArrayIndex; - } - - descriptorWrites.push_back(newWrite); - } - } - - for (BufferWriteDescriptor& bufferWrite : _bufferWrites) - { - if (bufferWrite.dstSet == set) - { - VkWriteDescriptorSet newWrite = {}; - newWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - newWrite.pNext = nullptr; - - newWrite.dstBinding = bufferWrite.dstBinding; - newWrite.dstSet = descriptor; - newWrite.descriptorCount = 1; - newWrite.descriptorType = bufferWrite.descriptorType; - newWrite.pBufferInfo = &bufferWrite.bufferInfo; - - if (bufferWrite.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) - { - newWrite.pBufferInfo = nullptr; - newWrite.pNext = &bufferWrite.accelinfo; - } - if (bufferWrite.dstArrayIndex != -1) - { - newWrite.dstArrayElement = bufferWrite.dstArrayIndex; - } - - descriptorWrites.push_back(newWrite); - } - } - - vkUpdateDescriptorSets(device._device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); - } - - VkDescriptorSet DescriptorSetBuilderVK::BuildDescriptorSet(i32 set, DescriptorLifetime lifetime) - { - ZoneScoped; - - VkDescriptorSetLayout* layout; - if (_pipelineType == PipelineType::Graphics) - { - layout = &_pipelineHandler->GetDescriptorSetLayout(_graphicsPipelineID, set); - } - else - { - layout = &_pipelineHandler->GetDescriptorSetLayout(_computePipelineID, set); - } - - void* next = nullptr; - u32 counts[1]; - counts[0] = Settings::MAX_TEXTURES; - - VkDescriptorSetVariableDescriptorCountAllocateInfo setCounts = {}; - setCounts.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO; - setCounts.pNext = nullptr; - setCounts.descriptorSetCount = 1; - setCounts.pDescriptorCounts = counts; - - for (const ImageWriteDescriptor& imageWrite : _imageWrites) - { - if (imageWrite.descriptorType != VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && imageWrite.imageArray != nullptr && imageWrite.dstSet == set) - { - counts[0] = imageWrite.imageCount; - next = &setCounts; - } - } - - if (_bufferPermissions) - { - ValidateAccesses(); - } - - VkDescriptorSet newSet = _parentPool->AllocateDescriptor(*layout, lifetime, next); - UpdateDescriptorSet(set, newSet, *_parentPool->_device); - return newSet; - } - - void DescriptorSetBuilderVK::ValidateAccesses() - { - ZoneScoped; - - bool didError = false; - - const BitSet& readPermissions = _bufferPermissions->GetReadBitSet(); - if (!_bufferReadAccesses->IsSubsetOf(readPermissions)) - { - NC_LOG_INFO("\n\n--- READS ---"); - - BitSet* subtracted = _bufferReadAccesses->NewBitwiseUnset(readPermissions); - - subtracted->ForEachSetBit([&](u32 set, u32 bit) - { - u32 bufferIndex = set * 64 + bit; - BufferID bufferID = BufferID(bufferIndex); - - const std::string& bufferName = _bufferHandler->GetBufferName(bufferID); - - u32 bindInfoIndex = _bufferIndexToBindInfoIndex[bufferIndex]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - NC_LOG_ERROR("DescriptorSetBuilderVK : Tried to read from BufferID {} (Buffer Name: {}, Binding Name: {}), but RenderPass does not have READ access for that", bufferIndex, bufferName, bindInfo.name); - didError = true; - }); - } - - const BitSet& writePermissions = _bufferPermissions->GetWriteBitSet(); - if (!_bufferWriteAccesses->IsSubsetOf(writePermissions)) - { - NC_LOG_INFO("\n\n--- WRITES ---"); - - BitSet* subtracted = _bufferWriteAccesses->NewBitwiseUnset(writePermissions); - - subtracted->ForEachSetBit([&](u32 set, u32 bit) - { - u32 bufferIndex = set * 64 + bit; - BufferID bufferID = BufferID(bufferIndex); - - const std::string& bufferName = _bufferHandler->GetBufferName(bufferID); - - u32 bindInfoIndex = _bufferIndexToBindInfoIndex[bufferIndex]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - NC_LOG_ERROR("DescriptorSetBuilderVK : Tried to write to BufferID {} (Buffer Name: {}, Binding Name: {}), but RenderPass does not have WRITE access for that", bufferIndex, bufferName, bindInfo.name); - didError = true; - }); - } - - bool isGraphics = _pipelineType == PipelineType::Graphics; - const BitSet& shaderStagePermissions = (isGraphics) ? _bufferPermissions->GetGraphicsBitSet() : _bufferPermissions->GetComputeBitSet(); - if (!_bufferAccesses->IsSubsetOf(shaderStagePermissions)) - { - std::string stageName = (isGraphics) ? "GRAPHICS" : "COMPUTE"; - NC_LOG_INFO("\n\n--- {} ---", stageName); - - BitSet* subtracted = _bufferAccesses->NewBitwiseUnset(shaderStagePermissions); - - subtracted->ForEachSetBit([&](u32 set, u32 bit) - { - u32 bufferIndex = set * 64 + bit; - BufferID bufferID = BufferID(bufferIndex); - - const std::string& bufferName = _bufferHandler->GetBufferName(bufferID); - - u32 bindInfoIndex = _bufferIndexToBindInfoIndex[bufferIndex]; - BindInfo& bindInfo = _bindInfos[bindInfoIndex]; - - NC_LOG_ERROR("DescriptorSetBuilderVK : Tried to use BufferID {} (Buffer Name: {}, Binding Name: {}) in a {} pipeline, but RenderPass does not have access for that", bufferIndex, bufferName, bindInfo.name, stageName); - didError = true; - }); - } - - if (didError) - { - NC_LOG_CRITICAL("DescriptorSetBuilderVK : ValidateAccesses failed to validate the RenderPass"); - } - } - - VkDescriptorSet DescriptorMegaPoolVK::AllocateDescriptor(VkDescriptorSetLayout layout, DescriptorLifetime lifetime, void* next) - { - if (lifetime == DescriptorLifetime::Static) - { - VkDescriptorSet set; - _staticHandle.Allocate(layout, set, next); - return set; - } - else - { - VkDescriptorSet set; - _dynamicHandle.Allocate(layout, set, next); - return set; - } - } - - void DescriptorMegaPoolVK::Init(i32 numFrames, RenderDeviceVK* device) - { - _device = device; - - _dynamicAllocatorPool = DescriptorAllocatorPoolVK::Create(device, numFrames); - _staticAllocatorPool = DescriptorAllocatorPoolVK::Create(device, 1); - _dynamicHandle = _dynamicAllocatorPool->GetAllocator(); - _staticHandle = _staticAllocatorPool->GetAllocator(); - } - - void DescriptorMegaPoolVK::SetFrame(i32 frameNumber) - { - _dynamicAllocatorPool->Flip(); - _dynamicHandle = _dynamicAllocatorPool->GetAllocator(); - } - } -} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.h deleted file mode 100644 index decdfe71..00000000 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/DescriptorSetBuilderVK.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once -#include "DescriptorAllocatorVK.h" -#include "ShaderHandlerVK.h" -#include "Renderer/Descriptors/GraphicsPipelineDesc.h" -#include "Renderer/Descriptors/ComputePipelineDesc.h" -#include "Renderer/Descriptors/BufferDesc.h" - -#include - -#include -#include - -#include - -namespace Memory -{ - class Allocator; -} - -class BitSet; - -namespace Renderer -{ - class TrackedBufferBitSets; - - namespace Backend - { - class RenderDeviceVK; - class PipelineHandlerVK; - class ShaderHandlerVK; - class BufferHandlerVK; - - enum class DescriptorLifetime - { - Static, - PerFrame - }; - - struct DescriptorMegaPoolVK; - - class DescriptorSetBuilderVK - { - public: - DescriptorSetBuilderVK(::Memory::Allocator* allocator, GraphicsPipelineID pipelineID, PipelineHandlerVK* pipelineHandler, ShaderHandlerVK* shaderHandler, BufferHandlerVK* bufferHandler, DescriptorMegaPoolVK* parentPool); - DescriptorSetBuilderVK(::Memory::Allocator* allocator, ComputePipelineID pipelineID, PipelineHandlerVK* pipelineHandler, ShaderHandlerVK* shaderHandler, BufferHandlerVK* bufferHandler, DescriptorMegaPoolVK* parentPool); - - void InitReflectData(); - void SetBufferPermissions(const TrackedBufferBitSets* bufferPermissions); - - void BindSampler(i32 set, i32 binding, VkDescriptorImageInfo& imageInfo); - void BindSampler(u32 nameHash, VkDescriptorImageInfo& imageInfo); - - void BindSamplerArrayIndex(i32 set, i32 binding, u32 arrayIndex, VkDescriptorImageInfo& imageInfo); - void BindSamplerArrayIndex(u32 nameHash, VkDescriptorImageInfo& imageInfo, u32 arrayIndex); - - void BindImage(i32 set, i32 binding, const VkDescriptorImageInfo& imageInfo, bool imageWrite = false); - void BindImage(u32 nameHash, const VkDescriptorImageInfo& imageInfo); - - void BindImageArray(i32 set, i32 binding, VkDescriptorImageInfo* images, i32 count); - void BindImageArray(u32 nameHash, VkDescriptorImageInfo* images, i32 count); - - void BindImageArrayIndex(i32 set, i32 binding, u32 arrayIndex, const VkDescriptorImageInfo& imageInfo, bool imageWrite = false); - void BindImageArrayIndex(u32 nameHash, const VkDescriptorImageInfo& imageInfo, u32 arrayIndex); - - void BindStorageImage(i32 set, i32 binding, VkDescriptorImageInfo* imageInfos, i32 count); - void BindStorageImage(u32 nameHash, VkDescriptorImageInfo* imageInfos, i32 count); - - void BindStorageImageArray(i32 set, i32 binding, VkDescriptorImageInfo* imageInfos, i32 count); - void BindStorageImageArray(u32 nameHash, VkDescriptorImageInfo* imageInfos, i32 count); - - void BindBuffer(i32 set, i32 binding, const VkDescriptorBufferInfo& bufferInfo, VkDescriptorType bufferType); - void BindBuffer(u32 nameHash, const VkDescriptorBufferInfo& bufferInfo, BufferID bufferID); - - void BindBufferArrayIndex(i32 set, i32 binding, u32 arrayIndex, const VkDescriptorBufferInfo& bufferInfo, VkDescriptorType bufferType); - void BindBufferArrayIndex(u32 nameHash, const VkDescriptorBufferInfo& bufferInfo, u32 arrayIndex, BufferID bufferID); - - void BindRayStructure(i32 set, i32 binding, const VkWriteDescriptorSetAccelerationStructureKHR& info); - void BindRayStructure(u32 nameHash, const VkWriteDescriptorSetAccelerationStructureKHR& info); - - void UpdateDescriptorSet(i32 set, VkDescriptorSet& descriptor, RenderDeviceVK& device); - VkDescriptorSet BuildDescriptorSet(i32 set, DescriptorLifetime lifetime); - - private: - void ValidateAccesses(); - - private: - enum class PipelineType - { - Graphics, - Compute, - }; - - struct ImageWriteDescriptor - { - int dstSet; - int dstBinding; - int dstArrayIndex = -1; - VkDescriptorType descriptorType; - VkDescriptorImageInfo imageInfo; - VkDescriptorImageInfo* imageArray{ nullptr }; - int imageCount; - }; - - struct BufferWriteDescriptor - { - int dstSet; - int dstBinding; - int dstArrayIndex = -1; - VkDescriptorType descriptorType; - VkDescriptorBufferInfo bufferInfo; - VkWriteDescriptorSetAccelerationStructureKHR accelinfo; - }; - - private: - ::Memory::Allocator* _allocator; - - PipelineHandlerVK* _pipelineHandler; - ShaderHandlerVK* _shaderHandler; - BufferHandlerVK* _bufferHandler; - DescriptorMegaPoolVK* _parentPool; - - PipelineType _pipelineType; - - GraphicsPipelineID _graphicsPipelineID; - ComputePipelineID _computePipelineID; - - std::vector _bindInfos; - robin_hood::unordered_map _hashedNameToBindInfoIndex; - robin_hood::unordered_map _bufferIndexToBindInfoIndex; - - std::vector _imageWrites; - std::vector _bufferWrites; - - const TrackedBufferBitSets* _bufferPermissions = nullptr; - BitSet* _bufferAccesses = nullptr; - BitSet* _bufferReadAccesses = nullptr; - BitSet* _bufferWriteAccesses = nullptr; - }; - - struct DescriptorAllocator - { - i32 maxDescriptors; - i32 current_descriptors; - VkDescriptorPool pool; - }; - - struct DescriptorMegaPoolVK - { - VkDescriptorSet AllocateDescriptor(VkDescriptorSetLayout layout, DescriptorLifetime lifetime, void* next = nullptr); - - void Init(i32 numFrames, RenderDeviceVK* device); - void SetFrame(i32 frameNumber); - - DescriptorAllocatorHandleVK _dynamicHandle; - DescriptorAllocatorHandleVK _staticHandle; - - DescriptorAllocatorPoolVK* _dynamicAllocatorPool; - DescriptorAllocatorPoolVK* _staticAllocatorPool; - - RenderDeviceVK* _device; - }; - } -} \ No newline at end of file diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.cpp index 55cb4383..de568331 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.cpp @@ -2,6 +2,8 @@ #include +#include + namespace Renderer { namespace Backend @@ -549,6 +551,52 @@ namespace Renderer return VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST; } + VkDescriptorType FormatConverterVK::ToVkDescriptorType(const FileFormat::DescriptorReflection& descriptor) + { + FileFormat::DescriptorTypeReflection type = descriptor.type; + if (type == FileFormat::DescriptorTypeReflection::Array) + { + type = descriptor.subType; + } + + switch (type) + { + case FileFormat::DescriptorTypeReflection::ByteAddressBuffer: + case FileFormat::DescriptorTypeReflection::StructuredBuffer: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + case FileFormat::DescriptorTypeReflection::ConstantBuffer: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + case FileFormat::DescriptorTypeReflection::SamplerState: + return VK_DESCRIPTOR_TYPE_SAMPLER; + + case FileFormat::DescriptorTypeReflection::Texture: + case FileFormat::DescriptorTypeReflection::TextureArray: + if (descriptor.accessType == FileFormat::DescriptorAccessTypeReflection::Read) + return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + else + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } + + NC_LOG_CRITICAL("This should never hit, did we forget to update this function after adding more descriptor types?"); + return VK_DESCRIPTOR_TYPE_MAX_ENUM; + } + + VkDescriptorType FormatConverterVK::ToVkDescriptorType(DescriptorType type) + { + switch(type) + { + case DescriptorType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + case DescriptorType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case DescriptorType::SampledImage: return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + case DescriptorType::StorageImage: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + default: + NC_LOG_CRITICAL("This should never hit, did we forget to update this function after adding more descriptor types?"); + } + return VK_DESCRIPTOR_TYPE_MAX_ENUM; + } + bool FormatConverterVK::ToAnisotropyEnabled(SamplerFilter filter) { switch (filter) diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.h index 69a71715..aae86219 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/FormatConverterVK.h @@ -1,11 +1,17 @@ #pragma once #include "Renderer/DescriptorMeta.h" +#include "Renderer/DescriptorType.h" #include "Renderer/RenderStates.h" #include #include +namespace FileFormat +{ + struct DescriptorReflection; +} + namespace Renderer { namespace Backend @@ -33,6 +39,8 @@ namespace Renderer static VkBorderColor ToVkBorderColor(StaticBorderColor borderColor); static VkIndexType ToVkIndexType(IndexFormat indexFormat); static VkPrimitiveTopology ToVkPrimitiveTopology(PrimitiveTopology topology); + static VkDescriptorType ToVkDescriptorType(const FileFormat::DescriptorReflection& descriptor); + static VkDescriptorType ToVkDescriptorType(DescriptorType type); static bool ToAnisotropyEnabled(SamplerFilter filter); static u32 ToByteSize(const InputFormat format); diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.cpp index 3db574bb..0fd928e5 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.cpp @@ -4,7 +4,6 @@ #include "ShaderHandlerVK.h" #include "ImageHandlerVK.h" #include "SpirvReflect.h" -#include "DescriptorSetBuilderVK.h" #include "DebugMarkerUtilVK.h" #include @@ -39,8 +38,6 @@ namespace Renderer std::vector descriptorSetLayouts; std::vector pushConstantRanges; - - DescriptorSetBuilderVK* descriptorSetBuilder; }; struct ComputePipelineCacheDesc @@ -60,8 +57,6 @@ namespace Renderer std::vector descriptorSetLayouts; std::vector pushConstantRanges; - - DescriptorSetBuilderVK* descriptorSetBuilder; }; struct PipelineHandlerVKData : IPipelineHandlerVKData @@ -100,12 +95,7 @@ namespace Renderer pipeline.descriptorSetLayoutDatas.clear(); pipeline.pushConstantRanges.clear(); - delete pipeline.descriptorSetBuilder; - CreatePipelineInternal(pipeline, pipeline.desc, pipeline.numRenderTargets); - - pipeline.descriptorSetBuilder = new DescriptorSetBuilderVK(_allocator, GraphicsPipelineID(i), this, _shaderHandler, _bufferHandler, _device->_descriptorMegaPool); - pipeline.descriptorSetBuilder->InitReflectData(); } for (u32 i = 0; i < data.computePipelines.size(); i++) @@ -123,12 +113,7 @@ namespace Renderer pipeline.descriptorSetLayoutDatas.clear(); pipeline.pushConstantRanges.clear(); - delete pipeline.descriptorSetBuilder; - CreatePipelineInternal(pipeline, pipeline.desc); - - pipeline.descriptorSetBuilder = new DescriptorSetBuilderVK(_allocator, ComputePipelineID(i), this, _shaderHandler, _bufferHandler, _device->_descriptorMegaPool); - pipeline.descriptorSetBuilder->InitReflectData(); } } @@ -169,12 +154,8 @@ namespace Renderer CreatePipelineInternal(pipeline, desc, numAttachments); GraphicsPipelineID pipelineID = GraphicsPipelineID(static_cast(nextID)); - pipeline.descriptorSetBuilder = new DescriptorSetBuilderVK(_allocator, pipelineID, this, _shaderHandler, _bufferHandler, _device->_descriptorMegaPool); - data.graphicsPipelines.push_back(pipeline); - pipeline.descriptorSetBuilder->InitReflectData(); // Needs to happen after push_back - return pipelineID; } @@ -198,34 +179,30 @@ namespace Renderer CreatePipelineInternal(pipeline, desc); ComputePipelineID pipelineID = ComputePipelineID(static_cast(nextID)); - pipeline.descriptorSetBuilder = new DescriptorSetBuilderVK(_allocator, pipelineID, this, _shaderHandler, _bufferHandler, _device->_descriptorMegaPool); - data.computePipelines.push_back(pipeline); - pipeline.descriptorSetBuilder->InitReflectData(); // Needs to happen after push_back - return pipelineID; } - const GraphicsPipelineDesc& PipelineHandlerVK::GetDescriptor(GraphicsPipelineID id) + const GraphicsPipelineDesc& PipelineHandlerVK::GetDesc(GraphicsPipelineID id) { PipelineHandlerVKData& data = static_cast(*_data); return data.graphicsPipelines[static_cast(id)].desc; } - const ComputePipelineDesc& PipelineHandlerVK::GetDescriptor(ComputePipelineID id) + const ComputePipelineDesc& PipelineHandlerVK::GetDesc(ComputePipelineID id) { PipelineHandlerVKData& data = static_cast(*_data); return data.computePipelines[static_cast(id)].desc; } - GraphicsPipelineDesc& PipelineHandlerVK::GetMutableDescriptor(GraphicsPipelineID id) + GraphicsPipelineDesc& PipelineHandlerVK::GetMutableDesc(GraphicsPipelineID id) { PipelineHandlerVKData& data = static_cast(*_data); return data.graphicsPipelines[static_cast(id)].desc; } - ComputePipelineDesc& PipelineHandlerVK::GetMutableDescriptor(ComputePipelineID id) + ComputePipelineDesc& PipelineHandlerVK::GetMutableDesc(ComputePipelineID id) { PipelineHandlerVKData& data = static_cast(*_data); return data.computePipelines[static_cast(id)].desc; @@ -321,108 +298,6 @@ namespace Renderer return data.computePipelines[static_cast(id)].pipelineLayout; } - DescriptorSetBuilderVK& PipelineHandlerVK::GetDescriptorSetBuilder(GraphicsPipelineID id) - { - PipelineHandlerVKData& data = static_cast(*_data); - return *data.graphicsPipelines[static_cast(id)].descriptorSetBuilder; - } - - DescriptorSetBuilderVK& PipelineHandlerVK::GetDescriptorSetBuilder(ComputePipelineID id) - { - PipelineHandlerVKData& data = static_cast(*_data); - return *data.computePipelines[static_cast(id)].descriptorSetBuilder; - } - - void AddDescriptorMetaEntry(DescriptorMetaInfo& metaInfo, Backend::BindInfo bindInfo, DescriptorSetSlot slot) - { - u32 nameHash = bindInfo.nameHash; - u32 bindingIndex = bindInfo.binding; - DescriptorMetaType type = FormatConverterVK::ToDescriptorMetaType(bindInfo.descriptorType); - u32 setSlot = bindInfo.set; - - if (setSlot != static_cast(slot)) - { - return; - } - - NC_ASSERT(type != DescriptorMetaType::UNIFORM_BUFFER_DYNAMIC, "Shader is using useless Uniform Buffer Dynamic descriptor"); - NC_ASSERT(type != DescriptorMetaType::STORAGE_BUFFER_DYNAMIC, "Shader is using useless Storage Buffer Dynamic descriptor"); - NC_ASSERT(type != DescriptorMetaType::INPUT_ATTACHMENT, "Shader is using useless Input Attachment descriptor"); - - // If we already have a binding with this name, we need to make sure it matches - if (metaInfo.nameHashToDescriptorIndex.contains(nameHash)) - { - u32 existingIndex = metaInfo.nameHashToDescriptorIndex[nameHash]; - DescriptorMeta& existingMeta = metaInfo.descriptors[existingIndex]; - NC_ASSERT(existingMeta.nameHash == nameHash, "DescriptorMeta nameHash mismatch"); - NC_ASSERT(existingMeta.bindingIndex == bindingIndex, "DescriptorMeta bindingIndex mismatch"); - return; - } - - // If we already have a binding with this binding index, we need to make sure it matches - if (metaInfo.bindingIndexToDescriptorIndex.contains(bindingIndex)) - { - u32 existingIndex = metaInfo.bindingIndexToDescriptorIndex[bindingIndex]; - DescriptorMeta& existingMeta = metaInfo.descriptors[existingIndex]; - NC_ASSERT(existingMeta.nameHash == nameHash, "DescriptorMeta nameHash mismatch"); - NC_ASSERT(existingMeta.bindingIndex == bindingIndex, "DescriptorMeta bindingIndex mismatch"); - return; - } - - // If we didn't have it yet, add it - DescriptorMeta meta = { - .name = bindInfo.name, - .nameHash = nameHash, - .bindingIndex = bindingIndex, - .type = type - }; - u32 descriptorIndex = static_cast(metaInfo.descriptors.size()); - metaInfo.descriptors.push_back(meta); - metaInfo.nameHashToDescriptorIndex[meta.nameHash] = descriptorIndex; - metaInfo.bindingIndexToDescriptorIndex[meta.bindingIndex] = descriptorIndex; - } - - void PipelineHandlerVK::GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, GraphicsPipelineID pipelineID, DescriptorSetSlot slot) - { - PipelineHandlerVKData& data = static_cast(*_data); - auto& pipeline = data.graphicsPipelines[static_cast(pipelineID)]; - - if (pipeline.desc.states.vertexShader != VertexShaderID::Invalid()) - { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(pipeline.desc.states.vertexShader); - - for(auto& bindInfo : bindReflection.dataBindings) - { - AddDescriptorMetaEntry(metaInfo, bindInfo, slot); - } - } - if (pipeline.desc.states.pixelShader != PixelShaderID::Invalid()) - { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(pipeline.desc.states.pixelShader); - - for (auto& bindInfo : bindReflection.dataBindings) - { - AddDescriptorMetaEntry(metaInfo, bindInfo, slot); - } - } - } - - void PipelineHandlerVK::GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, ComputePipelineID pipelineID, DescriptorSetSlot slot) - { - PipelineHandlerVKData& data = static_cast(*_data); - auto& pipeline = data.computePipelines[static_cast(pipelineID)]; - - if (pipeline.desc.computeShader != ComputeShaderID::Invalid()) - { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(pipeline.desc.computeShader); - - for (auto& bindInfo : bindReflection.dataBindings) - { - AddDescriptorMetaEntry(metaInfo, bindInfo, slot); - } - } - } - u64 PipelineHandlerVK::CalculateCacheDescHash(const GraphicsPipelineDesc& desc) { GraphicsPipelineCacheDesc cacheDesc = {}; @@ -494,18 +369,20 @@ namespace Renderer void PipelineHandlerVK::CreatePipelineInternal(GraphicsPipeline& pipeline, const GraphicsPipelineDesc& desc, u32 numAttachments) { + u32 numSupportedTextures = _device->HasExtendedTextureSupport() ? 8192 : 4096; + // -- Get Reflection data from shader -- std::vector bindInfos; std::vector bindInfoPushConstants; if (desc.states.vertexShader != VertexShaderID::Invalid()) { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.states.vertexShader); + const BindReflection& bindReflection = _shaderHandler->GetFullBindReflection(desc.states.vertexShader); bindInfos.insert(bindInfos.end(), bindReflection.dataBindings.begin(), bindReflection.dataBindings.end()); bindInfoPushConstants.insert(bindInfoPushConstants.end(), bindReflection.pushConstants.begin(), bindReflection.pushConstants.end()); } if (desc.states.pixelShader != PixelShaderID::Invalid()) { - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.states.pixelShader); + const BindReflection& bindReflection = _shaderHandler->GetFullBindReflection(desc.states.pixelShader); // Loop over all new databindings for (const BindInfo& dataBinding : bindReflection.dataBindings) @@ -555,10 +432,16 @@ namespace Renderer layoutBinding.binding = bindInfo.binding; layoutBinding.descriptorType = bindInfo.descriptorType; - layoutBinding.descriptorCount = bindInfo.count; + layoutBinding.descriptorCount = (bindInfo.count == 0) ? numSupportedTextures : bindInfo.count; layoutBinding.stageFlags = bindInfo.stageFlags; layout.bindings.push_back(layoutBinding); + + bool isTextureType = bindInfo.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + bindInfo.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bool isTextureArray = isTextureType && (bindInfo.count == 0 || bindInfo.count > 1); + layout.isTextureArray.push_back(isTextureArray); + layout.isVariableBinding.push_back(bindInfo.count == 0); } size_t numDescriptorSets = pipeline.descriptorSetLayoutDatas.size(); @@ -566,10 +449,31 @@ namespace Renderer for (size_t i = 0; i < numDescriptorSets; i++) { - pipeline.descriptorSetLayoutDatas[i].createInfo.bindingCount = static_cast(pipeline.descriptorSetLayoutDatas[i].bindings.size()); - pipeline.descriptorSetLayoutDatas[i].createInfo.pBindings = pipeline.descriptorSetLayoutDatas[i].bindings.data(); + DescriptorSetLayoutData& layoutData = pipeline.descriptorSetLayoutDatas[i]; + + std::vector bindingFlags(layoutData.bindings.size(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT); + for (size_t j = 0; j < layoutData.bindings.size(); j++) + { + if (layoutData.isTextureArray[j]) + { + bindingFlags[j] |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + } + if (layoutData.isVariableBinding[j]) + { + bindingFlags[j] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT; + } + } - if (vkCreateDescriptorSetLayout(_device->_device, &pipeline.descriptorSetLayoutDatas[i].createInfo, nullptr, &pipeline.descriptorSetLayouts[i]) != VK_SUCCESS) + VkDescriptorSetLayoutBindingFlagsCreateInfo flagsInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO }; + flagsInfo.bindingCount = static_cast(bindingFlags.size()); + flagsInfo.pBindingFlags = bindingFlags.data(); + + layoutData.createInfo.pNext = &flagsInfo; + layoutData.createInfo.bindingCount = static_cast(layoutData.bindings.size()); + layoutData.createInfo.pBindings = layoutData.bindings.data(); + layoutData.createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + + if (vkCreateDescriptorSetLayout(_device->_device, &layoutData.createInfo, nullptr, &pipeline.descriptorSetLayouts[i]) != VK_SUCCESS) { NC_LOG_CRITICAL("Failed to create descriptor set layout!"); } @@ -856,26 +760,29 @@ namespace Renderer void PipelineHandlerVK::CreatePipelineInternal(ComputePipeline& pipeline, const ComputePipelineDesc& desc) { + u32 numSupportedTextures = _device->HasExtendedTextureSupport() ? 8192 : 4096; + std::vector bindInfos; std::vector bindInfoPushConstants; - - const BindReflection& bindReflection = _shaderHandler->GetBindReflection(desc.computeShader); + const BindReflection& bindReflection = _shaderHandler->GetFullBindReflection(desc.computeShader); bindInfos.insert(bindInfos.end(), bindReflection.dataBindings.begin(), bindReflection.dataBindings.end()); bindInfoPushConstants.insert(bindInfoPushConstants.end(), bindReflection.pushConstants.begin(), bindReflection.pushConstants.end()); - for (BindInfo& bindInfo : bindInfos) { DescriptorSetLayoutData& layout = GetDescriptorSet(bindInfo.set, pipeline.descriptorSetLayoutDatas); VkDescriptorSetLayoutBinding layoutBinding = {}; - layoutBinding.binding = bindInfo.binding; layoutBinding.descriptorType = bindInfo.descriptorType; - layoutBinding.descriptorCount = bindInfo.count; + layoutBinding.descriptorCount = (bindInfo.count == 0) ? numSupportedTextures : bindInfo.count; layoutBinding.stageFlags = bindInfo.stageFlags; - layout.bindings.push_back(layoutBinding); - } + bool isTextureType = bindInfo.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + bindInfo.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bool isTextureArray = isTextureType && (bindInfo.count == 0 || bindInfo.count > 1); + layout.isTextureArray.push_back(isTextureArray); + layout.isVariableBinding.push_back(bindInfo.count == 0); + } for (BindInfoPushConstant& pushConstant : bindInfoPushConstants) { VkPushConstantRange& range = pipeline.pushConstantRanges.emplace_back(); @@ -883,29 +790,47 @@ namespace Renderer range.size = pushConstant.size; range.stageFlags = pushConstant.stageFlags; } - size_t numDescriptorSets = pipeline.descriptorSetLayoutDatas.size(); pipeline.descriptorSetLayouts.resize(numDescriptorSets); - for (size_t i = 0; i < numDescriptorSets; i++) { - pipeline.descriptorSetLayoutDatas[i].createInfo.bindingCount = static_cast(pipeline.descriptorSetLayoutDatas[i].bindings.size()); - pipeline.descriptorSetLayoutDatas[i].createInfo.pBindings = pipeline.descriptorSetLayoutDatas[i].bindings.data(); + DescriptorSetLayoutData& layoutData = pipeline.descriptorSetLayoutDatas[i]; - if (vkCreateDescriptorSetLayout(_device->_device, &pipeline.descriptorSetLayoutDatas[i].createInfo, nullptr, &pipeline.descriptorSetLayouts[i]) != VK_SUCCESS) + // Build binding flags + std::vector bindingFlags(layoutData.bindings.size(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT); + for (size_t j = 0; j < layoutData.bindings.size(); j++) + { + if (layoutData.isTextureArray[j]) + { + bindingFlags[j] |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + } + if (layoutData.isVariableBinding[j]) + { + bindingFlags[j] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT; + } + } + + VkDescriptorSetLayoutBindingFlagsCreateInfo flagsInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO }; + flagsInfo.bindingCount = static_cast(bindingFlags.size()); + flagsInfo.pBindingFlags = bindingFlags.data(); + + layoutData.createInfo.pNext = &flagsInfo; + layoutData.createInfo.bindingCount = static_cast(layoutData.bindings.size()); + layoutData.createInfo.pBindings = layoutData.bindings.data(); + layoutData.createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + + if (vkCreateDescriptorSetLayout(_device->_device, &layoutData.createInfo, nullptr, &pipeline.descriptorSetLayouts[i]) != VK_SUCCESS) { NC_LOG_CRITICAL("Failed to create descriptor set layout!"); } DebugMarkerUtilVK::SetObjectName(_device->_device, (uint64_t)pipeline.descriptorSetLayouts[i], VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, desc.debugName.c_str()); } - VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = static_cast(pipeline.descriptorSetLayouts.size()); pipelineLayoutInfo.pSetLayouts = pipeline.descriptorSetLayouts.data(); pipelineLayoutInfo.pushConstantRangeCount = static_cast(pipeline.pushConstantRanges.size()); // Optional pipelineLayoutInfo.pPushConstantRanges = pipeline.pushConstantRanges.data(); - if (vkCreatePipelineLayout(_device->_device, &pipelineLayoutInfo, nullptr, &pipeline.pipelineLayout) != VK_SUCCESS) { NC_LOG_CRITICAL("Failed to create pipeline layout!"); diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.h index d05539bd..7b29655e 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/PipelineHandlerVK.h @@ -23,7 +23,6 @@ namespace Renderer class ShaderHandlerVK; class ImageHandlerVK; class BufferHandlerVK; - class DescriptorSetBuilderVK; struct GraphicsPipeline; struct ComputePipeline; @@ -31,6 +30,8 @@ namespace Renderer { VkDescriptorSetLayoutCreateInfo createInfo; std::vector bindings; + std::vector isTextureArray; + std::vector isVariableBinding; }; struct IPipelineHandlerVKData {}; @@ -47,12 +48,12 @@ namespace Renderer GraphicsPipelineID CreatePipeline(const GraphicsPipelineDesc& desc); ComputePipelineID CreatePipeline(const ComputePipelineDesc& desc); - const GraphicsPipelineDesc& GetDescriptor(GraphicsPipelineID id); - const ComputePipelineDesc& GetDescriptor(ComputePipelineID id); + const GraphicsPipelineDesc& GetDesc(GraphicsPipelineID id); + const ComputePipelineDesc& GetDesc(ComputePipelineID id); // Be careful with these - GraphicsPipelineDesc& GetMutableDescriptor(GraphicsPipelineID id); - ComputePipelineDesc& GetMutableDescriptor(ComputePipelineID id); + GraphicsPipelineDesc& GetMutableDesc(GraphicsPipelineID id); + ComputePipelineDesc& GetMutableDesc(ComputePipelineID id); VkPipeline GetPipeline(GraphicsPipelineID id); VkPipeline GetPipeline(ComputePipelineID id); @@ -77,12 +78,6 @@ namespace Renderer VkPipelineLayout& GetPipelineLayout(GraphicsPipelineID id); VkPipelineLayout& GetPipelineLayout(ComputePipelineID id); - DescriptorSetBuilderVK& GetDescriptorSetBuilder(GraphicsPipelineID id); - DescriptorSetBuilderVK& GetDescriptorSetBuilder(ComputePipelineID id); - - void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, GraphicsPipelineID pipeline, DescriptorSetSlot slot); - void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, ComputePipelineID pipeline, DescriptorSetSlot slot); - private: u64 CalculateCacheDescHash(const GraphicsPipelineDesc& desc); u64 CalculateCacheDescHash(const ComputePipelineDesc& desc); diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.cpp index 195ca6e4..d4f2147d 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.cpp @@ -1,7 +1,6 @@ #include "RenderDeviceVK.h" #include "DebugMarkerUtilVK.h" -#include "DescriptorSetBuilderVK.h" #include "ImageHandlerVK.h" #include "SemaphoreHandlerVK.h" #include "SwapChainVK.h" @@ -79,7 +78,6 @@ namespace Renderer { // TODO: All cleanup - delete _descriptorMegaPool; delete _imguiContext; } @@ -166,9 +164,6 @@ namespace Renderer CreateCommandPool(); CreateTracyContext(); - _descriptorMegaPool = new DescriptorMegaPoolVK(); - _descriptorMegaPool->Init(FRAME_INDEX_COUNT, this); - fnVkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR)vkGetDeviceProcAddr(_device, "vkCmdDrawIndirectCountKHR"); fnVkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR)vkGetDeviceProcAddr(_device, "vkCmdDrawIndexedIndirectCountKHR"); @@ -407,6 +402,11 @@ namespace Renderer descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; descriptorIndexingFeatures.runtimeDescriptorArray = true; descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing = true; + descriptorIndexingFeatures.descriptorBindingPartiallyBound = true; + descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind = true; + descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind = true; + descriptorIndexingFeatures.descriptorBindingStorageImageUpdateAfterBind = true; + descriptorIndexingFeatures.descriptorBindingVariableDescriptorCount = true; descriptorIndexingFeatures.pNext = &shaderSubgroupFeatures; VkPhysicalDeviceShaderAtomicInt64FeaturesKHR atomicInt64Features = {}; @@ -1426,8 +1426,8 @@ namespace Renderer NC_LOG_CRITICAL("Tried to use a format that wasn't uncompressed or used BC compression, what is this? id: {}", static_cast::type>(format)); } - curWidth = Math::Max(1, curWidth / 2); - curHeight = Math::Max(1, curHeight / 2); + curWidth = Math::Max(1u, curWidth / 2); + curHeight = Math::Max(1u, curHeight / 2); } vkCmdCopyBufferToImage( diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.h index a553a074..4653886b 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/RenderDeviceVK.h @@ -31,7 +31,6 @@ namespace Renderer struct SwapChainVK; class ImageHandlerVK; class SemaphoreHandlerVK; - struct DescriptorMegaPoolVK; struct QueueFamilyIndices { @@ -73,6 +72,8 @@ namespace Renderer const std::string& GetGPUName() { return _gpuName; } ImageFormat GetSwapChainImageFormat() { return _swapChainFormats[0]; } + static const u32 FRAME_INDEX_COUNT = 2; + private: void InitOnce(); @@ -128,7 +129,6 @@ namespace Renderer uvec2 _mainWindowSize; vec2 _renderSize = vec2(1, 1); - static const u32 FRAME_INDEX_COUNT = 2; static bool _initialized; u32 _frameIndex; @@ -157,26 +157,25 @@ namespace Renderer VmaAllocator _allocator; - DescriptorMegaPoolVK* _descriptorMegaPool; - tracy::VkCtx* _tracyContext = nullptr; ImguiContext* _imguiContext = nullptr; - friend class ::Renderer::RendererVK; friend class BufferHandlerVK; + friend class CommandListHandlerVK; + friend struct DescriptorAllocatorHandleVK; + friend class DescriptorAllocatorPoolVKImpl; + friend class DescriptorSetBuilderVK; + friend class DescriptorHandlerVK; + friend class FidelityFXHandlerVK; friend class ImageHandlerVK; - friend class TextureHandlerVK; friend class ModelHandlerVK; - friend class ShaderHandlerVK; friend class PipelineHandlerVK; - friend class CommandListHandlerVK; + friend class ::Renderer::RendererVK; friend class SamplerHandlerVK; friend class SemaphoreHandlerVK; + friend class ShaderHandlerVK; + friend class TextureHandlerVK; friend class TimeQueryHandlerVK; friend class UploadBufferHandlerVK; - friend struct DescriptorAllocatorHandleVK; - friend class DescriptorAllocatorPoolVKImpl; - friend class DescriptorSetBuilderVK; - friend class FidelityFXHandlerVK; }; } } diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.cpp index 9daeb49b..0851f15e 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -92,7 +93,7 @@ namespace Renderer ZoneScoped; VertexShaderID shaderID; bool wasCached; - if (desc.shaderEntry.shaderData != nullptr && desc.shaderEntry.shaderSize != 0) + if (desc.shaderEntry != nullptr) { shaderID = LoadShaderFromMemory(desc.shaderEntry, _vertexShaderStore, wasCached); } @@ -113,7 +114,7 @@ namespace Renderer ZoneScoped; PixelShaderID shaderID; bool wasCached; - if (desc.shaderEntry.shaderData != nullptr && desc.shaderEntry.shaderSize != 0) + if (desc.shaderEntry != nullptr) { shaderID = LoadShaderFromMemory(desc.shaderEntry, _pixelShaderStore, wasCached); } @@ -135,7 +136,7 @@ namespace Renderer ComputeShaderID shaderID; bool wasCached; - if (desc.shaderEntry.shaderData != nullptr && desc.shaderEntry.shaderSize != 0) + if (desc.shaderEntry != nullptr) { shaderID = LoadShaderFromMemory(desc.shaderEntry, _computeShaderStore, wasCached); } @@ -151,7 +152,7 @@ namespace Renderer return shaderID; } - void ShaderHandlerVK::ReflectShader(const uint32_t* shaderData, size_t shaderSize, BindReflection& bindReflection, const std::string& shaderPath) + void ShaderHandlerVK::ReflectUsedBindings(const uint32_t* shaderData, size_t shaderSize, BindReflection& bindReflection, const std::string& shaderPath) { // Reflect descriptor sets SpvReflectShaderModule reflectModule; @@ -233,6 +234,41 @@ namespace Renderer } } + void ShaderHandlerVK::ReflectFullBindings(const ShaderEntry* shaderEntry, BindReflection& bindReflection) + { + const FileFormat::ShaderReflection& reflection = shaderEntry->reflection; + + for (const auto& [set, descriptorSet] : reflection.descriptorSets) + { + for (const auto& [binding, descriptor] : descriptorSet.descriptors) + { + if (set == 0) + { + BindInfoPushConstant pushConstant; + pushConstant.offset = descriptor.byteOffset; + pushConstant.size = descriptor.byteSize; + pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; + + bindReflection.pushConstants.push_back(pushConstant); + } + else + { + BindInfo bindInfo; + bindInfo.name = descriptor.name; + bindInfo.nameHash = StringUtils::fnv1a_32(descriptor.name.c_str(), descriptor.name.length()); + bindInfo.descriptorType = FormatConverterVK::ToVkDescriptorType(descriptor); + bindInfo.set = set; + bindInfo.binding = binding; + bindInfo.count = descriptor.count; + bindInfo.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; + bindInfo.isUsed = descriptor.isUsed; + bindInfo.isWrite = (descriptor.accessType == FileFormat::DescriptorAccessTypeReflection::ReadWrite || descriptor.accessType == FileFormat::DescriptorAccessTypeReflection::Write); + bindReflection.dataBindings.push_back(bindInfo); + } + } + } + } + void ShaderHandlerVK::ReadFile(const std::string& filename, ShaderBinary& binary) { ZoneScoped; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.h index ab660a13..bc87e990 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/ShaderHandlerVK.h @@ -40,6 +40,9 @@ namespace Renderer u32 count; u32 stageFlags; + u32 offset; + u32 size; + bool isUsed = false; bool isWrite = false; }; @@ -72,21 +75,40 @@ namespace Renderer PixelShaderID LoadShader(const PixelShaderDesc& desc); ComputeShaderID LoadShader(const ComputeShaderDesc& desc); + const VertexShaderDesc& GetDesc(const VertexShaderID id) { return _vertexShaderStore.descs[static_cast(id)]; } + const PixelShaderDesc& GetDesc(const PixelShaderID id) { return _pixelShaderStore.descs[static_cast(id)]; } + const ComputeShaderDesc& GetDesc(const ComputeShaderID id) { return _computeShaderStore.descs[static_cast(id)]; } + VkShaderModule GetShaderModule(const VertexShaderID id) { return _vertexShaderStore.shaders[static_cast(id)].module; } VkShaderModule GetShaderModule(const PixelShaderID id) { return _pixelShaderStore.shaders[static_cast(id)].module; } VkShaderModule GetShaderModule(const ComputeShaderID id) { return _computeShaderStore.shaders[static_cast(id)].module; } - const BindReflection& GetBindReflection(const VertexShaderID id) + // Reflection of only what this shader uses + const BindReflection& GetUsedBindReflection(const VertexShaderID id) { - return _vertexShaderStore.shaders[static_cast(id)].bindReflection; + return _vertexShaderStore.shaders[static_cast(id)].usedBindReflection; } - const BindReflection& GetBindReflection(const PixelShaderID id) + const BindReflection& GetUsedBindReflection(const PixelShaderID id) { - return _pixelShaderStore.shaders[static_cast(id)].bindReflection; + return _pixelShaderStore.shaders[static_cast(id)].usedBindReflection; + } + const BindReflection& GetUsedBindReflection(const ComputeShaderID id) + { + return _computeShaderStore.shaders[static_cast(id)].usedBindReflection; + } + + // Full reflection of all descriptors in the shader even if not used + const BindReflection& GetFullBindReflection(const VertexShaderID id) + { + return _vertexShaderStore.shaders[static_cast(id)].fullBindReflection; + } + const BindReflection& GetFullBindReflection(const PixelShaderID id) + { + return _pixelShaderStore.shaders[static_cast(id)].fullBindReflection; } - const BindReflection& GetBindReflection(const ComputeShaderID id) + const BindReflection& GetFullBindReflection(const ComputeShaderID id) { - return _computeShaderStore.shaders[static_cast(id)].bindReflection; + return _computeShaderStore.shaders[static_cast(id)].fullBindReflection; } private: @@ -101,7 +123,8 @@ namespace Renderer VkShaderModule module; ShaderBinary spirv; - BindReflection bindReflection; + BindReflection usedBindReflection; + BindReflection fullBindReflection; }; struct ShaderStoreBase @@ -165,7 +188,9 @@ namespace Renderer shader.module = CreateShaderModule(data, size, shaderPath); shader.permutationFields = permutationFields; - ReflectShader(data, size, shader.bindReflection, shaderPath); + ReflectUsedBindings(data, size, shader.usedBindReflection, shaderPath); + // TODO: Somehow get the full reflection if you're not using shaderpacks, because the descriptorsets are gonna need it. This codepath is broken for now. + NC_LOG_CRITICAL("ShaderHandlerVK::LoadShaderFromFile - Loading shaders from file without shaderpacks is currently not supported!"); u32 permutationPathHash = StringUtils::fnv1a_32(permutationPath.c_str(), permutationPath.length()); shaderStore.hashToIndex[permutationPathHash] = static_cast(id); @@ -175,13 +200,13 @@ namespace Renderer } template - T LoadShaderFromMemory(const ShaderEntry& shaderEntry, ShaderStoreBase& shaderStore, bool& wasCached) + T LoadShaderFromMemory(const ShaderEntry* shaderEntry, ShaderStoreBase& shaderStore, bool& wasCached) { size_t id; using idType = type_safe::underlying_type; // If shader is already loaded, return ID of already loaded version - if (TryFindExistingShader(shaderEntry.permutationNameHash, shaderStore, id)) + if (TryFindExistingShader(shaderEntry->permutationNameHash, shaderStore, id)) { wasCached = true; return T(static_cast(id)); @@ -191,19 +216,21 @@ namespace Renderer assert(id < T::MaxValue()); Shader& shader = shaderStore.shaders.emplace_back(); - u32* data = reinterpret_cast(shaderEntry.shaderData); - const u32 size = shaderEntry.shaderSize; - shader.module = CreateShaderModule(data, size, shaderEntry.debugName); + u32* data = reinterpret_cast(shaderEntry->shaderData); + const u32 size = shaderEntry->shaderSize; + shader.module = CreateShaderModule(data, size, shaderEntry->debugName); - ReflectShader(data, size, shader.bindReflection, shaderEntry.debugName); + ReflectUsedBindings(data, size, shader.usedBindReflection, shaderEntry->debugName); + ReflectFullBindings(shaderEntry, shader.fullBindReflection); - shaderStore.hashToIndex[shaderEntry.permutationNameHash] = static_cast(id); + shaderStore.hashToIndex[shaderEntry->permutationNameHash] = static_cast(id); wasCached = false; return T(static_cast(id)); } - void ReflectShader(const uint32_t* shaderData, size_t shaderSize, BindReflection& bindReflection, const std::string& shaderPath); + void ReflectUsedBindings(const uint32_t* shaderData, size_t shaderSize, BindReflection& bindReflection, const std::string& shaderPath); + void ReflectFullBindings(const ShaderEntry* shaderEntry, BindReflection& bindReflection); void ReadFile(const std::string& filename, ShaderBinary& binary); VkShaderModule CreateShaderModule(const uint32_t* shaderData, size_t shaderSize, const std::string& debugName); diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h index 8c7398c1..8e80d25c 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h @@ -112,8 +112,8 @@ namespace Renderer { VkExtent2D actualExtent = { (uint32_t)windowSize.x, (uint32_t)windowSize.y }; - actualExtent.width = Math::Max(capabilities.minImageExtent.width, Math::Min((int)capabilities.maxImageExtent.width, (int)actualExtent.width)); - actualExtent.height = Math::Max(capabilities.minImageExtent.height, Math::Min((int)capabilities.maxImageExtent.height, (int)actualExtent.height)); + actualExtent.width = Math::Max(capabilities.minImageExtent.width, Math::Min(capabilities.maxImageExtent.width, actualExtent.width)); + actualExtent.height = Math::Max(capabilities.minImageExtent.height, Math::Min(capabilities.maxImageExtent.height, actualExtent.height)); return actualExtent; } diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.cpp index 2f49965d..fd322008 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.cpp @@ -4,6 +4,7 @@ #include "FormatConverterVK.h" #include "DebugMarkerUtilVK.h" #include "BufferHandlerVK.h" +#include "DescriptorHandlerVK.h" #include "UploadBufferHandlerVK.h" #include "SamplerHandlerVK.h" @@ -60,6 +61,12 @@ namespace Renderer bool layoutUndefined = true; }; + struct TextureArrayBinding + { + DescriptorSetID descriptorSetID; + u32 bindingIndex; + }; + struct TextureArray { u32 size; @@ -68,6 +75,9 @@ namespace Renderer SafeVector* textureHashes = nullptr; robin_hood::unordered_map* textureIDToArrayIndex; robin_hood::unordered_set ownedTextureIDs; + + std::vector registeredBindings; + u32 lastFlushedCount = 0; // Track how many textures were in last descriptor update }; struct TextureHandlerVKData : ITextureHandlerVKData @@ -79,11 +89,12 @@ namespace Renderer SafeVector textureArrays; }; - void TextureHandlerVK::Init(RenderDeviceVK* device, BufferHandlerVK* bufferHandler, UploadBufferHandlerVK* uploadBufferHandler, SamplerHandlerVK* samplerHandler) + void TextureHandlerVK::Init(RenderDeviceVK* device, BufferHandlerVK* bufferHandler, DescriptorHandlerVK* descriptorHandler, UploadBufferHandlerVK* uploadBufferHandler, SamplerHandlerVK* samplerHandler) { _data = new TextureHandlerVKData(); _device = device; _bufferHandler = bufferHandler; + _descriptorHandler = descriptorHandler; _uploadBufferHandler = uploadBufferHandler; _samplerHandler = samplerHandler; } @@ -144,6 +155,47 @@ namespace Renderer vkFreeDescriptorSets(_device->_device, _device->_imguiContext->imguiPool, static_cast(data.descriptorsToFree.size()), data.descriptorsToFree.data()); data.descriptorsToFree.clear(); } + + // Flush texture array updates - only update newly added textures + if (_descriptorHandler != nullptr) + { + data.textureArrays.WriteLock( + [&](std::vector& textureArrays) + { + for (size_t i = 0; i < textureArrays.size(); i++) + { + TextureArray& textureArray = textureArrays[i]; + + u32 currentCount = static_cast(textureArray.textures->Size()); + if (currentCount <= textureArray.lastFlushedCount) + { + continue; // No new textures to flush + } + + u32 newTexturesCount = currentCount - textureArray.lastFlushedCount; + u32 startIndex = textureArray.lastFlushedCount; + + // Update all registered descriptor sets with only the new textures + textureArray.textures->ReadLock( + [&](const std::vector& textures) + { + const TextureID* textureIDs = textures.data() + startIndex; + + for (const auto& binding : textureArray.registeredBindings) + { + _descriptorHandler->UpdateTextureArrayDescriptors( + binding.descriptorSetID, + binding.bindingIndex, + textureIDs, + startIndex, + newTexturesCount); + } + }); + + textureArray.lastFlushedCount = currentCount; + } + }); + } } TextureID TextureHandlerVK::LoadTexture(const TextureDesc& desc) @@ -301,6 +353,9 @@ namespace Renderer textureArray.textureHashes->Resize(unloadStartIndex); textureArray.textures->Resize(unloadStartIndex); + + // Update lastFlushedCount so subsequent loads in the same frame get flushed correctly + textureArray.lastFlushedCount = Math::Min(textureArray.lastFlushedCount, unloadStartIndex); }); } @@ -330,6 +385,83 @@ namespace Renderer return TextureArrayID(static_cast(nextHandle)); } + void TextureHandlerVK::RegisterTextureArrayBinding(TextureArrayID textureArrayID, DescriptorSetID descriptorSetID, u32 bindingIndex) + { + TextureHandlerVKData& data = static_cast(*_data); + TextureArrayID::type id = static_cast(textureArrayID); + + if (data.textureArrays.Size() <= id) + { + NC_LOG_CRITICAL("TextureHandlerVK::RegisterTextureArrayBinding: Tried to register binding for invalid TextureArrayID: {0}", id); + } + + data.textureArrays.WriteLock( + [&](std::vector& textureArrays) + { + TextureArray& textureArray = textureArrays[id]; + + // Check if this binding already exists + for (const auto& binding : textureArray.registeredBindings) + { + if (binding.descriptorSetID == descriptorSetID && binding.bindingIndex == bindingIndex) + { + return; // Already registered + } + } + + TextureArrayBinding newBinding; + newBinding.descriptorSetID = descriptorSetID; + newBinding.bindingIndex = bindingIndex; + textureArray.registeredBindings.push_back(newBinding); + }); + } + + void TextureHandlerVK::FlushTextureArrayDescriptors(TextureArrayID textureArrayID) + { + TextureHandlerVKData& data = static_cast(*_data); + TextureArrayID::type id = static_cast(textureArrayID); + + if (data.textureArrays.Size() <= id) + { + NC_LOG_CRITICAL("TextureHandlerVK::RegisterTextureArrayBinding: Tried to register binding for invalid TextureArrayID: {0}", id); + } + + data.textureArrays.WriteLock( + [&](std::vector& textureArrays) + { + TextureArray& textureArray = textureArrays[id]; + + u32 currentCount = static_cast(textureArray.textures->Size()); + if (currentCount <= textureArray.lastFlushedCount) + { + return; // No new textures to flush + } + + u32 newTexturesCount = currentCount - textureArray.lastFlushedCount; + u32 startIndex = textureArray.lastFlushedCount; + + // Update all registered descriptor sets with only the new textures + textureArray.textures->ReadLock( + [&](const std::vector& textures) + { + const TextureID* textureIDs = textures.data() + startIndex; + + for (const auto& binding : textureArray.registeredBindings) + { + _descriptorHandler->UpdateTextureArrayDescriptors( + binding.descriptorSetID, + binding.bindingIndex, + textureIDs, + startIndex, + newTexturesCount); + } + }); + + textureArray.lastFlushedCount = currentCount; + + }); + } + TextureID TextureHandlerVK::CreateDataTexture(const DataTextureDesc& desc) { TextureHandlerVKData& data = static_cast(*_data); @@ -362,8 +494,8 @@ namespace Renderer for (i32 i = 0; i < desc.mipLevels; ++i) { // For each mip level, calculate the reduced dimensions. - u32 mipWidth = Math::Max(1u, desc.width >> i); - u32 mipHeight = Math::Max(1u, desc.height >> i); + u32 mipWidth = Math::Max(1, desc.width >> i); + u32 mipHeight = Math::Max(1, desc.height >> i); mipUploadSize += static_cast(static_cast(mipWidth) * static_cast(mipHeight) * FormatTexelSize(FormatConverterVK::ToVkFormat(texture->desc.format))); } texture->uploadSize = mipUploadSize; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.h index 68af7477..b10ca7a3 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/TextureHandlerVK.h @@ -1,4 +1,5 @@ #pragma once +#include "Renderer/Descriptors/DescriptorSetDesc.h" #include "Renderer/Descriptors/SamplerDesc.h" #include "Renderer/Descriptors/TextureDesc.h" #include "Renderer/Descriptors/TextureArrayDesc.h" @@ -19,6 +20,7 @@ namespace Renderer class BufferHandlerVK; class UploadBufferHandlerVK; class SamplerHandlerVK; + class DescriptorHandlerVK; struct Texture; struct ITextureHandlerVKData {}; @@ -26,11 +28,14 @@ namespace Renderer class TextureHandlerVK { public: - void Init(RenderDeviceVK* device, BufferHandlerVK* bufferHandler, UploadBufferHandlerVK* uploadBufferHandler, SamplerHandlerVK* samplerHandler); + void Init(RenderDeviceVK* device, BufferHandlerVK* bufferHandler, DescriptorHandlerVK* descriptorHandler, UploadBufferHandlerVK* uploadBufferHandler, SamplerHandlerVK* samplerHandler); void InitDebugTexture(); void FlipFrame(u32 frameIndex); + void RegisterTextureArrayBinding(TextureArrayID textureArrayID, DescriptorSetID descriptorSetID, u32 bindingIndex); + void FlushTextureArrayDescriptors(TextureArrayID textureArrayID); + TextureID LoadTexture(const TextureDesc& desc); TextureID LoadTextureIntoArray(const TextureDesc& desc, TextureArrayID textureArrayID, u32& arrayIndex, bool allowDuplicates); @@ -85,6 +90,7 @@ namespace Renderer RenderDeviceVK* _device; BufferHandlerVK* _bufferHandler; + DescriptorHandlerVK* _descriptorHandler = nullptr; UploadBufferHandlerVK* _uploadBufferHandler; SamplerHandlerVK* _samplerHandler; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp index aebf4fd5..027c9865 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp @@ -1,22 +1,21 @@ #include "RendererVK.h" #include "Renderer/Window.h" -#include "Backend/RenderDeviceVK.h" #include "Backend/BufferHandlerVK.h" +#include "Backend/CommandListHandlerVK.h" +#include "Backend/DebugMarkerUtilVK.h" +#include "Backend/DescriptorHandlerVK.h" +#include "Backend/FormatConverterVK.h" #include "Backend/ImageHandlerVK.h" -#include "Backend/TextureHandlerVK.h" -#include "Backend/ShaderHandlerVK.h" #include "Backend/PipelineHandlerVK.h" -#include "Backend/CommandListHandlerVK.h" +#include "Backend/RenderDeviceVK.h" #include "Backend/SamplerHandlerVK.h" #include "Backend/SemaphoreHandlerVK.h" -#include "Backend/UploadBufferHandlerVK.h" +#include "Backend/ShaderHandlerVK.h" #include "Backend/SwapChainVK.h" -#include "Backend/DebugMarkerUtilVK.h" -#include "Backend/DescriptorSetBuilderVK.h" -#include "Backend/FormatConverterVK.h" -#include "Backend/DebugMarkerUtilVK.h" +#include "Backend/TextureHandlerVK.h" #include "Backend/TimeQueryHandlerVK.h" +#include "Backend/UploadBufferHandlerVK.h" #include #include @@ -31,32 +30,36 @@ namespace Renderer { RendererVK::RendererVK(Novus::Window* window) : _device(new Backend::RenderDeviceVK(window)) + , _presentDescriptorSet(DescriptorSetSlot::PER_PASS) { _frameAllocator.Init(64 * 1024 * 1024, "Renderer Allocator"); // Create handlers _bufferHandler = new Backend::BufferHandlerVK(); + _commandListHandler = new Backend::CommandListHandlerVK(); + _descriptorHandler = new Backend::DescriptorHandlerVK(); _imageHandler = new Backend::ImageHandlerVK(); - _textureHandler = new Backend::TextureHandlerVK(); - _shaderHandler = new Backend::ShaderHandlerVK(); _pipelineHandler = new Backend::PipelineHandlerVK(); - _commandListHandler = new Backend::CommandListHandlerVK(); _samplerHandler = new Backend::SamplerHandlerVK(); _semaphoreHandler = new Backend::SemaphoreHandlerVK(); - _uploadBufferHandler = new Backend::UploadBufferHandlerVK(); + _shaderHandler = new Backend::ShaderHandlerVK(); + _textureHandler = new Backend::TextureHandlerVK(); _timeQueryHandler = new Backend::TimeQueryHandlerVK(); + _uploadBufferHandler = new Backend::UploadBufferHandlerVK(); // Init _device->Init(); + _bufferHandler->Init(_device); - _imageHandler->Init(_device, _samplerHandler); - _textureHandler->Init(_device, _bufferHandler, _uploadBufferHandler, _samplerHandler); - _shaderHandler->Init(_device); - _timeQueryHandler->Init(_device); - _pipelineHandler->Init(&_frameAllocator, _device, _shaderHandler, _imageHandler, _bufferHandler); + _descriptorHandler->Init(_device, _textureHandler); _commandListHandler->Init(_device); _samplerHandler->Init(_device); _semaphoreHandler->Init(_device); + _shaderHandler->Init(_device); + _timeQueryHandler->Init(_device); + _imageHandler->Init(_device, _samplerHandler); + _pipelineHandler->Init(&_frameAllocator, _device, _shaderHandler, _imageHandler, _bufferHandler); + _textureHandler->Init(_device, _bufferHandler, _descriptorHandler, _uploadBufferHandler, _samplerHandler); _uploadBufferHandler->Init(this, _device, _bufferHandler, _textureHandler, _semaphoreHandler, _commandListHandler); } @@ -174,6 +177,11 @@ namespace Renderer return _semaphoreHandler->CreateNSemaphore(); } + DescriptorSetID RendererVK::CreateDescriptorSet(const DescriptorSetDesc& desc) + { + return _descriptorHandler->CreateDescriptorSet(desc); + } + GraphicsPipelineID RendererVK::CreatePipeline(GraphicsPipelineDesc& desc) { return _pipelineHandler->CreatePipeline(desc); @@ -243,11 +251,128 @@ namespace Renderer _textureHandler->UnloadTexturesInArray(textureArrayID, unloadStartIndex); } + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, BufferID bufferID, DescriptorType type, u32 frameIndex) + { + VkBuffer buffer = _bufferHandler->GetBuffer(bufferID); + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, buffer, type, frameIndex); + } + + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, DescriptorType type, u32 frameIndex) + { + VkImageView imageView = _imageHandler->GetColorView(imageID, mipLevel); + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, imageView, type, true, frameIndex); + } + + void RendererVK::BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) + { + std::vector imageViews; + for (u32 i = 0; i < mipCount; i++) + { + u32 mip = mipLevel + i; + VkImageView imageView = _imageHandler->GetColorView(imageID, mip); + imageViews.push_back(imageView); + } + _descriptorHandler->BindDescriptorArray(descriptorSetID, bindingIndex, imageViews, 0, type, true, frameIndex); + } + + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, DescriptorType type, u32 frameIndex) + { + VkImageView imageView = _imageHandler->GetDepthView(imageID); + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, imageView, type, true, frameIndex); + } + + void RendererVK::BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, u32 arrayIndex, DescriptorType type, u32 frameIndex) + { + VkImageView imageView = _imageHandler->GetDepthView(imageID); + _descriptorHandler->BindDescriptorArray(descriptorSetID, bindingIndex, imageView, arrayIndex, type, true, frameIndex); + } + + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 frameIndex) + { + VkSampler sampler = _samplerHandler->GetSampler(samplerID); + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, sampler, frameIndex); + } + + void RendererVK::BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 arrayIndex, u32 frameIndex) + { + VkSampler sampler = _samplerHandler->GetSampler(samplerID); + _descriptorHandler->BindDescriptorArray(descriptorSetID, bindingIndex, sampler, arrayIndex, frameIndex); + } + + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, DescriptorType type, u32 frameIndex) + { + VkImageView imageView = _textureHandler->GetImageView(textureID, mipLevel); + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, imageView, type, false, frameIndex); + } + + void RendererVK::BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) + { + std::vector imageViews; + for (u32 i = 0; i < mipCount; i++) + { + u32 mip = mipLevel + i; + VkImageView imageView = _textureHandler->GetImageView(textureID, mip); + imageViews.push_back(imageView); + } + + _descriptorHandler->BindDescriptorArray(descriptorSetID, bindingIndex, imageViews, 0, type, false, frameIndex); + } + + void RendererVK::BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureArrayID textureArrayID) + { + _descriptorHandler->BindDescriptor(descriptorSetID, bindingIndex, textureArrayID); + } + u32 RendererVK::AddTextureToArray(TextureID textureID, TextureArrayID textureArrayID) { return _textureHandler->AddTextureToArray(textureID, textureArrayID); } + void RendererVK::FlushTextureArrayDescriptors(TextureArrayID textureArrayID) + { + _textureHandler->FlushTextureArrayDescriptors(textureArrayID); + } + + TextureBaseDesc RendererVK::GetDesc(TextureID textureID) + { + return _textureHandler->GetTextureDesc(textureID); + } + + const ImageDesc& RendererVK::GetDesc(ImageID ID) + { + return _imageHandler->GetImageDesc(ID); + } + + const DepthImageDesc& RendererVK::GetDesc(DepthImageID ID) + { + return _imageHandler->GetImageDesc(ID); + } + + const ComputePipelineDesc& RendererVK::GetDesc(ComputePipelineID ID) + { + return _pipelineHandler->GetDesc(ID); + } + + const GraphicsPipelineDesc& RendererVK::GetDesc(GraphicsPipelineID ID) + { + return _pipelineHandler->GetDesc(ID); + } + + const ComputeShaderDesc& RendererVK::GetDesc(ComputeShaderID ID) + { + return _shaderHandler->GetDesc(ID); + } + + const VertexShaderDesc& RendererVK::GetDesc(VertexShaderID ID) + { + return _shaderHandler->GetDesc(ID); + } + + const PixelShaderDesc& RendererVK::GetDesc(PixelShaderID ID) + { + return _shaderHandler->GetDesc(ID); + } + static VmaBudget sBudgets[16] = { { 0 } }; void RendererVK::FlushGPU() @@ -258,6 +383,7 @@ namespace Renderer f32 RendererVK::FlipFrame(u32 frameIndex) { ZoneScopedC(tracy::Color::Red3); + _frameIndex = frameIndex; // Reset old commandbuffers _commandListHandler->FlipFrame(); @@ -311,29 +437,24 @@ namespace Renderer return timeWaited; } - void RendererVK::ResetTimeQueries(u32 frameIndex) - { - _frameTimeQueries.clear(); - } - - TextureID RendererVK::GetTextureID(TextureArrayID textureArrayID, u32 index) + u32 RendererVK::GetCurrentFrameIndex() { - return _textureHandler->GetTextureIDInArray(textureArrayID, index); + return _frameIndex; } - TextureBaseDesc RendererVK::GetTextureDesc(TextureID textureID) + u32 RendererVK::GetFrameIndexCount() { - return _textureHandler->GetTextureDesc(textureID); + return _device->FRAME_INDEX_COUNT; } - const ImageDesc& RendererVK::GetImageDesc(ImageID ID) + void RendererVK::ResetTimeQueries(u32 frameIndex) { - return _imageHandler->GetImageDesc(ID); + _frameTimeQueries.clear(); } - const DepthImageDesc& RendererVK::GetImageDesc(DepthImageID ID) + TextureID RendererVK::GetTextureID(TextureArrayID textureArrayID, u32 index) { - return _imageHandler->GetImageDesc(ID); + return _textureHandler->GetTextureIDInArray(textureArrayID, index); } uvec2 RendererVK::GetImageDimensions(const ImageID id, u32 mipLevel) @@ -668,7 +789,7 @@ namespace Renderer } uvec2 extent = desc.extent; - if (extent == uvec2(0)) + if (extent == uvec2(0) && desc.renderTargets[0] != ImageMutableResource::Invalid()) { extent = _imageHandler->GetDimensions(desc.MutableResourceToImageID(desc.renderTargets[0]), 0); } @@ -1233,243 +1354,6 @@ namespace Renderer return false; } - void RendererVK::BindDescriptor(Backend::DescriptorSetBuilderVK& builder, Descriptor& descriptor) - { - if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_BUFFER) - { - ZoneScopedN("Buffer"); - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = _bufferHandler->GetBuffer(descriptor.bufferID); - bufferInfo.range = _bufferHandler->GetBufferSize(descriptor.bufferID); - - builder.BindBuffer(descriptor.nameHash, bufferInfo, descriptor.bufferID); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_BUFFER_ARRAY) - { - ZoneScopedN("BufferArray"); - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = _bufferHandler->GetBuffer(descriptor.bufferID); - bufferInfo.range = _bufferHandler->GetBufferSize(descriptor.bufferID); - - builder.BindBufferArrayIndex(descriptor.nameHash, bufferInfo, descriptor.arrayIndex, descriptor.bufferID); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_SAMPLER) - { - ZoneScopedN("Sampler"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.sampler = _samplerHandler->GetSampler(descriptor.samplerID); - - builder.BindSampler(descriptor.nameHash, imageInfo); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_SAMPLER_ARRAY) - { - ZoneScopedN("SamplerArray"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.sampler = _samplerHandler->GetSampler(descriptor.samplerID); - - builder.BindSamplerArrayIndex(descriptor.nameHash, imageInfo, descriptor.arrayIndex); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_TEXTURE) - { - ZoneScopedN("Texture"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = _textureHandler->GetImageView(descriptor.textureID); - - builder.BindImage(descriptor.nameHash, imageInfo); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_TEXTURE_ARRAY) - { - ZoneScopedN("TextureArray"); - const SafeVector& textureIDs = _textureHandler->GetTextureIDsInArray(descriptor.textureArrayID); - - u32 textureArraySize = _textureHandler->GetTextureArraySize(descriptor.textureArrayID); - - VkDescriptorImageInfo* imageInfos = Memory::Allocator::NewArray(&_frameAllocator, textureArraySize); - u32 numImageInfos = 0; - - u32 numTextures = static_cast(textureIDs.Size()); - - // From 0 to numTextures, add our actual textures - bool texturesAreOnionTextures = false; - - textureIDs.ReadLock( - [&](const std::vector textures) - { - for (auto textureID : textures) - { - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = _textureHandler->GetImageView(textureID); - imageInfo.sampler = VK_NULL_HANDLE; - - texturesAreOnionTextures = _textureHandler->IsOnionTexture(textureID); - } - }); - - // from numTextures to textureArraySize, add debug texture - VkDescriptorImageInfo imageInfoDebugTexture; - imageInfoDebugTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (texturesAreOnionTextures) - { - imageInfoDebugTexture.imageView = _textureHandler->GetDebugOnionTextureImageView(); - } - else - { - imageInfoDebugTexture.imageView = _textureHandler->GetDebugTextureImageView(); - } - - imageInfoDebugTexture.sampler = VK_NULL_HANDLE; - - for (u32 i = numTextures; i < textureArraySize; i++) - { - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo = imageInfoDebugTexture; - } - - builder.BindImageArray(descriptor.nameHash, imageInfos, textureArraySize); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_TEXTURE_WRITE) - { - ZoneScopedN("TextureWrite"); - VkDescriptorImageInfo* imageInfos = Memory::Allocator::NewArray(&_frameAllocator, descriptor.count); - u32 numImageInfos = 0; - - TextureBaseDesc textureDesc = _textureHandler->GetTextureDesc(descriptor.textureID); - - for (u32 i = 0; i < descriptor.count; i++) - { - u32 mipLevel = descriptor.imageMipLevel + i; - - if ((i32)mipLevel < textureDesc.mipLevels) - { - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _textureHandler->GetImageView(descriptor.textureID, mipLevel); - imageInfo.sampler = VK_NULL_HANDLE; - } - else - { - // Any imageInfos pointing to mips we don't have should point to the last mip - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _textureHandler->GetImageView(descriptor.textureID, textureDesc.mipLevels - 1); - imageInfo.sampler = VK_NULL_HANDLE; - } - } - - builder.BindStorageImage(descriptor.nameHash, imageInfos, static_cast(descriptor.count)); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_TEXTURE_READ_WRITE) - { - ZoneScopedN("TextureReadWrite"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _textureHandler->GetImageView(descriptor.textureID); - - builder.BindImage(descriptor.nameHash, imageInfo); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_IMAGE) - { - ZoneScopedN("Image"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorView(descriptor.imageID,descriptor.imageMipLevel); - - builder.BindImage(descriptor.nameHash, imageInfo); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_IMAGE_ARRAY) - { - ZoneScopedN("ImageArray"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorView(descriptor.imageID, descriptor.imageMipLevel); - - builder.BindImageArrayIndex(descriptor.nameHash, imageInfo, descriptor.arrayIndex); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE) - { - ZoneScopedN("DepthImage"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - imageInfo.imageView = _imageHandler->GetDepthView(descriptor.depthImageID); - - builder.BindImage(descriptor.nameHash, imageInfo); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_DEPTH_IMAGE_ARRAY) - { - ZoneScopedN("DepthImageArray"); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - imageInfo.imageView = _imageHandler->GetDepthView(descriptor.depthImageID); - - builder.BindImageArrayIndex(descriptor.nameHash, imageInfo, descriptor.arrayIndex); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_STORAGE_IMAGE) - { - ZoneScopedN("StorageImage"); - VkDescriptorImageInfo* imageInfos = Memory::Allocator::NewArray(&_frameAllocator, descriptor.count); - u32 numImageInfos = 0; - - const ImageDesc& imageDesc = _imageHandler->GetImageDesc(descriptor.imageID); - - for (u32 i = 0; i < descriptor.count; i++) - { - u32 mipLevel = descriptor.imageMipLevel + i; - - if (mipLevel < imageDesc.mipLevels) - { - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorView(descriptor.imageID, mipLevel); - imageInfo.sampler = VK_NULL_HANDLE; - } - else - { - // Any imageInfos pointing to mips we don't have should point to the last mip - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorView(descriptor.imageID, imageDesc.mipLevels - 1); - imageInfo.sampler = VK_NULL_HANDLE; - } - } - - builder.BindStorageImage(descriptor.nameHash, imageInfos, static_cast(descriptor.count)); - } - else if (descriptor.descriptorType == DescriptorType::DESCRIPTOR_TYPE_STORAGE_IMAGE_ARRAY) - { - ZoneScopedN("StorageImageArray"); - VkDescriptorImageInfo* imageInfos = Memory::Allocator::NewArray(&_frameAllocator, descriptor.count); - u32 numImageInfos = 0; - - const ImageDesc& imageDesc = _imageHandler->GetImageDesc(descriptor.imageID); - - for (u32 i = 0; i < descriptor.count; i++) - { - u32 mipLevel = descriptor.imageMipLevel + i; - - if (mipLevel < imageDesc.mipLevels) - { - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorArrayView(descriptor.imageID, mipLevel); - imageInfo.sampler = VK_NULL_HANDLE; - } - else - { - // Any imageInfos pointing to mips we don't have should point to the last mip - VkDescriptorImageInfo& imageInfo = imageInfos[numImageInfos++]; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorArrayView(descriptor.imageID, imageDesc.mipLevels - 1); - imageInfo.sampler = VK_NULL_HANDLE; - } - } - - builder.BindStorageImageArray(descriptor.nameHash, imageInfos, static_cast(descriptor.count)); - } - } - void RendererVK::RecreateSwapChain(Backend::SwapChainVK* swapChain) { _device->RecreateSwapChain(_imageHandler, _semaphoreHandler, swapChain); @@ -1502,7 +1386,7 @@ namespace Renderer destroyList.buffers.clear(); } - void RendererVK::BindDescriptorSet(CommandListID commandListID, DescriptorSetSlot slot, Descriptor* descriptors, u32 numDescriptors, const TrackedBufferBitSets* bufferPermissions) + void RendererVK::BindDescriptorSet(CommandListID commandListID, DescriptorSet* descriptorSet, const TrackedBufferBitSets* bufferPermissions) { ZoneScopedNC("RendererVK::BindDescriptorSet", tracy::Color::Red3); @@ -1510,55 +1394,38 @@ namespace Renderer GraphicsPipelineID graphicsPipelineID = _commandListHandler->GetBoundGraphicsPipeline(commandListID); ComputePipelineID computePipelineID = _commandListHandler->GetBoundComputePipeline(commandListID); + DescriptorSetID descriptorSetID = descriptorSet->GetID(); + + VkDescriptorSet vkDescriptorSet = _descriptorHandler->GetVkDescriptorSet(descriptorSetID, _frameIndex); + u32 slot = static_cast(descriptorSet->GetSlot()); + if (graphicsPipelineID != GraphicsPipelineID::Invalid()) { - if (_pipelineHandler->GetNumDescriptorSetLayouts(graphicsPipelineID) <= static_cast(slot)) + /*if (_pipelineHandler->GetNumDescriptorSetLayouts(graphicsPipelineID) <= slot) { return; - } - - Backend::DescriptorSetBuilderVK& builder = _pipelineHandler->GetDescriptorSetBuilder(graphicsPipelineID); - builder.SetBufferPermissions(bufferPermissions); + }*/ - for (u32 i = 0; i < numDescriptors; i++) - { - ZoneScopedNC("BindDescriptor", tracy::Color::Red3); - Descriptor& descriptor = descriptors[i]; - BindDescriptor(builder, descriptor); - } - - VkDescriptorSet descriptorSet = builder.BuildDescriptorSet(static_cast(slot), Backend::DescriptorLifetime::PerFrame); - Backend::DebugMarkerUtilVK::SetObjectName(_device->_device, (u64)descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, DescriptorSetToName(slot)); + // TODO: Validate buffer permissions VkPipelineLayout pipelineLayout = _pipelineHandler->GetPipelineLayout(graphicsPipelineID); // Bind descriptor set - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, slot, 1, &descriptorSet, 0, nullptr); - } + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, slot, 1, &vkDescriptorSet, 0, nullptr); + } else if (computePipelineID != ComputePipelineID::Invalid()) { - if (_pipelineHandler->GetNumDescriptorSetLayouts(computePipelineID) <= static_cast(slot)) + /*if (_pipelineHandler->GetNumDescriptorSetLayouts(computePipelineID) <= slot) { return; - } - - Backend::DescriptorSetBuilderVK& builder = _pipelineHandler->GetDescriptorSetBuilder(computePipelineID); - builder.SetBufferPermissions(bufferPermissions); - - for (u32 i = 0; i < numDescriptors; i++) - { - ZoneScopedNC("BindDescriptor", tracy::Color::Red3); - Descriptor& descriptor = descriptors[i]; - BindDescriptor(builder, descriptor); - } + }*/ - VkDescriptorSet descriptorSet = builder.BuildDescriptorSet(static_cast(slot), Backend::DescriptorLifetime::PerFrame); - Backend::DebugMarkerUtilVK::SetObjectName(_device->_device, (u64)descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, DescriptorSetToName(slot)); + // TODO: Validate buffer permissions VkPipelineLayout pipelineLayout = _pipelineHandler->GetPipelineLayout(computePipelineID); // Bind descriptor set - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, slot, 1, &descriptorSet, 0, nullptr); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, slot, 1, &vkDescriptorSet, 0, nullptr); } } @@ -1572,9 +1439,6 @@ namespace Renderer // Add a marker specifying the frameIndex Backend::DebugMarkerUtilVK::PushMarker(commandBuffer, Color(1,1,1,1), std::to_string(frameIndex)); Backend::DebugMarkerUtilVK::PopMarker(commandBuffer); - - // Free up any old descriptors - _device->_descriptorMegaPool->SetFrame(frameIndex); } #if !TRACY_ENABLE @@ -1799,36 +1663,27 @@ namespace Renderer GraphicsPipelineID graphicsPipelineID = _commandListHandler->GetBoundGraphicsPipeline(commandListID); + VkShaderStageFlags shaderStageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; + VkPipelineLayout layout; + if (graphicsPipelineID != GraphicsPipelineID::Invalid()) { - VkShaderStageFlags shaderStageFlags = 0; - - u32 numPushConstantRanges = _pipelineHandler->GetNumPushConstantRanges(graphicsPipelineID); - for (u32 i = 0; i < numPushConstantRanges; i++) + layout = _pipelineHandler->GetPipelineLayout(graphicsPipelineID); + } + else + { + ComputePipelineID computePipelineID = _commandListHandler->GetBoundComputePipeline(commandListID); + if (computePipelineID != ComputePipelineID::Invalid()) { - const VkPushConstantRange& constantRange = _pipelineHandler->GetPushConstantRange(graphicsPipelineID, i); - - if (offset >= constantRange.offset && offset < constantRange.offset + constantRange.size) - { - shaderStageFlags |= constantRange.stageFlags; - } + layout = _pipelineHandler->GetPipelineLayout(computePipelineID); } - - if (shaderStageFlags == 0) + else { - NC_LOG_CRITICAL("RendererVK::PushConstant : shaderStageFlags was 0, did we try to push a constant that doesn't exist?"); + NC_LOG_CRITICAL("Tried to push constants without a bound graphics or compute pipeline"); + return; } - - VkPipelineLayout layout = _pipelineHandler->GetPipelineLayout(graphicsPipelineID); - vkCmdPushConstants(commandBuffer, layout, shaderStageFlags, offset, size, data); - } - - ComputePipelineID computePipelineID = _commandListHandler->GetBoundComputePipeline(commandListID); - if (computePipelineID != ComputePipelineID::Invalid()) - { - VkPipelineLayout layout = _pipelineHandler->GetPipelineLayout(computePipelineID); - vkCmdPushConstants(commandBuffer, layout, VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, offset, size, data); } + vkCmdPushConstants(commandBuffer, layout, shaderStageFlags, offset, size, data); } void RendererVK::Present(Novus::Window* window, ImageID imageID, SemaphoreID semaphoreID) @@ -1943,55 +1798,32 @@ namespace Renderer BeginRenderPass(commandListID, renderPassDesc); ImageDesc imageDesc = _imageHandler->GetImageDesc(imageID); - ImageComponentType componentType = ToImageComponentType(imageDesc.format); - std::string componentTypeName = ""; - - switch (componentType) - { - case ImageComponentType::FLOAT: - case ImageComponentType::SNORM: - case ImageComponentType::UNORM: - componentTypeName = "float"; - break; - case ImageComponentType::SINT: - componentTypeName = "int"; - break; - case ImageComponentType::UINT: - componentTypeName = "uint"; - break; - - default: - break; - } - - u8 componentCount = ToImageComponentCount(imageDesc.format); - if (componentCount > 1) - { - componentTypeName += std::to_string(componentCount); - } + + std::string componentTypeName = GetTextureTypeName(imageDesc.format); u32 componentTypeNameHash = StringUtils::fnv1a_32(componentTypeName.c_str(), componentTypeName.size()); GraphicsPipelineID pipelineID = GetBlitPipeline(componentTypeNameHash); VkPipelineLayout pipelineLayout = _pipelineHandler->GetPipelineLayout(pipelineID); - Backend::DescriptorSetBuilderVK& builder = _pipelineHandler->GetDescriptorSetBuilder(pipelineID); + + if (!_presentDescriptorSet.IsInitialized()) + { + _presentDescriptorSet.RegisterPipeline(this, pipelineID); + _presentDescriptorSet.Init(this); + } BeginPipeline(commandListID, pipelineID); SetViewport(commandListID, _lastViewport); SetScissorRect(commandListID, _lastScissorRect); - // Set descriptors - VkDescriptorImageInfo samplerInfo = {}; - samplerInfo.sampler = _samplerHandler->GetSampler(samplerID); - builder.BindSampler("_sampler"_h, samplerInfo); - - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.imageView = _imageHandler->GetColorView(imageID); - builder.BindImage("_texture"_h, imageInfo); - - VkDescriptorSet descriptorSet = builder.BuildDescriptorSet(DescriptorSetSlot::PER_PASS, Backend::DescriptorLifetime::PerFrame); + VkSampler vkSampler = _samplerHandler->GetSampler(samplerID); + VkImageView vkImageView = _imageHandler->GetColorView(imageID); + DescriptorSetID descriptorSetID = _presentDescriptorSet.GetID(); + _descriptorHandler->BindDescriptor(descriptorSetID, 0, vkSampler, frameIndex); + _descriptorHandler->BindDescriptor(descriptorSetID, 1, vkImageView, DescriptorType::SampledImage, false, frameIndex); + + VkDescriptorSet descriptorSet = _descriptorHandler->GetVkDescriptorSet(descriptorSetID, _frameIndex); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, DescriptorSetSlot::PER_PASS, 1, &descriptorSet, 0, nullptr); struct BlitConstant @@ -2009,7 +1841,7 @@ namespace Renderer blitConstant.channelRedirectors |= (2 << 16); blitConstant.channelRedirectors |= (3 << 24); - vkCmdPushConstants(commandBuffer, pipelineLayout, VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(BlitConstant), &blitConstant); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(BlitConstant), &blitConstant); vkCmdDraw(commandBuffer, 3, 1, 0, 0); @@ -2224,14 +2056,4 @@ namespace Renderer { return _device->HasExtendedTextureSupport(); } - - void RendererVK::GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, GraphicsPipelineID pipeline, DescriptorSetSlot slot) - { - _pipelineHandler->GetDescriptorMetaFromPipeline(metaInfo, pipeline, slot); - } - - void RendererVK::GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, ComputePipelineID pipeline, DescriptorSetSlot slot) - { - _pipelineHandler->GetDescriptorMetaFromPipeline(metaInfo, pipeline, slot); - } } diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h index a040c1be..5e68c449 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h @@ -1,5 +1,5 @@ #pragma once -#include +#include "Renderer/Renderer.h" #include @@ -12,21 +12,21 @@ namespace Renderer { namespace Backend { - class RenderDeviceVK; + struct BindInfo; class BufferHandlerVK; + class CommandListHandlerVK; + class DescriptorHandlerVK; + class DescriptorSetBuilderVK; class ImageHandlerVK; - class TextureHandlerVK; - class ShaderHandlerVK; class PipelineHandlerVK; - class CommandListHandlerVK; + class RenderDeviceVK; class SamplerHandlerVK; class SemaphoreHandlerVK; - class UploadBufferHandlerVK; - class TimeQueryHandlerVK; - struct BindInfo; - class DescriptorSetBuilderVK; + class ShaderHandlerVK; struct SwapChainVK; - class DescriptorSetBuilderVK; + class TextureHandlerVK; + class TimeQueryHandlerVK; + class UploadBufferHandlerVK; } class RendererVK : public Renderer @@ -60,6 +60,8 @@ namespace Renderer [[nodiscard]] SamplerID CreateSampler(SamplerDesc& desc) override; [[nodiscard]] SemaphoreID CreateNSemaphore() override; + [[nodiscard]] DescriptorSetID CreateDescriptorSet(const DescriptorSetDesc& desc) override; + [[nodiscard]] GraphicsPipelineID CreatePipeline(GraphicsPipelineDesc& desc) override; [[nodiscard]] ComputePipelineID CreatePipeline(ComputePipelineDesc& desc) override; @@ -81,9 +83,22 @@ namespace Renderer // Unloading void UnloadTexture(TextureID textureID) override; void UnloadTexturesInArray(TextureArrayID textureArrayID, u32 unloadStartIndex) override; + + // Descriptor binding + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, BufferID bufferID, DescriptorType type, u32 frameIndex) override; + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, DescriptorType type, u32 frameIndex) override; + void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, ImageID imageID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) override; + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, DescriptorType type, u32 frameIndex) override; + void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, DepthImageID imageID, u32 arrayIndex, DescriptorType type, u32 frameIndex) override; + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 frameIndex) override; + void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, SamplerID samplerID, u32 arrayIndex, u32 frameIndex) override; + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, DescriptorType type, u32 frameIndex) override; + void BindDescriptorArray(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureID textureID, u32 mipLevel, u32 mipCount, DescriptorType type, u32 frameIndex) override; + void BindDescriptor(DescriptorSetID descriptorSetID, u32 bindingIndex, TextureArrayID textureArrayID) override; // Misc u32 AddTextureToArray(TextureID textureID, TextureArrayID textureArrayID) override; + void FlushTextureArrayDescriptors(TextureArrayID textureArrayID) override; // Command List Functions [[nodiscard]] CommandListID BeginCommandList() override; @@ -129,7 +144,7 @@ namespace Renderer void SetIndexBuffer(CommandListID commandListID, BufferID bufferID, IndexFormat indexFormat) override; void SetBuffer(CommandListID commandListID, u32 slot, BufferID buffer) override; - void BindDescriptorSet(CommandListID commandListID, DescriptorSetSlot slot, Descriptor* descriptors, u32 numDescriptors, const TrackedBufferBitSets* bufferPermissions) override; + void BindDescriptorSet(CommandListID commandListID, DescriptorSet* descriptorSet, const TrackedBufferBitSets* bufferPermissions) override; void MarkFrameStart(CommandListID commandListID, u32 frameIndex) override; void BeginTrace(CommandListID commandListID, const tracy::SourceLocationData* sourceLocation) override; @@ -173,18 +188,30 @@ namespace Renderer [[nodiscard]] const std::string& GetTimeQueryName(TimeQueryID id) override; [[nodiscard]] f32 GetLastTimeQueryDuration(TimeQueryID id) override; + // ID to Descriptor + [[nodiscard]] TextureBaseDesc GetDesc(TextureID textureID); + + [[nodiscard]] const ImageDesc& GetDesc(ImageID ID); + [[nodiscard]] const DepthImageDesc& GetDesc(DepthImageID ID); + + [[nodiscard]] const ComputePipelineDesc& GetDesc(ComputePipelineID ID); + [[nodiscard]] const GraphicsPipelineDesc& GetDesc(GraphicsPipelineID ID); + + [[nodiscard]] const ComputeShaderDesc& GetDesc(ComputeShaderID ID); + [[nodiscard]] const VertexShaderDesc& GetDesc(VertexShaderID ID); + [[nodiscard]] const PixelShaderDesc& GetDesc(PixelShaderID ID); + // Utils // Flush will wait until any in-flight frames are done void FlushGPU() override; f32 FlipFrame(u32 frameIndex) override; + [[nodiscard]] u32 GetCurrentFrameIndex() override; + [[nodiscard]] u32 GetFrameIndexCount() override; + void ResetTimeQueries(u32 frameIndex) override; [[nodiscard]] TextureID GetTextureID(TextureArrayID textureArrayID, u32 index) override; - [[nodiscard]] TextureBaseDesc GetTextureDesc(TextureID textureID) override; - - [[nodiscard]] const ImageDesc& GetImageDesc(ImageID ID) override; - [[nodiscard]] const DepthImageDesc& GetImageDesc(DepthImageID ID) override; [[nodiscard]] uvec2 GetImageDimensions(const ImageID id, u32 mipLevel = 0) override; [[nodiscard]] uvec2 GetImageDimensions(const DepthImageID id) override; @@ -208,12 +235,8 @@ namespace Renderer bool HasExtendedTextureSupport() override; - void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, GraphicsPipelineID pipeline, DescriptorSetSlot slot) override; - void GetDescriptorMetaFromPipeline(DescriptorMetaInfo& metaInfo, ComputePipelineID pipeline, DescriptorSetSlot slot) override; - private: [[nodiscard]] bool ReflectDescriptorSet(const std::string& name, u32 nameHash, u32 type, i32& set, const std::vector& bindInfos, u32& outBindInfoIndex, VkDescriptorSetLayoutBinding* outDescriptorLayoutBinding); - void BindDescriptor(Backend::DescriptorSetBuilderVK& builder, Descriptor& descriptor); void RecreateSwapChain(Backend::SwapChainVK* swapChain); void CreateDummyPipeline(); @@ -221,20 +244,22 @@ namespace Renderer private: Backend::RenderDeviceVK* _device = nullptr; Backend::BufferHandlerVK* _bufferHandler = nullptr; + Backend::DescriptorHandlerVK* _descriptorHandler = nullptr; + Backend::CommandListHandlerVK* _commandListHandler = nullptr; Backend::ImageHandlerVK* _imageHandler = nullptr; - Backend::TextureHandlerVK* _textureHandler = nullptr; - Backend::ShaderHandlerVK* _shaderHandler = nullptr; Backend::PipelineHandlerVK* _pipelineHandler = nullptr; - Backend::CommandListHandlerVK* _commandListHandler = nullptr; Backend::SamplerHandlerVK* _samplerHandler = nullptr; Backend::SemaphoreHandlerVK* _semaphoreHandler = nullptr; - Backend::UploadBufferHandlerVK* _uploadBufferHandler = nullptr; + Backend::ShaderHandlerVK* _shaderHandler = nullptr; + Backend::TextureHandlerVK* _textureHandler = nullptr; Backend::TimeQueryHandlerVK* _timeQueryHandler = nullptr; + Backend::UploadBufferHandlerVK* _uploadBufferHandler = nullptr; Memory::StackAllocator _frameAllocator; + u32 _frameIndex = 0; GraphicsPipelineID _globalDummyPipeline = GraphicsPipelineID::Invalid(); - //Backend::DescriptorSetBuilderVK* _descriptorSetBuilder = nullptr; + DescriptorSet _presentDescriptorSet; Viewport _lastViewport; ScissorRect _lastScissorRect; diff --git a/Source/Renderer/Renderer/ShaderEntry.h b/Source/Renderer/Renderer/ShaderEntry.h index b6449c6a..9742f0c2 100644 --- a/Source/Renderer/Renderer/ShaderEntry.h +++ b/Source/Renderer/Renderer/ShaderEntry.h @@ -4,6 +4,8 @@ #include #include +#include + #include namespace Renderer @@ -33,7 +35,10 @@ namespace Renderer { std::string debugName; u32 permutationNameHash; + u8* shaderData = nullptr; u32 shaderSize = 0; + + FileFormat::ShaderReflection reflection; }; } \ No newline at end of file diff --git a/Source/Renderer/Renderer/Window.cpp b/Source/Renderer/Renderer/Window.cpp index 910c4385..1562e336 100644 --- a/Source/Renderer/Renderer/Window.cpp +++ b/Source/Renderer/Renderer/Window.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace Novus @@ -59,7 +60,11 @@ namespace Novus bool Window::Update(f32 deltaTime) { - glfwPollEvents(); + { + ZoneScopedN("glfwPollEvents"); + glfwPollEvents(); + } + if (glfwWindowShouldClose(_window)) { diff --git a/Source/ShaderCooker/ShaderCooker/ShaderCompiler.cpp b/Source/ShaderCooker/ShaderCooker/ShaderCompiler.cpp index 5a9bffe2..29195fb6 100644 --- a/Source/ShaderCooker/ShaderCooker/ShaderCompiler.cpp +++ b/Source/ShaderCooker/ShaderCooker/ShaderCompiler.cpp @@ -164,7 +164,7 @@ namespace ShaderCooker std::string path = itr->make_preferred().string(); if (fs::exists(*itr)) { - if (fs::is_regular_file(*itr) && itr->extension() == ".hlsl") + if (fs::is_regular_file(*itr) && itr->extension() == ".slang") { //std::transform(path.begin(), path.end(), path.begin(), ::tolower); u32 strHash = StringUtils::fnv1a_32(path.c_str(), path.length()); @@ -195,7 +195,10 @@ namespace ShaderCooker shader.fileBufferSize = shader.source.length(); if (!Lexer::Process(shader) || !Parser::CheckSyntax(shader) || !Parser::ResolveIncludes(this, shader)) + { _shaders.pop_back(); + _numFailedShaders++; + } else _shaderHashToIndex[strHash] = static_cast(_shaders.size() - 1); } @@ -260,7 +263,7 @@ namespace ShaderCooker if (!shader.hasResolvedIncludes) continue; - if (StringUtils::EndsWith(shader.name, ".inc.hlsl")) + if (StringUtils::EndsWith(shader.name, ".inc.slang")) { _shaderCache->Touch(shader.path); continue; @@ -415,21 +418,26 @@ namespace ShaderCooker void ShaderCompiler::GetPermutationFilename(const Shader& shader, u32 permutationID, const std::string& inputFileName, std::string& filename) { filename = inputFileName; - size_t offset = filename.find_first_of('.'); + // Strip .slang from the extension + size_t offset = filename.find_last_of('.'); + filename = filename.substr(0, offset); + + // Extract the .ps/.vs/.cs into its own string + offset = filename.find_first_of('.'); std::string extension = filename.substr(offset); filename = filename.substr(0, offset); + // Add permutation data to the filename const Permutation& permutation = shader.permutations[permutationID]; - for (u32 i = 0; i < permutation.defines.size(); i++) { const Define& define = permutation.defines[i]; filename += "-" + define.name + define.value; } + // Add back the extension (without .slang) filename += extension; std::replace(filename.begin(), filename.end(), '\\', '/'); } - } diff --git a/Source/ShaderCooker/ShaderCooker/SlangBridge.cpp b/Source/ShaderCooker/ShaderCooker/SlangBridge.cpp index 144556a3..55242ceb 100644 --- a/Source/ShaderCooker/ShaderCooker/SlangBridge.cpp +++ b/Source/ShaderCooker/ShaderCooker/SlangBridge.cpp @@ -231,6 +231,206 @@ namespace ShaderCooker return StringUtils::fnv1a_32(shaderPath.string().c_str(), shaderPath.string().length()); } + FileFormat::DescriptorTypeReflection GetDescriptorTypeReflection(slang::TypeLayoutReflection* typeLayout, u32& count) + { + slang::TypeReflection::Kind kind = typeLayout->getKind(); + switch (kind) + { + case slang::TypeReflection::Kind::ConstantBuffer: + { + return FileFormat::DescriptorTypeReflection::ConstantBuffer; + } + case slang::TypeReflection::Kind::SamplerState: + { + return FileFormat::DescriptorTypeReflection::SamplerState; + } + case slang::TypeReflection::Kind::Resource: + { + SlangResourceShape shape = typeLayout->getResourceShape(); + + switch (shape) + { + case SlangResourceShape::SLANG_BYTE_ADDRESS_BUFFER: + return FileFormat::DescriptorTypeReflection::ByteAddressBuffer; + case SlangResourceShape::SLANG_STRUCTURED_BUFFER: + return FileFormat::DescriptorTypeReflection::StructuredBuffer; + case SlangResourceShape::SLANG_TEXTURE_1D: + case SlangResourceShape::SLANG_TEXTURE_2D: + case SlangResourceShape::SLANG_TEXTURE_3D: + case SlangResourceShape::SLANG_TEXTURE_CUBE: + return FileFormat::DescriptorTypeReflection::Texture; + case SlangResourceShape::SLANG_TEXTURE_1D_ARRAY: + case SlangResourceShape::SLANG_TEXTURE_2D_ARRAY: + case SlangResourceShape::SLANG_TEXTURE_CUBE_ARRAY: + return FileFormat::DescriptorTypeReflection::TextureArray; + default: + NC_LOG_CRITICAL("Unsupported resource shape {0} in GetDescriptorTypeReflection", static_cast(shape)); + } + break; + } + case slang::TypeReflection::Kind::Array: + { + size_t elementCount = typeLayout->getElementCount(); + if (elementCount == ~size_t(0)) + { + // Unbounded array + count = 0; // 0 means it's gonna be unbounded + } + else + { + count = static_cast(elementCount); + } + return FileFormat::DescriptorTypeReflection::Array; + } + } + + NC_LOG_CRITICAL("Unsupported type kind {0} in GetDescriptorTypeReflection", static_cast(kind)); + return FileFormat::DescriptorTypeReflection::Unknown; + } + + FileFormat::DescriptorAccessTypeReflection ToAccessType(SlangResourceAccess access) + { + switch(access) + { + case SLANG_RESOURCE_ACCESS_NONE: + return FileFormat::DescriptorAccessTypeReflection::None; + case SLANG_RESOURCE_ACCESS_READ: + return FileFormat::DescriptorAccessTypeReflection::Read; + case SLANG_RESOURCE_ACCESS_READ_WRITE: + return FileFormat::DescriptorAccessTypeReflection::ReadWrite; + case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: + return FileFormat::DescriptorAccessTypeReflection::RasterOrdered; + case SLANG_RESOURCE_ACCESS_APPEND: + return FileFormat::DescriptorAccessTypeReflection::Append; + case SLANG_RESOURCE_ACCESS_CONSUME: + return FileFormat::DescriptorAccessTypeReflection::Consume; + case SLANG_RESOURCE_ACCESS_WRITE: + return FileFormat::DescriptorAccessTypeReflection::Write; + case SLANG_RESOURCE_ACCESS_FEEDBACK: + return FileFormat::DescriptorAccessTypeReflection::Feedback; + } + + return FileFormat::DescriptorAccessTypeReflection::None; + } + + bool ReflectDescriptors(slang::ProgramLayout* programLayout, Slang::ComPtr entryPointMetadata, FileFormat::ShaderReflection& out) + { + SlangResult result; + bool success = true; + + u32 parameterCount = programLayout->getParameterCount(); + + for (u32 i = 0; i < parameterCount; i++) + { + slang::VariableLayoutReflection* variableLayout = programLayout->getParameterByIndex(i); + slang::TypeLayoutReflection* typeLayout = variableLayout->getTypeLayout(); + + u32 slot = variableLayout->getBindingSpace(); + const char* name = variableLayout->getName(); + u32 binding = variableLayout->getBindingIndex(); + FileFormat::DescriptorAccessTypeReflection accessType = ToAccessType(typeLayout->getResourceAccess()); + bool isUsed; + u32 byteOffset = 0; + u32 byteSize = 0; + + if (slot == 4) + { + volatile int asd = 123; + } + + SlangParameterCategory category = static_cast(variableLayout->getCategory()); + result = entryPointMetadata->isParameterLocationUsed(category, slot, binding, isUsed); + NC_ASSERT(SLANG_SUCCEEDED(result), "Failed to get parameter usage from metadata"); + + u32 count = 1; + FileFormat::DescriptorTypeReflection type = GetDescriptorTypeReflection(typeLayout, count); + FileFormat::DescriptorTypeReflection subType = FileFormat::DescriptorTypeReflection::Unknown; + + // Get byteOffset and byteSize for ConstantBuffer types (push constants) + if (type == FileFormat::DescriptorTypeReflection::ConstantBuffer) + { + byteOffset = static_cast(variableLayout->getOffset(slang::ParameterCategory::Uniform)); + slang::TypeLayoutReflection* elementTypeLayout = typeLayout->getElementTypeLayout(); + if (elementTypeLayout) + { + byteSize = static_cast(elementTypeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM)); + } + } + + if (slot == 0) + { + if (type != FileFormat::DescriptorTypeReflection::ConstantBuffer) + { + // Slot 0 is reserved for push constants + NC_LOG_ERROR("Descriptor found in slot 0 which is reserved for push constants: {0} (binding {1})\n You probably wanted to use the PER_PASS or PER_DRAW macros", name, binding); + success = false; + continue; + } + if (byteSize == 0) + { + // Slot 0 is reserved for push constants + NC_LOG_ERROR("Push constant buffer has size 0: {0} (binding {1})", name, binding); + success = false; + continue; + } + } + + // Get the subtype if this is an array + if (type == FileFormat::DescriptorTypeReflection::Array) + { + slang::TypeLayoutReflection* elementTypeLayout = typeLayout->getElementTypeLayout(); + subType = GetDescriptorTypeReflection(elementTypeLayout, count); + } + + FileFormat::DescriptorSetReflection& descriptorSet = out.GetDescriptorSetBySlot(slot); + if (descriptorSet.descriptors.contains(binding)) + { + // Make sure the existing descriptor matches + FileFormat::DescriptorReflection& existingDescriptor = descriptorSet.descriptors[binding]; + + if (existingDescriptor.name != name || + existingDescriptor.type != type || + existingDescriptor.subType != subType || + existingDescriptor.count != count || + existingDescriptor.accessType != accessType || + existingDescriptor.isUsed != isUsed || + existingDescriptor.byteOffset != byteOffset || + existingDescriptor.byteSize != byteSize) + { + std::string existingDescriptorStr = existingDescriptor.ToString(); + std::string newDescriptorStr = FileFormat::DescriptorReflection{ .binding = binding, .name = name, .type = type, .subType = subType, .count = count }.ToString(); + NC_LOG_ERROR("Descriptor binding conflict at slot {0}, binding {1}:\nExisting: {2}\nNew: {3}", + slot, + binding, + existingDescriptorStr.c_str(), + newDescriptorStr.c_str()); + + success = false; + } + } + else + { + // New binding + FileFormat::DescriptorReflection descriptor; + descriptor.binding = binding; + descriptor.name = name; + descriptor.type = type; + descriptor.subType = subType; + descriptor.count = count; + descriptor.accessType = accessType; + descriptor.isUsed = isUsed; + descriptor.byteOffset = byteOffset; + descriptor.byteSize = byteSize; + + // TODO: Check so we don't have implicit padding (explicit padding is fine) + + descriptorSet.descriptors[binding] = descriptor; + } + } + + return success; + } + bool SlangBridge::Compile(std::filesystem::path path, const std::string& source, FileFormat::ShaderInMemory& shaderInMemory) { SlangBridgeData* data = static_cast(_data); @@ -246,9 +446,9 @@ namespace ShaderCooker // Set up defines std::vector defines; defines.reserve(32); - defines.push_back({ "DEBUG", "0" }); - defines.push_back({ "GLOBAL", "1" }); - defines.push_back({ "TILES", "2" }); + // 1 indexed because we let 0 be the push constants, it's not technically correct but we get nice error checking if we do this + defines.push_back({ "DEBUG", "1" }); + defines.push_back({ "GLOBAL", "2" }); defines.push_back({ "LIGHT", "3" }); defines.push_back({ "TERRAIN", "4" }); defines.push_back({ "MODEL", "5" }); @@ -359,6 +559,25 @@ namespace ShaderCooker return false; } + Slang::ComPtr entryPointMetadata; + result = linkedProgram->getEntryPointMetadata(0, 0, entryPointMetadata.writeRef(), data->diagnostics.writeRef()); + if (data->diagnostics) + { + std::string diagStr = { (char*)data->diagnostics->getBufferPointer(), data->diagnostics->getBufferSize() }; + NC_LOG_ERROR("[Slang] Get Entrypoint metadata: {0} ({1})", diagStr.c_str(), path.string().c_str()); + } + if (!SLANG_SUCCEEDED(result)) + { + NC_LOG_ERROR("[Slang] Failed to get entrypoint metadata ({0})", path.string().c_str()); + return false; + } + + // Reflect descriptors + if (!ReflectDescriptors(programLayout, entryPointMetadata, shaderInMemory.reflection)) + { + return false; + } + // Copy to output blob shaderInMemory.data = new u8[kernelBlob->getBufferSize()]; memcpy(shaderInMemory.data, kernelBlob->getBufferPointer(), kernelBlob->getBufferSize()); @@ -386,22 +605,22 @@ namespace ShaderCooker } } - // We expect filename to end with .XX.hlsl where XX is the profile of the shader, for example vs for vertex shader, ps for pixel shader, cs for compute etc - // First we remove the .hlsl part of the name - fs::path withoutHlsl = filename.replace_extension(); + // We expect filename to end with .XX.slang where XX is the profile of the shader, for example vs for vertex shader, ps for pixel shader, cs for compute etc + // First we remove the .slang part of the name + fs::path withoutSlang = filename.replace_extension(); - if (!withoutHlsl.has_extension()) + if (!withoutSlang.has_extension()) { - NC_LOG_ERROR("Filename \"{0}\" should end with .XX.hlsl where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); + NC_LOG_ERROR("Filename \"{0}\" should end with .XX.slang where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); return false; } - std::string extension = withoutHlsl.extension().string().substr(1); // Get the extension (.vs) as a string, then remove the first char which will be the "." + std::string extension = withoutSlang.extension().string().substr(1); // Get the extension (.vs) as a string, then remove the first char which will be the "." if (extension.length() != 2 && extension.length() != 3) { - NC_LOG_ERROR("Filename \"{0}\" should end with .XX.hlsl where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); + NC_LOG_ERROR("Filename \"{0}\" should end with .XX.slang where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); return false; } @@ -419,7 +638,7 @@ namespace ShaderCooker if (!isValidProfile) { - NC_LOG_ERROR("Filename \"{0}\" should end with .XX.hlsl where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); + NC_LOG_ERROR("Filename \"{0}\" should end with .XX.slang where XX is one of these valid profiles depending on shader type: {1}", filename.string(), validProfiles); return false; }