mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Add support for VK_EXT_vertex_attribute_divisor
This commit is contained in:
@@ -917,9 +917,12 @@ rdcarray<VertexInputAttribute> 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;
|
||||
|
||||
@@ -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)));
|
||||
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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); \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -155,6 +155,9 @@ struct VulkanCreationInfo
|
||||
uint32_t vbufferBinding;
|
||||
uint32_t bytestride;
|
||||
bool perInstance;
|
||||
|
||||
// VkVertexInputBindingDivisorDescriptionEXT
|
||||
uint32_t instanceDivisor;
|
||||
};
|
||||
vector<Binding> vertexBindings;
|
||||
|
||||
|
||||
@@ -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<bool> isInstanced,
|
||||
const char *entryName, std::vector<uint32_t> instDivisor,
|
||||
uint32_t &descSet, const DrawcallDescription *draw,
|
||||
int32_t indexOffset, uint64_t numFetchVerts, uint32_t numVerts,
|
||||
std::vector<uint32_t> &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<int32_t>(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<bool> attrIsInstanced;
|
||||
std::vector<uint32_t> 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};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 <typename SerialiserType>
|
||||
static void SerialiseNext(SerialiserType &ser, VkStructureType &sType, const void *&pNext)
|
||||
@@ -2301,6 +2305,31 @@ void Deserialise(const VkRenderPassInputAttachmentAspectCreateInfoKHR &el)
|
||||
delete[] el.pAspectReferences;
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, VkVertexInputBindingDivisorDescriptionEXT &el)
|
||||
{
|
||||
SERIALISE_MEMBER(binding);
|
||||
SERIALISE_MEMBER(divisor);
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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<string> Layers;
|
||||
for(uint32_t i = 0; i < createInfo.enabledLayerCount; i++)
|
||||
Layers.push_back(createInfo.ppEnabledLayerNames[i]);
|
||||
|
||||
@@ -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 <typename SerialiserType>
|
||||
|
||||
Reference in New Issue
Block a user