diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 4fbb9df41..e940083dd 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -1440,7 +1440,8 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta // consider it filled if any array element is filled (or it's push constants) bool filledSlot = cblock != NULL && !cblock->bufferBacked; for(int idx = 0; slotBinds != NULL && idx < slotBinds->count(); idx++) - filledSlot |= (*slotBinds)[idx].resourceResourceId != ResourceId(); + filledSlot |= + (*slotBinds)[idx].resourceResourceId != ResourceId() || (*slotBinds)[idx].inlineBlock; // if it's masked out by stage bits, act as if it's not filled, so it's marked in red if(!stageBitsIncluded) @@ -1541,6 +1542,12 @@ void VulkanPipelineStateViewer::addConstantBlockRow(ShaderReflection *shaderDeta } else { + if(descriptorBind && descriptorBind->inlineBlock) + { + name = tr("Inline block"); + vecrange = tr("%1 bytes").arg(length); + } + if(length == byteSize) sizestr = tr("%1 Variables, %2 bytes").arg(numvars).arg(length); else diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index fd2def19f..f400c61a9 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -40,15 +40,16 @@ struct BindingElement { return dynamicallyUsed == o.dynamicallyUsed && viewResourceId == o.viewResourceId && resourceResourceId == o.resourceResourceId && samplerResourceId == o.samplerResourceId && - immutableSampler == o.immutableSampler && viewFormat == o.viewFormat && - swizzle == o.swizzle && firstMip == o.firstMip && firstSlice == o.firstSlice && - numMips == o.numMips && numSlices == o.numSlices && byteOffset == o.byteOffset && - byteSize == o.byteSize && filter == o.filter && addressU == o.addressU && - addressV == o.addressV && addressW == o.addressW && mipBias == o.mipBias && - maxAnisotropy == o.maxAnisotropy && compareFunction == o.compareFunction && - minLOD == o.minLOD && maxLOD == o.maxLOD && borderColor[0] == o.borderColor[0] && - borderColor[1] == o.borderColor[1] && borderColor[2] == o.borderColor[2] && - borderColor[3] == o.borderColor[3] && unnormalized == o.unnormalized; + immutableSampler == o.immutableSampler && inlineBlock == o.inlineBlock && + viewFormat == o.viewFormat && swizzle == o.swizzle && firstMip == o.firstMip && + firstSlice == o.firstSlice && numMips == o.numMips && numSlices == o.numSlices && + byteOffset == o.byteOffset && byteSize == o.byteSize && filter == o.filter && + addressU == o.addressU && addressV == o.addressV && addressW == o.addressW && + mipBias == o.mipBias && maxAnisotropy == o.maxAnisotropy && + compareFunction == o.compareFunction && minLOD == o.minLOD && maxLOD == o.maxLOD && + borderColor[0] == o.borderColor[0] && borderColor[1] == o.borderColor[1] && + borderColor[2] == o.borderColor[2] && borderColor[3] == o.borderColor[3] && + unnormalized == o.unnormalized; } bool operator<(const BindingElement &o) const { @@ -62,6 +63,8 @@ struct BindingElement return samplerResourceId < o.samplerResourceId; if(!(immutableSampler == o.immutableSampler)) return immutableSampler < o.immutableSampler; + if(!(inlineBlock == o.inlineBlock)) + return inlineBlock < o.inlineBlock; if(!(viewFormat == o.viewFormat)) return viewFormat < o.viewFormat; if(!(swizzle == o.swizzle)) @@ -170,6 +173,9 @@ since single descriptors may only be dynamically skipped by control flow. DOCUMENT("For samplers - ``True`` if unnormalized co-ordinates are used in this sampler."); bool unnormalized = false; + DOCUMENT("``True`` if this is an inline uniform block binding."); + bool inlineBlock = false; + DOCUMENT(R"(For samplers - the :class:`ResourceId` of the ycbcr conversion object associated with this sampler. )"); diff --git a/renderdoc/driver/vulkan/vk_bindless_feedback.cpp b/renderdoc/driver/vulkan/vk_bindless_feedback.cpp index 885c35961..272f46d46 100644 --- a/renderdoc/driver/vulkan/vk_bindless_feedback.cpp +++ b/renderdoc/driver/vulkan/vk_bindless_feedback.cpp @@ -597,7 +597,8 @@ void VulkanReplay::FetchShaderFeedback(uint32_t eventId) continue; // only process array bindings - if(bindData.descriptorCount > 1) + if(bindData.descriptorCount > 1 && + bindData.descriptorType != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) { key.binding = (uint32_t)binding; diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 7bd23b4e1..88b53b4e2 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -321,6 +321,10 @@ bool VkInitParams::IsSupportedVersion(uint64_t ver) if(ver == CurrentVersion) return true; + // 0x11 -> 0x12 - added inline uniform block support + if(ver == 0x11) + return true; + // 0x10 -> 0x11 - non-breaking changes to image state serialization if(ver == 0x10) return true; @@ -957,6 +961,7 @@ FrameRefType GetRefType(VkDescriptorType descType) case VK_DESCRIPTOR_TYPE_SAMPLER: case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: @@ -973,6 +978,9 @@ FrameRefType GetRefType(VkDescriptorType descType) bool IsValid(const VkWriteDescriptorSet &write, uint32_t arrayElement) { + if(write.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + return true; + // this makes assumptions that only hold within the context of Serialise_InitialState below, // specifically that if pTexelBufferView/pBufferInfo is set then we are using them. In the general // case they can be garbage and we must ignore them based on the descriptorType diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 2cdf5ac4b..fc728339f 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -441,6 +441,9 @@ struct DescriptorSetSlot DescriptorSetSlotImageInfo imageInfo; ResourceId texelBufferView; + + // inline uniform block + uint32_t inlineOffset; }; DECLARE_REFLECTION_STRUCT(DescriptorSetSlotBufferInfo); @@ -694,6 +697,7 @@ DECLARE_REFLECTION_STRUCT(VkDedicatedAllocationBufferCreateInfoNV); DECLARE_REFLECTION_STRUCT(VkDedicatedAllocationImageCreateInfoNV); DECLARE_REFLECTION_STRUCT(VkDedicatedAllocationMemoryAllocateInfoNV); DECLARE_REFLECTION_STRUCT(VkDescriptorPoolCreateInfo); +DECLARE_REFLECTION_STRUCT(VkDescriptorPoolInlineUniformBlockCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkDescriptorSetAllocateInfo); DECLARE_REFLECTION_STRUCT(VkDescriptorSetLayoutBindingFlagsCreateInfo) DECLARE_REFLECTION_STRUCT(VkDescriptorSetLayoutCreateInfo); @@ -810,6 +814,8 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImageFormatInfo2); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImagelessFramebufferFeatures); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImageViewImageFormatInfoEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceIndexTypeUint8FeaturesEXT); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceInlineUniformBlockFeaturesEXT); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceInlineUniformBlockPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceLineRasterizationFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceLineRasterizationPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceMaintenance3Properties); @@ -942,6 +948,7 @@ DECLARE_REFLECTION_STRUCT(VkValidationCacheCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkValidationFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkValidationFlagsEXT); DECLARE_REFLECTION_STRUCT(VkWriteDescriptorSet); +DECLARE_REFLECTION_STRUCT(VkWriteDescriptorSetInlineUniformBlockEXT); DECLARE_DESERIALISE_TYPE(VkAcquireNextImageInfoKHR); DECLARE_DESERIALISE_TYPE(VkAcquireProfilingLockInfoKHR); @@ -985,6 +992,7 @@ DECLARE_DESERIALISE_TYPE(VkDedicatedAllocationBufferCreateInfoNV); DECLARE_DESERIALISE_TYPE(VkDedicatedAllocationImageCreateInfoNV); DECLARE_DESERIALISE_TYPE(VkDedicatedAllocationMemoryAllocateInfoNV); DECLARE_DESERIALISE_TYPE(VkDescriptorPoolCreateInfo); +DECLARE_DESERIALISE_TYPE(VkDescriptorPoolInlineUniformBlockCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkDescriptorSetAllocateInfo); DECLARE_DESERIALISE_TYPE(VkDescriptorSetLayoutBindingFlagsCreateInfo) DECLARE_DESERIALISE_TYPE(VkDescriptorSetLayoutCreateInfo); @@ -1097,6 +1105,8 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceImageFormatInfo2); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceImagelessFramebufferFeatures); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceImageViewImageFormatInfoEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceIndexTypeUint8FeaturesEXT); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceInlineUniformBlockFeaturesEXT); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceInlineUniformBlockPropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceLineRasterizationFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceLineRasterizationPropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceMaintenance3Properties); @@ -1226,6 +1236,7 @@ DECLARE_DESERIALISE_TYPE(VkValidationCacheCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkValidationFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkValidationFlagsEXT); DECLARE_DESERIALISE_TYPE(VkWriteDescriptorSet); +DECLARE_DESERIALISE_TYPE(VkWriteDescriptorSetInlineUniformBlockEXT); // plain structs with no next chain DECLARE_REFLECTION_STRUCT(VkAllocationCallbacks); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 38280ff54..7a92cf1b3 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -826,6 +826,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION, }, + { + VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION, + }, { VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, VK_EXT_LINE_RASTERIZATION_SPEC_VERSION, }, @@ -3922,6 +3925,10 @@ void WrappedVulkan::AddUsage(VulkanDrawcallTreeNode &drawNode, rdcarray= (int32_t)descset.currentBindings.size()) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 38956f626..da9b187c5 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -53,7 +53,7 @@ struct VkInitParams uint64_t GetSerialiseSize(); // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x11; + static const uint64_t CurrentVersion = 0x12; static bool IsSupportedVersion(uint64_t ver); }; @@ -691,11 +691,12 @@ private: struct DescriptorSetInfo { DescriptorSetInfo(bool p = false) : push(p) {} - DescriptorSetInfo(const DescriptorSetInfo &) = default; - DescriptorSetInfo &operator=(const DescriptorSetInfo &) = default; + DescriptorSetInfo(const DescriptorSetInfo &) = delete; + DescriptorSetInfo &operator=(const DescriptorSetInfo &) = delete; ~DescriptorSetInfo() { clear(); } ResourceId layout; rdcarray currentBindings; + bytebuf inlineData; bool push; void clear() @@ -704,6 +705,7 @@ private: for(size_t i = 0; i < currentBindings.size(); i++) delete[] currentBindings[i]; + inlineData.clear(); currentBindings.clear(); } }; @@ -999,6 +1001,10 @@ public: { return m_DescriptorSetState[descSet].currentBindings; } + const bytebuf &GetCurrentDescSetInlineData(ResourceId descSet) + { + return m_DescriptorSetState[descSet].inlineData; + } uint32_t GetReadbackMemoryIndex(uint32_t resourceCompatibleBitmask); uint32_t GetUploadMemoryIndex(uint32_t resourceCompatibleBitmask); diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index fe10dd7db..92d248a35 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -1705,20 +1705,25 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, delete[] a; for(VkBufferView *a : bufViewWrites) delete[] a; + for(VkWriteDescriptorSetInlineUniformBlockEXT *a : inlineWrites) + delete a; } rdcarray imgWrites; rdcarray bufWrites; rdcarray bufViewWrites; + rdcarray inlineWrites; } alloced; rdcarray &allocImgWrites = alloced.imgWrites; rdcarray &allocBufWrites = alloced.bufWrites; rdcarray &allocBufViewWrites = alloced.bufViewWrites; + rdcarray &allocInlineWrites = alloced.inlineWrites; + // one for each descriptor type. 1 of each to start with, we then increment for each descriptor // we need to allocate - VkDescriptorPoolSize poolSizes[11] = { + VkDescriptorPoolSize poolSizes[12] = { {VK_DESCRIPTOR_TYPE_SAMPLER, 1}, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}, {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1}, @@ -1730,11 +1735,23 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1}, {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1}, + {VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, 0}, }; + VkDescriptorPoolInlineUniformBlockCreateInfoEXT inlineCreateInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT, + }; + + static const uint32_t InlinePoolIndex = 11; + + uint32_t poolSizeCount = InlinePoolIndex; + // count up our own for(size_t i = 0; i < newBindingsCount; i++) + { + RDCASSERT(newBindings[i].descriptorType < ARRAY_COUNT(poolSizes), newBindings[i].descriptorType); poolSizes[newBindings[i].descriptorType].descriptorCount += newBindings[i].descriptorCount; + } const rdcarray &pipeDescSetLayouts = creationInfo.m_PipelineLayout[pipeInfo.layout].descSetLayouts; @@ -1827,19 +1844,38 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, uint32_t maxDescriptorSetInputAttachments = m_pDriver->GetDeviceProps().limits.maxDescriptorSetInputAttachments; + uint32_t maxDescriptorSetInlineUniformBlocks = 0; + uint32_t maxPerStageDescriptorInlineUniformBlocks[6] = {}; + + if(m_pDriver->GetExtensions(NULL).ext_EXT_inline_uniform_block) + { + VkPhysicalDeviceInlineUniformBlockPropertiesEXT inlineProps = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, + }; + + VkPhysicalDeviceProperties2 availBase = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + availBase.pNext = &inlineProps; + m_pDriver->vkGetPhysicalDeviceProperties2(m_pDriver->GetPhysDev(), &availBase); + + maxDescriptorSetInlineUniformBlocks = inlineProps.maxDescriptorSetInlineUniformBlocks; + for(size_t i = 0; i < ARRAY_COUNT(maxPerStageDescriptorInlineUniformBlocks); i++) + maxPerStageDescriptorInlineUniformBlocks[i] = + inlineProps.maxPerStageDescriptorInlineUniformBlocks; + } + bool error = false; #define UPDATE_AND_CHECK_LIMIT(maxLimit) \ if(!error) \ { \ - if(bind.descriptorCount > maxLimit) \ + if(descriptorCount > maxLimit) \ { \ error = true; \ RDCWARN("Limit %s is exceeded. Cannot patch in required descriptor(s).", #maxLimit); \ } \ else \ { \ - maxLimit -= bind.descriptorCount; \ + maxLimit -= descriptorCount; \ } \ } @@ -1850,14 +1886,14 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, { \ if(newBind.stageFlags & (1U << sbit)) \ { \ - if(bind.descriptorCount > maxLimit[sbit]) \ + if(descriptorCount > maxLimit[sbit]) \ { \ error = true; \ RDCWARN("Limit %s is exceeded. Cannot patch in required descriptor(s).", #maxLimit); \ } \ else \ { \ - maxLimit[sbit] -= bind.descriptorCount; \ + maxLimit[sbit] -= descriptorCount; \ } \ } \ } \ @@ -1895,7 +1931,15 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, continue; // make room in the pool - poolSizes[bind.descriptorType].descriptorCount += bind.descriptorCount; + if(bind.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + poolSizes[InlinePoolIndex].descriptorCount += bind.descriptorCount; + inlineCreateInfo.maxInlineUniformBlockBindings++; + } + else + { + poolSizes[bind.descriptorType].descriptorCount += bind.descriptorCount; + } VkDescriptorSetLayoutBinding newBind; // offset the binding. We offset all sets to make it easier for patching - don't need to @@ -1917,6 +1961,8 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, else newBind.stageFlags = bind.stageFlags; + uint32_t descriptorCount = bind.descriptorCount; + switch(bind.descriptorType) { case VK_DESCRIPTOR_TYPE_SAMPLER: @@ -1965,6 +2011,11 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, UPDATE_AND_CHECK_LIMIT(maxDescriptorSetInputAttachments); UPDATE_AND_CHECK_STAGE_LIMIT(maxPerStageDescriptorInputAttachments); break; + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + descriptorCount = 1; + UPDATE_AND_CHECK_LIMIT(maxDescriptorSetInlineUniformBlocks); + UPDATE_AND_CHECK_STAGE_LIMIT(maxPerStageDescriptorInlineUniformBlocks); + break; default: break; } @@ -2017,9 +2068,15 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, // 1 set for each layout poolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; poolCreateInfo.maxSets = (uint32_t)setLayouts.size(); - poolCreateInfo.poolSizeCount = ARRAY_COUNT(poolSizes); + poolCreateInfo.poolSizeCount = poolSizeCount; poolCreateInfo.pPoolSizes = poolSizes; + if(inlineCreateInfo.maxInlineUniformBlockBindings > 0) + { + poolCreateInfo.poolSizeCount++; + poolCreateInfo.pNext = &inlineCreateInfo; + } + // create descriptor pool with enough space for our descriptors vkr = m_pDriver->vkCreateDescriptorPool(dev, &poolCreateInfo, NULL, &descpool); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2126,9 +2183,29 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, allocBufWrites.push_back(out); break; } + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + { + allocInlineWrites.push_back(new VkWriteDescriptorSetInlineUniformBlockEXT); + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = allocInlineWrites.back(); + inlineWrite->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + inlineWrite->pNext = NULL; + inlineWrite->dataSize = bind.descriptorCount; + inlineWrite->pData = setInfo.inlineData.data() + slot->inlineOffset; + write.pNext = inlineWrite; + break; + } default: RDCERR("Unexpected descriptor type %d", write.descriptorType); } + // skip validity check for inline uniform block as the descriptor count means something + // different + if(write.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + write.descriptorCount = bind.descriptorCount; + descWrites.push_back(write); + continue; + } + // start with no descriptors write.descriptorCount = 0; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index d1f37bb97..cd3c808d8 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -489,7 +489,8 @@ DeclExt(KHR_performance_query); \ DeclExt(KHR_buffer_device_address); \ DeclExt(EXT_tooling_info); \ - DeclExt(KHR_separate_depth_stencil_layouts); + DeclExt(KHR_separate_depth_stencil_layouts); \ + DeclExt(EXT_inline_uniform_block); // for simplicity and since the check itself is platform agnostic, // these aren't protected in platform defines @@ -580,7 +581,8 @@ CheckExt(KHR_performance_query, VKXX); \ CheckExt(KHR_buffer_device_address, VK12); \ CheckExt(EXT_tooling_info, VKXX); \ - CheckExt(KHR_separate_depth_stencil_layouts, VK12); + CheckExt(KHR_separate_depth_stencil_layouts, VK12); \ + CheckExt(EXT_inline_uniform_block, VKXX); #define HookInitVulkanInstanceExts_PhysDev() \ HookInitExtension(KHR_surface, GetPhysicalDeviceSurfaceSupportKHR); \ diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 9681b715f..31439dd3c 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -88,6 +88,8 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo const VkDescriptorSetLayoutCreateInfo *pCreateInfo) { dynamicCount = 0; + inlineCount = 0; + inlineByteSize = 0; flags = pCreateInfo->flags; @@ -114,6 +116,12 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) dynamicCount++; + if(bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + inlineCount++; + inlineByteSize = AlignUp4(inlineByteSize + bindings[b].descriptorCount); + } + if((bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || bindings[b].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) && pCreateInfo->pBindings[i].pImmutableSamplers) @@ -126,42 +134,70 @@ void DescSetLayout::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo } } -void DescSetLayout::CreateBindingsArray(rdcarray &descBindings) const +void DescSetLayout::CreateBindingsArray(bytebuf &inlineData, + rdcarray &descBindings) const { + uint32_t inlineOffset = 0; descBindings.resize(bindings.size()); for(size_t i = 0; i < bindings.size(); i++) { - descBindings[i] = new DescriptorSetSlot[bindings[i].descriptorCount]; - memset(descBindings[i], 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount); + if(bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + descBindings[i] = new DescriptorSetSlot[1]; + memset(descBindings[i], 0, sizeof(DescriptorSetSlot)); + descBindings[i]->inlineOffset = inlineOffset; + inlineOffset = AlignUp4(inlineOffset + bindings[i].descriptorCount); + } + else + { + descBindings[i] = new DescriptorSetSlot[bindings[i].descriptorCount]; + memset(descBindings[i], 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount); + } } + + inlineData.resize(inlineByteSize); } -void DescSetLayout::UpdateBindingsArray(const DescSetLayout &prevLayout, +void DescSetLayout::UpdateBindingsArray(const DescSetLayout &prevLayout, bytebuf &inlineData, rdcarray &descBindings) const { // if we have fewer bindings now, delete the orphaned bindings arrays for(size_t i = bindings.size(); i < prevLayout.bindings.size(); i++) SAFE_DELETE_ARRAY(descBindings[i]); + inlineData.resize(inlineByteSize); + // resize to the new number of bindings descBindings.resize(bindings.size()); + uint32_t inlineOffset = 0; // re-allocate slots and move any previous bindings that overlapped over. for(size_t i = 0; i < bindings.size(); i++) { - // allocate new slot array - DescriptorSetSlot *newSlots = new DescriptorSetSlot[bindings[i].descriptorCount]; - memset(newSlots, 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount); + if(bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + SAFE_DELETE_ARRAY(descBindings[i]); + descBindings[i] = new DescriptorSetSlot[1]; + memset(descBindings[i], 0, sizeof(DescriptorSetSlot)); + descBindings[i]->inlineOffset = inlineOffset; + inlineOffset = AlignUp4(inlineOffset + bindings[i].descriptorCount); + } + else + { + // allocate new slot array + DescriptorSetSlot *newSlots = new DescriptorSetSlot[bindings[i].descriptorCount]; + memset(newSlots, 0, sizeof(DescriptorSetSlot) * bindings[i].descriptorCount); - // copy over any previous bindings that overlapped - if(i < prevLayout.bindings.size()) - memcpy(newSlots, descBindings[i], - sizeof(DescriptorSetSlot) * - RDCMIN(prevLayout.bindings[i].descriptorCount, bindings[i].descriptorCount)); + // copy over any previous bindings that overlapped + if(i < prevLayout.bindings.size()) + memcpy(newSlots, descBindings[i], + sizeof(DescriptorSetSlot) * + RDCMIN(prevLayout.bindings[i].descriptorCount, bindings[i].descriptorCount)); - // delete old array, and assign the new one - SAFE_DELETE_ARRAY(descBindings[i]); - descBindings[i] = newSlots; + // delete old array, and assign the new one + SAFE_DELETE_ARRAY(descBindings[i]); + descBindings[i] = newSlots; + } } } @@ -1118,7 +1154,7 @@ void DescUpdateTemplate::Init(VulkanResourceManager *resourceMan, VulkanCreation bindPoint = pCreateInfo->pipelineBindPoint; - dataByteSize = 0; + unwrapByteSize = 0; texelBufferViewCount = 0; bufferInfoCount = 0; @@ -1128,6 +1164,8 @@ void DescUpdateTemplate::Init(VulkanResourceManager *resourceMan, VulkanCreation { uint32_t entrySize = 4; + size_t stride = entry.stride; + if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { @@ -1145,6 +1183,19 @@ void DescUpdateTemplate::Init(VulkanResourceManager *resourceMan, VulkanCreation imageInfoCount += entry.descriptorCount; } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // a bit of magic handling. The calculation is stride * descriptorCount bytes for the data, + // plus the size of the 'base' structure. For inline uniform blocks there's no base structure + // and the data is in bytes, so stride 1. + stride = 1; + + entrySize = 0; + + inlineInfoCount++; + inlineByteSize += entry.descriptorCount; + inlineByteSize = AlignUp4(inlineByteSize); + } else { entrySize = sizeof(VkDescriptorBufferInfo); @@ -1152,8 +1203,8 @@ void DescUpdateTemplate::Init(VulkanResourceManager *resourceMan, VulkanCreation bufferInfoCount += entry.descriptorCount; } - dataByteSize = - RDCMAX(dataByteSize, entry.offset + entry.stride * entry.descriptorCount + entrySize); + unwrapByteSize = + RDCMAX(unwrapByteSize, entry.offset + stride * entry.descriptorCount + entrySize); } if(pCreateInfo->templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) @@ -1188,7 +1239,10 @@ void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication application.bufView.reserve(texelBufferViewCount); application.bufInfo.reserve(bufferInfoCount); application.imgInfo.reserve(imageInfoCount); + application.inlineData.resize(inlineByteSize); + application.inlineUniform.reserve(inlineInfoCount); + uint32_t inlineOffset = 0; for(const VkDescriptorUpdateTemplateEntry &entry : updates) { VkWriteDescriptorSet write = {}; @@ -1235,6 +1289,22 @@ void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication write.pImageInfo = &application.imgInfo[idx]; } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + application.inlineUniform.push_back({}); + + VkWriteDescriptorSetInlineUniformBlockEXT &inlineWrite = application.inlineUniform.back(); + inlineWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + inlineWrite.pNext = NULL; + inlineWrite.dataSize = entry.descriptorCount; + + void *dst = application.inlineData.data() + inlineOffset; + memcpy(dst, src, inlineWrite.dataSize); + inlineWrite.pData = dst; + + write.pNext = &inlineWrite; + write.descriptorCount = entry.descriptorCount; + } else { size_t idx = application.bufInfo.size(); diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 07a96aaad..a4ba19706 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -60,8 +60,8 @@ struct DescSetLayout void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, const VkDescriptorSetLayoutCreateInfo *pCreateInfo); - void CreateBindingsArray(rdcarray &descBindings) const; - void UpdateBindingsArray(const DescSetLayout &prevLayout, + void CreateBindingsArray(bytebuf &inlineData, rdcarray &descBindings) const; + void UpdateBindingsArray(const DescSetLayout &prevLayout, bytebuf &inlineData, rdcarray &descBindings) const; struct Binding @@ -116,6 +116,9 @@ struct DescSetLayout uint32_t dynamicCount; VkDescriptorSetLayoutCreateFlags flags; + uint32_t inlineCount; + uint32_t inlineByteSize; + bool operator==(const DescSetLayout &other) const; bool operator!=(const DescSetLayout &other) const { return !(*this == other); } }; @@ -125,6 +128,8 @@ struct DescUpdateTemplateApplication rdcarray bufInfo; rdcarray imgInfo; rdcarray bufView; + rdcarray inlineUniform; + bytebuf inlineData; rdcarray writes; }; @@ -140,11 +145,13 @@ struct DescUpdateTemplate VkPipelineBindPoint bindPoint; - size_t dataByteSize; + size_t unwrapByteSize; uint32_t texelBufferViewCount; uint32_t bufferInfoCount; uint32_t imageInfoCount; + uint32_t inlineInfoCount; + uint32_t inlineByteSize; rdcarray updates; }; diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 53461ff68..9c4329b66 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -52,7 +52,12 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) if((layout.flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) == 0) { for(size_t i = 0; i < layout.bindings.size(); i++) - initialContents.numDescriptors += layout.bindings[i].descriptorCount; + { + if(layout.bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + initialContents.numDescriptors++; + else + initialContents.numDescriptors += layout.bindings[i].descriptorCount; + } initialContents.descriptorSlots = new DescriptorSetSlot[initialContents.numDescriptors]; RDCEraseMem(initialContents.descriptorSlots, @@ -61,11 +66,22 @@ bool WrappedVulkan::Prepare_InitialState(WrappedVkRes *res) uint32_t e = 0; for(size_t i = 0; i < layout.bindings.size(); i++) { - for(uint32_t b = 0; b < layout.bindings[i].descriptorCount; b++) + if(layout.bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) { - initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][b]; + initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][0]; + } + else + { + for(uint32_t b = 0; b < layout.bindings[i].descriptorCount; b++) + { + initialContents.descriptorSlots[e++] = record->descInfo->descBindings[i][b]; + } } } + + initialContents.inlineData = AllocAlignedBuffer(record->descInfo->inlineData.size()); + memcpy(initialContents.inlineData, record->descInfo->inlineData.data(), + record->descInfo->inlineData.size()); } else { @@ -548,9 +564,14 @@ uint64_t WrappedVulkan::GetSize_InitialState(ResourceId id, const VkInitialConte uint32_t NumBindings = 0; for(size_t i = 0; i < layout.bindings.size(); i++) - NumBindings += layout.bindings[i].descriptorCount; + { + if(layout.bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + NumBindings++; + else + NumBindings += layout.bindings[i].descriptorCount; + } - return 32 + NumBindings * sizeof(DescriptorSetSlot); + return 32 + NumBindings * sizeof(DescriptorSetSlot) + layout.inlineByteSize; } else if(initial.type == eResBuffer) { @@ -601,6 +622,7 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, { DescriptorSetSlot *Bindings = NULL; uint32_t NumBindings = 0; + bytebuf InlineData; // while writing, fetching binding information from prepared initial contents if(ser.IsWriting()) @@ -611,12 +633,24 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, Bindings = initial->descriptorSlots; for(size_t i = 0; i < layout.bindings.size(); i++) - NumBindings += layout.bindings[i].descriptorCount; + { + if(layout.bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + NumBindings++; + else + NumBindings += layout.bindings[i].descriptorCount; + } + + InlineData.assign(initial->inlineData, layout.inlineByteSize); } SERIALISE_ELEMENT_ARRAY(Bindings, NumBindings); SERIALISE_ELEMENT(NumBindings); + if(ser.VersionAtLeast(0x12)) + { + SERIALISE_ELEMENT(InlineData); + } + SERIALISE_CHECK_READ_ERRORS(); // while reading, fetch the binding information and allocate a VkWriteDescriptorSet array @@ -638,6 +672,16 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, initialContents.numDescriptors = (uint32_t)layout.bindings.size(); initialContents.descriptorInfo = new VkDescriptorBufferInfo[NumBindings]; + initialContents.inlineInfo = NULL; + + if(layout.inlineCount > 0) + { + initialContents.inlineInfo = + new VkWriteDescriptorSetInlineUniformBlockEXT[layout.inlineCount]; + initialContents.inlineData = AllocAlignedBuffer(InlineData.size()); + RDCASSERTEQUAL(layout.inlineByteSize, InlineData.size()); + memcpy(initialContents.inlineData, InlineData.data(), InlineData.size()); + } // if we have partially-valid arrays, we need to split up writes. The worst case will never be // == number of bindings since that implies all arrays are valid, but it is an upper bound as @@ -649,8 +693,11 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, VkWriteDescriptorSet *writes = initialContents.descriptorWrites; VkDescriptorBufferInfo *dstData = initialContents.descriptorInfo; + VkWriteDescriptorSetInlineUniformBlockEXT *dstInline = initialContents.inlineInfo; DescriptorSetSlot *srcData = Bindings; + byte *srcInlineData = initialContents.inlineData; + // validBinds counts up as we make a valid VkWriteDescriptorSet, so can be used to index into // writes[] along the way as the 'latest' write. uint32_t bind = 0; @@ -662,6 +709,14 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, if(descriptorCount == 0) continue; + uint32_t inlineSize = 0; + + if(layout.bindings[j].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + inlineSize = descriptorCount; + descriptorCount = 1; + } + writes[bind].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writes[bind].pNext = NULL; @@ -686,6 +741,13 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, VkBufferView *dstTexelBuffer = (VkBufferView *)dstData; dstData += descriptorCount; + RDCCOMPILE_ASSERT( + sizeof(VkDescriptorImageInfo) <= sizeof(VkDescriptorBufferInfo), + "VkDescriptorBufferInfo should be large enough for all descriptor write types"); + RDCCOMPILE_ASSERT( + sizeof(VkBufferView) <= sizeof(VkDescriptorBufferInfo), + "VkDescriptorBufferInfo should be large enough for all descriptor write types"); + // the correct one will be set below writes[bind].pBufferInfo = NULL; writes[bind].pImageInfo = NULL; @@ -700,10 +762,26 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, // For the array case we batch up updates as much as possible, iterating along the array and // skipping any invalid descriptors. + if(writes[bind].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // handle inline uniform block specially because the descriptorCount doesn't mean what it + // normally means in the write. + + dstInline->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + dstInline->pNext = NULL; + dstInline->pData = srcInlineData + src->inlineOffset; + dstInline->dataSize = inlineSize; + + writes[bind].pNext = dstInline; + writes[bind].descriptorCount = inlineSize; + bind++; + + dstInline++; + } // quick check for slots that were completely uninitialised and so don't have valid data - if(descriptorCount == 1 && src->texelBufferView == ResourceId() && - src->imageInfo.sampler == ResourceId() && src->imageInfo.imageView == ResourceId() && - src->bufferInfo.buffer == ResourceId()) + else if(descriptorCount == 1 && src->texelBufferView == ResourceId() && + src->imageInfo.sampler == ResourceId() && + src->imageInfo.imageView == ResourceId() && src->bufferInfo.buffer == ResourceId()) { // do nothing - don't increment bind so that the same write descriptor is used next time. continue; @@ -1306,6 +1384,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten // need to blat over the current descriptor set contents, so these are available // when we want to fetch pipeline state rdcarray &bindings = m_DescriptorSetState[id].currentBindings; + bytebuf &inlineData = m_DescriptorSetState[id].inlineData; for(uint32_t i = 0; i < initial.numDescriptors; i++) { @@ -1313,6 +1392,16 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten DescriptorSetSlot *bind = bindings[writes[i].dstBinding]; + if(writes[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = + (VkWriteDescriptorSetInlineUniformBlockEXT *)FindNextStruct( + &writes[i], VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT); + memcpy(inlineData.data() + bind->inlineOffset + writes[i].dstArrayElement, + inlineWrite->pData, inlineWrite->dataSize); + continue; + } + for(uint32_t d = 0; d < writes[i].descriptorCount; d++) { uint32_t idx = writes[i].dstArrayElement + d; diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index 49e886d79..032d15b44 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -117,6 +117,8 @@ struct VkInitialContents SAFE_DELETE_ARRAY(descriptorSlots); SAFE_DELETE_ARRAY(descriptorWrites); SAFE_DELETE_ARRAY(descriptorInfo); + SAFE_DELETE_ARRAY(inlineInfo); + FreeAlignedBuffer(inlineData); rm->ResourceTypeRelease(GetWrapped(buf)); rm->ResourceTypeRelease(GetWrapped(img)); @@ -147,6 +149,8 @@ struct VkInitialContents DescriptorSetSlot *descriptorSlots; VkWriteDescriptorSet *descriptorWrites; VkDescriptorBufferInfo *descriptorInfo; + VkWriteDescriptorSetInlineUniformBlockEXT *inlineInfo; + byte *inlineData; uint32_t numDescriptors; // for plain resources, we store the resource type and memory allocation details of the contents diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index 7ba9eba4d..457aeb675 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -105,6 +105,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, COPY_STRUCT(VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV, \ VkDedicatedAllocationImageCreateInfoNV); \ COPY_STRUCT(VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, VkDescriptorPoolCreateInfo); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT, \ + VkDescriptorPoolInlineUniformBlockCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, \ VkDescriptorSetLayoutBindingFlagsCreateInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, VkDescriptorSetLayoutSupport); \ @@ -224,6 +226,10 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceImagelessFramebufferFeatures) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, \ VkPhysicalDeviceIndexTypeUint8FeaturesEXT); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT, \ + VkPhysicalDeviceInlineUniformBlockFeaturesEXT); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, \ + VkPhysicalDeviceInlineUniformBlockPropertiesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, \ VkPhysicalDeviceMaintenance3Properties); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT, \ @@ -415,6 +421,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, COPY_STRUCT(VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, VkTimelineSemaphoreSubmitInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT, VkValidationCacheCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, VkValidationFeaturesEXT); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT, \ + VkWriteDescriptorSetInlineUniformBlockEXT); \ COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO, \ VkLayerInstanceCreateInfo); \ COPY_STRUCT_CAPTURE_ONLY(VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, VkLayerDeviceCreateInfo); \ @@ -566,7 +574,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR: \ case VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR: \ case VK_STRUCTURE_TYPE_DEFERRED_OPERATION_INFO_KHR: \ - case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD: \ case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT: \ @@ -617,8 +624,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX: \ @@ -664,8 +669,7 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT: \ case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT: \ case VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD: \ - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR: \ - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: + case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR: size_t GetNextPatchSize(const void *pNext) { @@ -835,6 +839,9 @@ size_t GetNextPatchSize(const void *pNext) case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: memSize += info->descriptorCount * sizeof(VkDescriptorBufferInfo); break; + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + // nothing to unwrap for inline uniform blocks, it's on the next chain + break; default: RDCERR("Unhandled descriptor type unwrapping VkWriteDescriptorSet"); break; } break; @@ -1413,6 +1420,11 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, break; } + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + { + // nothing to do/patch + break; + } default: RDCERR("Unhandled descriptor type unwrapping VkWriteDescriptorSet"); break; } diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index e872f3472..2279a53d9 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1668,11 +1668,15 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: dst.bindings[b].type = BindType::InputAttachment; break; + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + dst.bindings[b].descriptorCount = 1; + dst.bindings[b].type = BindType::ConstantBuffer; + break; default: dst.bindings[b].type = BindType::Unknown; RDCERR("Unexpected descriptor type"); } - dst.bindings[b].binds.resize(layoutBind.descriptorCount); - for(uint32_t a = 0; a < layoutBind.descriptorCount; a++) + dst.bindings[b].binds.resize(dst.bindings[b].descriptorCount); + for(uint32_t a = 0; a < dst.bindings[b].descriptorCount; a++) { VKPipe::BindingElement &dstel = dst.bindings[b].binds[a]; @@ -1680,7 +1684,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) // if we have a list of used binds, and this is an array descriptor (so would be // expected to be in the list), check it for dynamic usage. - if(layoutBind.descriptorCount > 1 && hasUsedBinds) + if(dst.bindings[b].descriptorCount > 1 && hasUsedBinds) { // if we exhausted the list, all other elements are unused if(usedBindsSize == 0) @@ -1769,11 +1773,10 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) } } } - - if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) + else if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { ResourceId viewid = info[a].imageInfo.imageView; @@ -1804,8 +1807,8 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) dst.bindings[b].binds[a].numSlices = 1; } } - if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) + else if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) { ResourceId viewid = info[a].texelBufferView; @@ -1842,10 +1845,18 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) dst.bindings[b].binds[a].byteSize = 0; } } - if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || - layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) + else if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + dst.bindings[b].binds[a].viewResourceId = ResourceId(); + dst.bindings[b].binds[a].resourceResourceId = ResourceId(); + dst.bindings[b].binds[a].inlineBlock = true; + dst.bindings[b].binds[a].byteOffset = 0; + dst.bindings[b].binds[a].byteSize = layoutBind.descriptorCount; + } + else if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || + layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { dst.bindings[b].binds[a].viewResourceId = ResourceId(); @@ -1963,6 +1974,37 @@ void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, if(c.bufferBacked) { + const rdcarray &descSets = + (refl.stage == ShaderStage::Compute) ? m_pDriver->m_RenderState.compute.descSets + : m_pDriver->m_RenderState.graphics.descSets; + + Bindpoint bind = mapping.constantBlocks[c.bindPoint]; + + if(bind.bindset < descSets.count()) + { + ResourceId set = descSets[bind.bindset].descSet; + + const WrappedVulkan::DescriptorSetInfo &setData = m_pDriver->m_DescriptorSetState[set]; + + ResourceId layoutId = setData.layout; + + if(bind.bind < m_pDriver->m_CreationInfo.m_DescSetLayout[layoutId].bindings.count()) + { + const DescSetLayout::Binding &layoutBind = + m_pDriver->m_CreationInfo.m_DescSetLayout[layoutId].bindings[bind.bind]; + + if(layoutBind.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + bytebuf inlineData; + inlineData.assign( + setData.inlineData.data() + setData.currentBindings[bind.bind]->inlineOffset, + layoutBind.descriptorCount); + StandardFillCBufferVariables(refl.resourceId, c.variables, outvars, inlineData); + return; + } + } + } + StandardFillCBufferVariables(refl.resourceId, c.variables, outvars, data); } else diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 7ee4902f3..1a804bcfb 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1040,6 +1040,8 @@ struct DescSetLayout; struct DescriptorSetData { DescriptorSetData() : layout(NULL) {} + DescriptorSetData(const DescriptorSetData &) = delete; + DescriptorSetData &operator=(const DescriptorSetData &) = delete; ~DescriptorSetData() { for(size_t i = 0; i < descBindings.size(); i++) @@ -1052,6 +1054,7 @@ struct DescriptorSetData // descriptor set bindings for this descriptor set. Filled out on // create from the layout. rdcarray descBindings; + bytebuf inlineData; // lock protecting bindFrameRefs and bindMemRefs Threading::CriticalSection refLock; diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 388fef878..b0c38e38e 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -572,6 +572,16 @@ SERIALISE_VK_HANDLES(); PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, \ VkPhysicalDeviceIndexTypeUint8FeaturesEXT) \ \ + /* VK_EXT_inline_uniform_block */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT, \ + VkPhysicalDeviceInlineUniformBlockFeaturesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, \ + VkPhysicalDeviceInlineUniformBlockPropertiesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT, \ + VkWriteDescriptorSetInlineUniformBlockEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT, \ + VkDescriptorPoolInlineUniformBlockCreateInfoEXT) \ + \ /* VK_EXT_line_rasterization */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT, \ VkPhysicalDeviceLineRasterizationFeaturesEXT) \ @@ -1048,12 +1058,6 @@ SERIALISE_VK_HANDLES(); PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT) \ \ - /* VK_EXT_inline_uniform_block */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT) \ - \ /* VK_EXT_pipeline_creation_cache_control */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT) \ \ @@ -4015,6 +4019,7 @@ void DoSerialise(SerialiserType &ser, DescriptorSetSlot &el) SERIALISE_MEMBER(bufferInfo).TypedAs("VkDescriptorBufferInfo"_lit); SERIALISE_MEMBER(imageInfo).TypedAs("VkDescriptorImageInfo"_lit); SERIALISE_MEMBER(texelBufferView).TypedAs("VkBufferView"_lit); + SERIALISE_MEMBER(inlineOffset).Named("InlineDataOffset"_lit); } template @@ -6909,6 +6914,76 @@ void Deserialise(const VkPhysicalDeviceIndexTypeUint8FeaturesEXT &el) DeserialiseNext(el.pNext); } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceInlineUniformBlockFeaturesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(inlineUniformBlock); + SERIALISE_MEMBER(descriptorBindingInlineUniformBlockUpdateAfterBind); +} + +template <> +void Deserialise(const VkPhysicalDeviceInlineUniformBlockFeaturesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceInlineUniformBlockPropertiesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(maxInlineUniformBlockSize); + SERIALISE_MEMBER(maxPerStageDescriptorInlineUniformBlocks); + SERIALISE_MEMBER(maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks); + SERIALISE_MEMBER(maxDescriptorSetInlineUniformBlocks); + SERIALISE_MEMBER(maxDescriptorSetUpdateAfterBindInlineUniformBlocks); +} + +template <> +void Deserialise(const VkPhysicalDeviceInlineUniformBlockPropertiesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkWriteDescriptorSetInlineUniformBlockEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(dataSize); + SERIALISE_MEMBER_ARRAY(pData, dataSize); +} + +template <> +void Deserialise(const VkWriteDescriptorSetInlineUniformBlockEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkDescriptorPoolInlineUniformBlockCreateInfoEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(maxInlineUniformBlockBindings); +} + +template <> +void Deserialise(const VkDescriptorPoolInlineUniformBlockCreateInfoEXT &el) +{ + DeserialiseNext(el.pNext); +} + template void DoSerialise(SerialiserType &ser, VkPhysicalDeviceLineRasterizationFeaturesEXT &el) { diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index fb132bb09..c2198d90f 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -186,6 +186,7 @@ public: const rdcarray &curBinds = m_pDriver->GetCurrentDescSetBindings(descSets[set].descSet); + const bytebuf &curInline = m_pDriver->GetCurrentDescSetInlineData(descSets[set].descSet); const DescSetLayout &setLayout = m_Creation.m_DescSetLayout[pipeLayout.descSetLayouts[set]]; for(size_t bind = 0; bind < setLayout.bindings.size(); bind++) @@ -248,6 +249,17 @@ public: } break; } + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + { + // push directly into the buffer cache from the inline data + BindpointIndex idx; + idx.bindset = (int32_t)set; + idx.bind = (int32_t)bind; + idx.arrayIndex = 0; + bufferCache[idx].assign(curInline.data() + curSlots->inlineOffset, + bindLayout.descriptorCount); + break; + } case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { @@ -315,18 +327,7 @@ public: virtual uint64_t GetBufferLength(BindpointIndex bind) override { - bool valid = true; - const VkDescriptorBufferInfo &bufData = - GetDescriptor("reading buffer length", bind, valid); - if(valid) - { - if(bufData.range != VK_WHOLE_SIZE) - return bufData.range; - - return m_Creation.m_Buffer[GetResID(bufData.buffer)].size - bufData.offset; - } - - return 0; + return PopulateBuffer(bind).size(); } virtual void ReadBufferValue(BindpointIndex bind, uint64_t offset, uint64_t byteSize, diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 99c879d99..d4b3b27d3 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -391,6 +391,7 @@ void VulkanRenderState::BindDescriptorSet(WrappedVulkan *vk, const DescSetLayout rdcarray allocImgWrites; rdcarray allocBufWrites; rdcarray allocBufViewWrites; + rdcarray allocInlineWrites; const WrappedVulkan::DescriptorSetInfo &setInfo = vk->GetDebugManager()->GetDescSetInfo(descSet); @@ -445,6 +446,22 @@ void VulkanRenderState::BindDescriptorSet(WrappedVulkan *vk, const DescSetLayout push.pImageInfo = dst; allocImgWrites.push_back(dst); } + else if(push.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + allocInlineWrites.push_back(new VkWriteDescriptorSetInlineUniformBlockEXT); + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = allocInlineWrites.back(); + inlineWrite->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + inlineWrite->pNext = NULL; + inlineWrite->dataSize = bind.descriptorCount; + inlineWrite->pData = setInfo.inlineData.data() + slots->inlineOffset; + + push.pNext = inlineWrite; + push.descriptorCount = bind.descriptorCount; + writes.push_back(push); + + // skip validity checks + continue; + } else { VkDescriptorBufferInfo *dst = new VkDescriptorBufferInfo[push.descriptorCount]; @@ -514,6 +531,8 @@ void VulkanRenderState::BindDescriptorSet(WrappedVulkan *vk, const DescSetLayout delete[] a; for(VkBufferView *a : allocBufViewWrites) delete[] a; + for(VkWriteDescriptorSetInlineUniformBlockEXT *a : allocInlineWrites) + delete a; } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index dbf341f42..315c044fe 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -727,8 +727,10 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman { for(size_t i = 0; i < ARRAY_COUNT(BakedCmdBufferInfo::pushDescriptorID[p]); i++) { - m_DescriptorSetState[m_BakedCmdBufferInfo[BakedCommandBuffer].pushDescriptorID[p][i]] = - DescriptorSetInfo(true); + DescriptorSetInfo &pushDesc = + m_DescriptorSetState[m_BakedCmdBufferInfo[BakedCommandBuffer].pushDescriptorID[p][i]]; + pushDesc.clear(); + pushDesc.push = true; } } @@ -3946,15 +3948,16 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo const DescSetLayout &desclayout = m_CreationInfo.m_DescSetLayout[descSetLayouts[set]]; rdcarray &bindings = m_DescriptorSetState[setId].currentBindings; + bytebuf &inlineData = m_DescriptorSetState[setId].inlineData; ResourceId prevLayout = m_DescriptorSetState[setId].layout; if(prevLayout == ResourceId()) { - desclayout.CreateBindingsArray(bindings); + desclayout.CreateBindingsArray(inlineData, bindings); } else if(prevLayout != descSetLayouts[set]) { - desclayout.UpdateBindingsArray(m_CreationInfo.m_DescSetLayout[prevLayout], bindings); + desclayout.UpdateBindingsArray(m_CreationInfo.m_DescSetLayout[prevLayout], inlineData, bindings); } m_DescriptorSetState[setId].layout = descSetLayouts[set]; @@ -4019,6 +4022,14 @@ void WrappedVulkan::ApplyPushDescriptorWrites(VkPipelineBindPoint pipelineBindPo (*bind)[curIdx].imageInfo.SetFrom(writeDesc.pImageInfo[d], sampler, imageView); } } + else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = + (VkWriteDescriptorSetInlineUniformBlockEXT *)FindNextStruct( + &writeDesc, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT); + memcpy(inlineData.data() + (*bind)->inlineOffset + writeDesc.dstArrayElement, + inlineWrite->pData, inlineWrite->dataSize); + } else { for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) @@ -4223,6 +4234,10 @@ void WrappedVulkan::vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout; } } + else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // nothing to unwrap, the next chain contains the data which we can leave as-is + } else { unwrappedWrites[i].pBufferInfo = bufInfos; @@ -4285,6 +4300,10 @@ void WrappedVulkan::vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, record->MarkResourceFrameReferenced(GetResID(write.pImageInfo[d].sampler), eFrameRef_Read); } + else if(write.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // no bindings in this type + } else { record->MarkBufferFrameReferenced(GetRecord(write.pBufferInfo[d].buffer), @@ -4437,7 +4456,7 @@ void WrappedVulkan::vkCmdPushDescriptorSetWithTemplateKHR( DescUpdateTemplate *tempInfo = GetRecord(descriptorUpdateTemplate)->descTemplateInfo; // allocate the whole blob of memory - byte *memory = GetTempMemory(tempInfo->dataByteSize); + byte *memory = GetTempMemory(tempInfo->unwrapByteSize); // iterate the entries, copy the descriptor data and unwrap for(const VkDescriptorUpdateTemplateEntry &entry : tempInfo->updates) @@ -4495,6 +4514,11 @@ void WrappedVulkan::vkCmdPushDescriptorSetWithTemplateKHR( } } } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // memcpy the data + memcpy(dst, src, entry.descriptorCount); + } else { for(uint32_t d = 0; d < entry.descriptorCount; d++) diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index 7655e5c5d..affef3b01 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -96,6 +96,10 @@ VkWriteDescriptorSet WrappedVulkan::UnwrapInfo(const VkWriteDescriptorSet *write { VkWriteDescriptorSet ret = *writeDesc; + // nothing to unwrap for inline uniform block + if(ret.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + return ret; + byte *memory = GetTempMemory(sizeof(VkDescriptorBufferInfo) * writeDesc->descriptorCount); VkDescriptorBufferInfo *bufInfos = (VkDescriptorBufferInfo *)memory; @@ -448,7 +452,7 @@ bool WrappedVulkan::Serialise_vkAllocateDescriptorSets(SerialiserType &ser, VkDe // this is stored in the resource record on capture, we need to be able to look to up m_DescriptorSetState[live].layout = layoutId; m_CreationInfo.m_DescSetLayout[layoutId].CreateBindingsArray( - m_DescriptorSetState[live].currentBindings); + m_DescriptorSetState[live].inlineData, m_DescriptorSetState[live].currentBindings); } AddResource(DescriptorSet, ResourceType::ShaderBinding, "Descriptor Set"); @@ -521,7 +525,8 @@ VkResult WrappedVulkan::vkAllocateDescriptorSets(VkDevice device, record->descInfo = new DescriptorSetData(); record->descInfo->layout = layoutRecord->descInfo->layout; - record->descInfo->layout->CreateBindingsArray(record->descInfo->descBindings); + record->descInfo->layout->CreateBindingsArray(record->descInfo->inlineData, + record->descInfo->descBindings); } else { @@ -644,6 +649,7 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr valid &= (writeDesc.pBufferInfo[i].buffer != VK_NULL_HANDLE); break; } + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: break; default: RDCERR("Unexpected descriptor type %d", writeDesc.descriptorType); } @@ -655,6 +661,7 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr // update our local tracking rdcarray &bindings = m_DescriptorSetState[GetResID(writeDesc.dstSet)].currentBindings; + bytebuf &inlineData = m_DescriptorSetState[GetResID(writeDesc.dstSet)].inlineData; { RDCASSERT(writeDesc.dstBinding < bindings.size()); @@ -712,6 +719,14 @@ void WrappedVulkan::ReplayDescriptorSetWrite(VkDevice device, const VkWriteDescr (*bind)[curIdx].imageInfo.SetFrom(writeDesc.pImageInfo[d], sampler, imageView); } } + else if(writeDesc.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = + (VkWriteDescriptorSetInlineUniformBlockEXT *)FindNextStruct( + &writeDesc, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT); + memcpy(inlineData.data() + (*bind)->inlineOffset + writeDesc.dstArrayElement, + inlineWrite->pData, inlineWrite->dataSize); + } else { for(uint32_t d = 0; d < writeDesc.descriptorCount; d++, curIdx++) @@ -768,6 +783,21 @@ void WrappedVulkan::ReplayDescriptorSetCopy(VkDevice device, const VkCopyDescrip for(uint32_t d = 0; d < copyDesc.descriptorCount; d++, curSrcIdx++, curDstIdx++) { + if(layoutSrcBinding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // inline uniform blocks are special, the descriptor count is a byte count. The layouts may + // not match so inline offsets might not match, so we just copy the data and break. + + bytebuf &dstInlineData = m_DescriptorSetState[dstSetId].inlineData; + bytebuf &srcInlineData = m_DescriptorSetState[srcSetId].inlineData; + + memcpy(dstInlineData.data() + (*dstbind)->inlineOffset + copyDesc.dstArrayElement, + srcInlineData.data() + (*srcbind)->inlineOffset + copyDesc.srcArrayElement, + copyDesc.descriptorCount); + + break; + } + // allow consecutive descriptor bind updates. See vkUpdateDescriptorSets for more // explanation if(curSrcIdx >= layoutSrcBinding->descriptorCount) @@ -921,6 +951,10 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout; } } + else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // nothing to unwrap, the next chain contains the data which we can leave as-is + } else { unwrappedWrites[i].pBufferInfo = bufInfos; @@ -1026,6 +1060,7 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, RDCASSERT(descWrite.dstBinding < record->descInfo->descBindings.size()); DescriptorSetSlot **binding = &record->descInfo->descBindings[descWrite.dstBinding]; + bytebuf &inlineData = record->descInfo->inlineData; const DescSetLayout::Binding *layoutBinding = &layout.bindings[descWrite.dstBinding]; @@ -1098,6 +1133,17 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, bind.imageInfo.SetFrom(descWrite.pImageInfo[d], sampler, imageView); } + else if(descWrite.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + VkWriteDescriptorSetInlineUniformBlockEXT *inlineWrite = + (VkWriteDescriptorSetInlineUniformBlockEXT *)FindNextStruct( + &descWrite, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT); + memcpy(inlineData.data() + bind.inlineOffset + descWrite.dstArrayElement, + inlineWrite->pData, inlineWrite->dataSize); + + // break now because the descriptorCount is not the number of descriptors + break; + } else { bind.bufferInfo.SetFrom(descWrite.pBufferInfo[d]); @@ -1143,6 +1189,23 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, for(uint32_t d = 0; d < pDescriptorCopies[i].descriptorCount; d++, curSrcIdx++, curDstIdx++) { + if(srclayoutBinding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // inline uniform blocks are special, the descriptor count is a byte count. The layouts + // may not match so inline offsets might not match, so we just copy the data and break. + + bytebuf &dstInlineData = dstrecord->descInfo->inlineData; + bytebuf &srcInlineData = srcrecord->descInfo->inlineData; + + memcpy(dstInlineData.data() + (*dstbinding)->inlineOffset + + pDescriptorCopies[i].dstArrayElement, + srcInlineData.data() + (*srcbinding)->inlineOffset + + pDescriptorCopies[i].srcArrayElement, + pDescriptorCopies[i].descriptorCount); + + break; + } + if(curDstIdx >= dstlayoutBinding->descriptorCount) { dstlayoutBinding++; @@ -1307,7 +1370,7 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( { // allocate the whole blob of memory - byte *memory = GetTempMemory(tempInfo->dataByteSize); + byte *memory = GetTempMemory(tempInfo->unwrapByteSize); // iterate the entries, copy the descriptor data and unwrap for(const VkDescriptorUpdateTemplateEntry &entry : tempInfo->updates) @@ -1358,6 +1421,11 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( src += entry.stride; } } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + // memcpy the data + memcpy(dst, src, entry.descriptorCount); + } else { for(uint32_t d = 0; d < entry.descriptorCount; d++) @@ -1411,6 +1479,7 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( RDCASSERT(entry.dstBinding < record->descInfo->descBindings.size()); DescriptorSetSlot **binding = &record->descInfo->descBindings[entry.dstBinding]; + bytebuf &inlineData = record->descInfo->inlineData; const DescSetLayout::Binding *layoutBinding = &layout.bindings[entry.dstBinding]; @@ -1472,6 +1541,14 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( bind.imageInfo.SetFrom(srcInfo, sampler, imageView); } + else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) + { + memcpy(inlineData.data() + bind.inlineOffset + entry.dstArrayElement, src, + entry.descriptorCount); + + // break now because the descriptorCount is not the number of descriptors + break; + } else { bind.bufferInfo.SetFrom(*(const VkDescriptorBufferInfo *)src); diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 8f86d74ed..63b3684d7 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -2523,6 +2523,14 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi CHECK_PHYS_EXT_FEATURE(performanceCounterMultipleQueryPools); } END_PHYS_EXT_CHECK(); + + BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceInlineUniformBlockFeaturesEXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT); + { + CHECK_PHYS_EXT_FEATURE(inlineUniformBlock); + CHECK_PHYS_EXT_FEATURE(descriptorBindingInlineUniformBlockUpdateAfterBind); + } + END_PHYS_EXT_CHECK(); } if(availFeatures.depthClamp) diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 7a404047a..4eec78f61 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1868,6 +1868,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::BindingElement &el) SERIALISE_MEMBER(maxLOD); SERIALISE_MEMBER(borderColor); SERIALISE_MEMBER(unnormalized); + SERIALISE_MEMBER(inlineBlock); SERIALISE_MEMBER(ycbcrSampler);