From f87338dc0e796702adca890aad600e278ebfc1c3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 25 Apr 2018 17:58:39 +0100 Subject: [PATCH] Add support for VK_EXT_vertex_attribute_divisor --- .../Code/Interface/CommonPipelineState.cpp | 7 ++- .../VulkanPipelineStateViewer.cpp | 23 ++++---- renderdoc/api/replay/vk_pipestate.h | 12 ++++- renderdoc/driver/vulkan/vk_common.h | 4 ++ renderdoc/driver/vulkan/vk_core.cpp | 3 ++ renderdoc/driver/vulkan/vk_hookset_defs.h | 3 +- renderdoc/driver/vulkan/vk_info.cpp | 17 ++++++ renderdoc/driver/vulkan/vk_info.h | 3 ++ renderdoc/driver/vulkan/vk_postvs.cpp | 54 ++++++++++++++----- renderdoc/driver/vulkan/vk_replay.cpp | 2 + renderdoc/driver/vulkan/vk_serialise.cpp | 32 ++++++++++- renderdoc/driver/vulkan/vk_shader_cache.cpp | 19 +++++++ .../vulkan/wrappers/vk_device_funcs.cpp | 4 ++ renderdoc/replay/renderdoc_serialise.inl | 3 +- 14 files changed, 158 insertions(+), 28 deletions(-) diff --git a/qrenderdoc/Code/Interface/CommonPipelineState.cpp b/qrenderdoc/Code/Interface/CommonPipelineState.cpp index b225906b1..7efc1a81a 100644 --- a/qrenderdoc/Code/Interface/CommonPipelineState.cpp +++ b/qrenderdoc/Code/Interface/CommonPipelineState.cpp @@ -917,9 +917,12 @@ rdcarray CommonPipelineState::GetVertexInputs() ret[a].vertexBuffer = (int)attrs[i].binding; ret[a].byteOffset = attrs[i].byteOffset; ret[a].perInstance = false; - if(attrs[i].binding < (uint32_t)m_Vulkan->vertexInput.bindings.count()) - ret[a].perInstance = m_Vulkan->vertexInput.bindings[attrs[i].binding].perInstance; ret[a].instanceRate = 1; + if(attrs[i].binding < (uint32_t)m_Vulkan->vertexInput.bindings.count()) + { + ret[a].perInstance = m_Vulkan->vertexInput.bindings[attrs[i].binding].perInstance; + ret[a].instanceRate = m_Vulkan->vertexInput.bindings[attrs[i].binding].instanceDivisor; + } ret[a].format = attrs[i].format; ret[a].used = true; ret[a].genericEnabled = false; diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 06b37b16f..60f17bce0 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -180,9 +180,9 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); ui->viBuffers->setHeader(header); - ui->viBuffers->setColumns({tr("Slot"), tr("Buffer"), tr("Rate"), tr("Offset"), tr("Stride"), - tr("Byte Length"), tr("Go")}); - header->setColumnStretchHints({1, 4, 2, 2, 2, 3, -1}); + ui->viBuffers->setColumns({tr("Slot"), tr("Buffer"), tr("Rate"), tr("Divisor"), tr("Offset"), + tr("Stride"), tr("Byte Length"), tr("Go")}); + header->setColumnStretchHints({1, 4, 2, 2, 2, 2, 3, -1}); ui->viBuffers->setHoverIconColumn(6, action, action_hover); ui->viBuffers->setClearSelectionOnFocusLoss(true); @@ -1595,7 +1595,7 @@ void VulkanPipelineStateViewer::setState() length = buf->length; RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), state.inputAssembly.indexBuffer.resourceId, tr("Index"), + {tr("Index"), state.inputAssembly.indexBuffer.resourceId, tr("Index"), lit("-"), (qulonglong)state.inputAssembly.indexBuffer.byteOffset, draw != NULL ? draw->indexByteWidth : 0, (qulonglong)length, QString()}); @@ -1616,8 +1616,8 @@ void VulkanPipelineStateViewer::setState() { if(ibufferUsed || showEmpty) { - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), ResourceId(), tr("Index"), lit("-"), lit("-"), lit("-"), QString()}); + RDTreeWidgetItem *node = new RDTreeWidgetItem({tr("Index"), ResourceId(), tr("Index"), lit("-"), + lit("-"), lit("-"), lit("-"), QString()}); node->setTag(QVariant::fromValue( VulkanVBIBTag(state.inputAssembly.indexBuffer.resourceId, @@ -1657,6 +1657,7 @@ void VulkanPipelineStateViewer::setState() uint64_t length = 1; uint64_t offset = 0; uint32_t stride = 0; + uint32_t divisor = 1; if(vbuff != NULL) { @@ -1671,6 +1672,8 @@ void VulkanPipelineStateViewer::setState() { stride = bind->byteStride; rate = bind->perInstance ? tr("Instance") : tr("Vertex"); + if(bind->perInstance) + divisor = bind->instanceDivisor; } else { @@ -1680,11 +1683,11 @@ void VulkanPipelineStateViewer::setState() RDTreeWidgetItem *node = NULL; if(filledSlot) - node = new RDTreeWidgetItem({i, vbuff->resourceId, rate, (qulonglong)offset, stride, - (qulonglong)length, QString()}); + node = new RDTreeWidgetItem({i, vbuff->resourceId, rate, divisor, (qulonglong)offset, + stride, (qulonglong)length, QString()}); else node = new RDTreeWidgetItem( - {i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), QString()}); + {i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), lit("-"), QString()}); node->setTag(QVariant::fromValue(VulkanVBIBTag( vbuff != NULL ? vbuff->resourceId : ResourceId(), vbuff != NULL ? vbuff->byteOffset : 0))); @@ -1706,7 +1709,7 @@ void VulkanPipelineStateViewer::setState() if(usedBindings[i]) { RDTreeWidgetItem *node = new RDTreeWidgetItem( - {i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), QString()}); + {i, tr("No Binding"), lit("-"), lit("-"), lit("-"), lit("-"), lit("-"), QString()}); node->setTag(QVariant::fromValue(VulkanVBIBTag(ResourceId(), 0))); diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index 6f39e23fd..0b628cec8 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -320,7 +320,7 @@ struct VertexBinding bool operator==(const VertexBinding &o) const { return vertexBufferBinding == o.vertexBufferBinding && byteStride == o.byteStride && - perInstance == o.perInstance; + perInstance == o.perInstance && instanceDivisor == o.instanceDivisor; } bool operator<(const VertexBinding &o) const { @@ -330,6 +330,8 @@ struct VertexBinding return byteStride < o.byteStride; if(!(perInstance == o.perInstance)) return perInstance < o.perInstance; + if(!(instanceDivisor == o.instanceDivisor)) + return instanceDivisor < o.instanceDivisor; return false; } DOCUMENT("The vertex binding where data will be sourced from."); @@ -338,6 +340,14 @@ struct VertexBinding uint32_t byteStride = 0; DOCUMENT("``True`` if the vertex data is instance-rate."); bool perInstance = false; + DOCUMENT(R"(The instance rate divisor. + +If this is ``0`` then every vertex gets the same value. + +If it's ``1`` then one element is read for each instance, and for ``N`` greater than ``1`` then +``N`` instances read the same element before advancing. +)"); + uint32_t instanceDivisor = 1; }; DOCUMENT("Describes a single Vulkan vertex buffer binding.") diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 87aae15d9..6c8e9cd0e 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -214,6 +214,7 @@ enum { VkCheckExt_AMD_neg_viewport, VkCheckExt_EXT_conserv_rast, + VkCheckExt_EXT_vertex_divisor, VkCheckExt_Max, }; @@ -624,6 +625,8 @@ DECLARE_REFLECTION_STRUCT(VkPipelineTessellationDomainOriginStateCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkImageViewUsageCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkInputAttachmentAspectReference); DECLARE_REFLECTION_STRUCT(VkRenderPassInputAttachmentAspectCreateInfoKHR); +DECLARE_REFLECTION_STRUCT(VkVertexInputBindingDivisorDescriptionEXT); +DECLARE_REFLECTION_STRUCT(VkPipelineVertexInputDivisorStateCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkDeviceCreateInfo); DECLARE_DESERIALISE_TYPE(VkBufferCreateInfo); @@ -667,6 +670,7 @@ DECLARE_DESERIALISE_TYPE(VkPipelineRasterizationConservativeStateCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineTessellationDomainOriginStateCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkImageViewUsageCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkRenderPassInputAttachmentAspectCreateInfoKHR); +DECLARE_DESERIALISE_TYPE(VkPipelineVertexInputDivisorStateCreateInfoEXT); DECLARE_REFLECTION_ENUM(VkFlagWithNoBits); DECLARE_REFLECTION_ENUM(VkQueueFlagBits); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 5ca057327..e4ddca747 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -564,6 +564,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME, VK_EXT_VALIDATION_FLAGS_SPEC_VERSION, }, + { + VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION, + }, #ifdef VK_IMG_format_pvrtc { VK_IMG_FORMAT_PVRTC_EXTENSION_NAME, VK_IMG_FORMAT_PVRTC_SPEC_VERSION, diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 7a628a3a9..085b9e010 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -324,7 +324,8 @@ CheckExt(KHR_bind_memory2, VK11); \ CheckExt(EXT_conservative_rasterization, VKXX); \ CheckExt(EXT_global_priority, VKXX); \ - CheckExt(AMD_buffer_marker, VKXX); + CheckExt(AMD_buffer_marker, VKXX); \ + CheckExt(EXT_vertex_attribute_divisor, VKXX); #define HookInitVulkanInstanceExts() \ HookInitExtension(KHR_surface, DestroySurfaceKHR); \ diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index bc950cd6c..ec5d6d55c 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -205,6 +205,23 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk vertexBindings[i].perInstance = pCreateInfo->pVertexInputState->pVertexBindingDescriptions[i].inputRate == VK_VERTEX_INPUT_RATE_INSTANCE; + vertexBindings[i].instanceDivisor = 1; + } + + // if there's a divisors struct, apply them now + const VkPipelineVertexInputDivisorStateCreateInfoEXT *divisors = + (const VkPipelineVertexInputDivisorStateCreateInfoEXT *)FindNextStruct( + pCreateInfo->pVertexInputState, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT); + if(divisors) + { + for(uint32_t b = 0; b < divisors->vertexBindingDivisorCount; b++) + { + const VkVertexInputBindingDivisorDescriptionEXT &div = divisors->pVertexBindingDivisors[b]; + + if(div.binding < vertexBindings.size()) + vertexBindings[div.binding].instanceDivisor = div.divisor; + } } vertexAttrs.resize(pCreateInfo->pVertexInputState->vertexAttributeDescriptionCount); diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 874009475..e68e47bb3 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -155,6 +155,9 @@ struct VulkanCreationInfo uint32_t vbufferBinding; uint32_t bytestride; bool perInstance; + + // VkVertexInputBindingDivisorDescriptionEXT + uint32_t instanceDivisor; }; vector vertexBindings; diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 1a2cde0c5..2bd753fbc 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -35,7 +35,7 @@ static const uint32_t MeshOutputDispatchWidth = 128; static const uint32_t MeshOutputTBufferArraySize = 16; static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRVPatchData &patchData, - const char *entryName, std::vector isInstanced, + const char *entryName, std::vector instDivisor, uint32_t &descSet, const DrawcallDescription *draw, int32_t indexOffset, uint64_t numFetchVerts, uint32_t numVerts, std::vector &modSpirv, uint32_t &bufStride) @@ -849,14 +849,41 @@ static void ConvertToMeshOutputCompute(const ShaderReflection &refl, const SPIRV ops.push_back(SPIRVOperation(spv::OpImage, {tb.imageTypeID, rawimg, loaded})); // vec4 result = texelFetch(rawimg, vtxID or instID); - uint32_t idx = location < isInstanced.size() && isInstanced[location] ? instanceLookup - : vertexLookup; + uint32_t idx = vertexLookup; + + if(location < instDivisor.size()) + { + uint32_t divisor = instDivisor[location]; + + if(divisor == ~0U) + { + // this magic value indicates vertex-rate data + idx = vertexLookup; + } + else if(divisor == 0) + { + // if the divisor is 0, all instances read the first value. + idx = editor.AddConstantImmediate(0); + } + else if(divisor == 1) + { + // if the divisor is 1, it's just regular instancing + idx = instanceLookup; + } + else + { + // otherwise we divide by the divisor + idx = editor.MakeId(); + divisor = editor.AddConstantImmediate(int32_t(divisor & 0x7fffffff)); + ops.push_back(SPIRVOperation(spv::OpSDiv, {sint32ID, idx, instanceLookup, divisor})); + } + } + uint32_t result = editor.MakeId(); ops.push_back(SPIRVOperation(spv::OpImageFetch, {ins[i].vec4ID, result, rawimg, idx})); // for one component, extract x, for less than 4, extract the sub-vector, otherwise - // leave - // alone (4 components) + // leave alone (4 components) if(refl.inputSignature[i].compCount == 1) { uint32_t swizzleIn = result; @@ -1240,7 +1267,7 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) VkBufferView view; }; - std::vector attrIsInstanced; + std::vector attrInstDivisor; CompactedAttrBuffer vbuffers[64]; RDCEraseEl(vbuffers); @@ -1292,7 +1319,7 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) continue; } - bool isInstanced = false; + uint32_t instDivisor = ~0U; size_t stride = 1; const byte *origVBBegin = NULL; @@ -1306,7 +1333,10 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) origVBBegin = origVBs[vb].data() + attrDesc.offset; origVBEnd = origVBs[vb].data() + origVBs[vb].size(); stride = vbDesc.stride; - isInstanced = (vbDesc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE); + if(vbDesc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE) + instDivisor = pipeInfo.vertexBindings[vbDesc.binding].instanceDivisor; + else + instDivisor = ~0U; break; } } @@ -1360,7 +1390,7 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, }; - if(isInstanced) + if(instDivisor != ~0U) bufInfo.size = elemSize * (maxInstance + 1); vkr = m_pDriver->vkCreateBuffer(dev, &bufInfo, NULL, &vbuffers[attr].buf); @@ -1505,8 +1535,8 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) m_pDriver->vkCreateBufferView(dev, &info, NULL, &vbuffers[attr].view); - attrIsInstanced.resize(RDCMAX(attrIsInstanced.size(), size_t(attr + 1))); - attrIsInstanced[attr] = isInstanced; + attrInstDivisor.resize(RDCMAX(attrInstDivisor.size(), size_t(attr + 1))); + attrInstDivisor[attr] = instDivisor; descWrites[numWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descWrites[numWrites].dstSet = m_MeshFetchDescSet; @@ -1540,7 +1570,7 @@ void VulkanReplay::InitPostVSBuffers(uint32_t eventId) } ConvertToMeshOutputCompute(*refl, *pipeInfo.shaders[0].patchData, - pipeInfo.shaders[0].entryPoint.c_str(), attrIsInstanced, descSet, + pipeInfo.shaders[0].entryPoint.c_str(), attrInstDivisor, descSet, drawcall, baseVertex, numFetchVerts, numVerts, modSpirv, bufStride); VkComputePipelineCreateInfo compPipeInfo = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 84545bbb4..b79f6888a 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -874,6 +874,8 @@ void VulkanReplay::SavePipelineState() m_VulkanPipelineState.vertexInput.bindings[i].vertexBufferBinding = p.vertexBindings[i].vbufferBinding; m_VulkanPipelineState.vertexInput.bindings[i].perInstance = p.vertexBindings[i].perInstance; + m_VulkanPipelineState.vertexInput.bindings[i].instanceDivisor = + p.vertexBindings[i].instanceDivisor; } m_VulkanPipelineState.vertexInput.vertexBuffers.resize(state.vbuffers.size()); diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index bb210d1ce..6ed555487 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -178,7 +178,11 @@ SERIALISE_VK_HANDLES(); VkPipelineTessellationDomainOriginStateCreateInfoKHR) \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR, VkImageViewUsageCreateInfoKHR) \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR, \ - VkRenderPassInputAttachmentAspectCreateInfoKHR) + VkRenderPassInputAttachmentAspectCreateInfoKHR) \ + \ + /* VK_EXT_vertex_attribute_divisor */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT, \ + VkPipelineVertexInputDivisorStateCreateInfoEXT) template static void SerialiseNext(SerialiserType &ser, VkStructureType &sType, const void *&pNext) @@ -2301,6 +2305,31 @@ void Deserialise(const VkRenderPassInputAttachmentAspectCreateInfoKHR &el) delete[] el.pAspectReferences; } +template +void DoSerialise(SerialiserType &ser, VkVertexInputBindingDivisorDescriptionEXT &el) +{ + SERIALISE_MEMBER(binding); + SERIALISE_MEMBER(divisor); +} + +template +void DoSerialise(SerialiserType &ser, VkPipelineVertexInputDivisorStateCreateInfoEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(vertexBindingDivisorCount); + SERIALISE_MEMBER_ARRAY(pVertexBindingDivisors, vertexBindingDivisorCount); +} + +template <> +void Deserialise(const VkPipelineVertexInputDivisorStateCreateInfoEXT &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pVertexBindingDivisors; +} + INSTANTIATE_SERIALISE_TYPE(VkOffset2D); INSTANTIATE_SERIALISE_TYPE(VkExtent2D); INSTANTIATE_SERIALISE_TYPE(VkMemoryType); @@ -2402,6 +2431,7 @@ INSTANTIATE_SERIALISE_TYPE(VkDescriptorUpdateTemplateCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkBindBufferMemoryInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkBindImageMemoryInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkPipelineRasterizationConservativeStateCreateInfoEXT); +INSTANTIATE_SERIALISE_TYPE(VkPipelineVertexInputDivisorStateCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(DescriptorSetSlot); INSTANTIATE_SERIALISE_TYPE(ImageRegionState); diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 6385359d3..97f7f1749 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -356,6 +356,25 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p : VK_VERTEX_INPUT_RATE_VERTEX; } + static VkPipelineVertexInputDivisorStateCreateInfoEXT vertexDivisor = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT, + }; + static VkVertexInputBindingDivisorDescriptionEXT vibindDivisors[128] = {}; + + if(m_pDriver->m_ExtensionsEnabled[VkCheckExt_EXT_vertex_divisor]) + { + vertexDivisor.pVertexBindingDivisors = vibindDivisors; + vertexDivisor.vertexBindingDivisorCount = vi.vertexBindingDescriptionCount; + + for(uint32_t i = 0; i < vi.vertexBindingDescriptionCount; i++) + { + vibindDivisors[i].binding = i; + vibindDivisors[i].divisor = pipeInfo.vertexBindings[i].instanceDivisor; + } + + vi.pNext = &vertexDivisor; + } + RDCASSERT(ARRAY_COUNT(viattr) >= pipeInfo.vertexAttrs.size()); RDCASSERT(ARRAY_COUNT(vibind) >= pipeInfo.vertexBindings.size()); diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index eee9fda3a..0468b3304 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -989,6 +989,10 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) != Extensions.end()) m_ExtensionsEnabled[VkCheckExt_EXT_conserv_rast] = true; + if(std::find(Extensions.begin(), Extensions.end(), + VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) != Extensions.end()) + m_ExtensionsEnabled[VkCheckExt_EXT_vertex_divisor] = true; + std::vector Layers; for(uint32_t i = 0; i < createInfo.enabledLayerCount; i++) Layers.push_back(createInfo.ppEnabledLayerNames[i]); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index b6e7d41b2..00bd1c505 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1819,8 +1819,9 @@ void DoSerialise(SerialiserType &ser, VKPipe::VertexBinding &el) SERIALISE_MEMBER(vertexBufferBinding); SERIALISE_MEMBER(byteStride); SERIALISE_MEMBER(perInstance); + SERIALISE_MEMBER(instanceDivisor); - SIZE_CHECK(12); + SIZE_CHECK(16); } template