Merge pull request #236 from cdavis5e/push-descriptor

Support the VK_KHR_push_descriptor extension.
This commit is contained in:
Bill Hollings 2018-09-01 13:38:24 -04:00 committed by GitHub
commit 93541e494e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 372 additions and 1 deletions

View File

@ -131,6 +131,35 @@ private:
};
#pragma mark -
#pragma mark MVKCmdPushDescriptorSet
/** Vulkan command to update a descriptor set. */
class MVKCmdPushDescriptorSet : public MVKCommand {
public:
void setContent(VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites);
void encode(MVKCommandEncoder* cmdEncoder) override;
MVKCmdPushDescriptorSet(MVKCommandTypePool<MVKCmdPushDescriptorSet>* pool);
~MVKCmdPushDescriptorSet() override;
private:
void clearDescriptorWrites();
VkPipelineBindPoint _pipelineBindPoint;
MVKPipelineLayout* _pipelineLayout;
std::vector<VkWriteDescriptorSet> _descriptorWrites;
uint32_t _set;
};
#pragma mark -
#pragma mark Command creation functions
@ -168,3 +197,11 @@ void mvkCmdPushConstants(MVKCommandBuffer* cmdBuff,
uint32_t offset,
uint32_t size,
const void* pValues);
/** Adds commands to the specified command buffer that update the specified descriptor set. */
void mvkCmdPushDescriptorSet(MVKCommandBuffer* cmdBuff,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites);

View File

@ -179,6 +179,64 @@ MVKCmdPushConstants::MVKCmdPushConstants(MVKCommandTypePool<MVKCmdPushConstants>
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark MVKCmdPushDescriptorSet
void MVKCmdPushDescriptorSet::setContent(VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites) {
_pipelineBindPoint = pipelineBindPoint;
_pipelineLayout = (MVKPipelineLayout*)layout;
_set = set;
// Add the descriptor writes
clearDescriptorWrites(); // Clear for reuse
_descriptorWrites.reserve(descriptorWriteCount);
for (uint32_t dwIdx = 0; dwIdx < descriptorWriteCount; dwIdx++) {
_descriptorWrites.push_back(pDescriptorWrites[dwIdx]);
VkWriteDescriptorSet& descWrite = _descriptorWrites.back();
// Make a copy of the associated data.
if (descWrite.pImageInfo) {
auto* pNewImageInfo = new VkDescriptorImageInfo[descWrite.descriptorCount];
std::copy_n(descWrite.pImageInfo, descWrite.descriptorCount, pNewImageInfo);
descWrite.pImageInfo = pNewImageInfo;
}
if (descWrite.pBufferInfo) {
auto* pNewBufferInfo = new VkDescriptorBufferInfo[descWrite.descriptorCount];
std::copy_n(descWrite.pBufferInfo, descWrite.descriptorCount, pNewBufferInfo);
descWrite.pBufferInfo = pNewBufferInfo;
}
if (descWrite.pTexelBufferView) {
auto* pNewTexelBufferView = new VkBufferView[descWrite.descriptorCount];
std::copy_n(descWrite.pTexelBufferView, descWrite.descriptorCount, pNewTexelBufferView);
descWrite.pTexelBufferView = pNewTexelBufferView;
}
}
}
void MVKCmdPushDescriptorSet::encode(MVKCommandEncoder* cmdEncoder) {
_pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites, _set);
}
MVKCmdPushDescriptorSet::MVKCmdPushDescriptorSet(MVKCommandTypePool<MVKCmdPushDescriptorSet>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
MVKCmdPushDescriptorSet::~MVKCmdPushDescriptorSet() {
clearDescriptorWrites();
}
void MVKCmdPushDescriptorSet::clearDescriptorWrites() {
for (VkWriteDescriptorSet &descWrite : _descriptorWrites) {
if (descWrite.pImageInfo) delete[] descWrite.pImageInfo;
if (descWrite.pBufferInfo) delete[] descWrite.pBufferInfo;
if (descWrite.pTexelBufferView) delete[] descWrite.pTexelBufferView;
}
_descriptorWrites.clear();
}
#pragma mark -
#pragma mark Command creation functions
@ -232,3 +290,13 @@ void mvkCmdPushConstants(MVKCommandBuffer* cmdBuff,
cmdBuff->addCommand(cmd);
}
void mvkCmdPushDescriptorSet(MVKCommandBuffer* cmdBuff,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites) {
MVKCmdPushDescriptorSet* cmd = cmdBuff->_commandPool->_cmdPushDescriptorSetPool.acquireObject();
cmd->setContent(pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites);
cmdBuff->addCommand(cmd);
}

View File

@ -131,6 +131,8 @@ public:
MVKCommandTypePool<MVKCmdDispatchIndirect> _cmdDispatchIndirectPool;
MVKCommandTypePool<MVKCmdPushDescriptorSet> _cmdPushDescriptorSetPool;
#pragma mark Command resources

View File

@ -118,7 +118,8 @@ MVKCommandPool::MVKCommandPool(MVKDevice* device,
_cmdCopyQueryPoolResultsPool(this, true),
_cmdPushConstantsPool(this, true),
_cmdDispatchPool(this, true),
_cmdDispatchIndirectPool(this, true)
_cmdDispatchIndirectPool(this, true),
_cmdPushDescriptorSetPool(this, true)
{}
// TODO: Destroying a command pool implicitly destroys all command buffers and commands created from it.

View File

@ -78,6 +78,16 @@ public:
std::vector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
/** Encodes this binding layout and the specified descriptor binding on the specified command encoder immediately. */
void push(MVKCommandEncoder* cmdEncoder,
uint32_t& dstArrayElement,
uint32_t& descriptorCount,
VkDescriptorType descriptorType,
const VkDescriptorImageInfo*& pImageInfo,
const VkDescriptorBufferInfo*& pBufferInfo,
const VkBufferView*& pTexelBufferView,
MVKShaderResourceBinding& dslMTLRezIdxOffsets);
/** Populates the specified shader converter context, at the specified descriptor set binding. */
void populateShaderConverterContext(SPIRVToMSLConverterContext& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
@ -119,11 +129,20 @@ public:
uint32_t* pDynamicOffsetIndex);
/** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */
void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
std::vector<VkWriteDescriptorSet>& descriptorWrites,
MVKShaderResourceBinding& dslMTLRezIdxOffsets);
/** Populates the specified shader converter context, at the specified DSL index. */
void populateShaderConverterContext(SPIRVToMSLConverterContext& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex);
/** Returns true if this layout is for push descriptors only. */
bool isPushDescriptorLayout() const { return _isPushDescriptorLayout; }
/** Constructs an instance for the specified device. */
MVKDescriptorSetLayout(MVKDevice* device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo);
@ -135,6 +154,7 @@ protected:
std::vector<MVKDescriptorSetLayoutBinding> _bindings;
MVKShaderResourceBinding _mtlResourceCounts;
bool _isPushDescriptorLayout : 1;
};

View File

@ -173,6 +173,172 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
}
}
void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder,
uint32_t& dstArrayElement,
uint32_t& descriptorCount,
VkDescriptorType descriptorType,
const VkDescriptorImageInfo*& pImageInfo,
const VkDescriptorBufferInfo*& pBufferInfo,
const VkBufferView*& pTexelBufferView,
MVKShaderResourceBinding& dslMTLRezIdxOffsets) {
MVKMTLBufferBinding bb;
MVKMTLTextureBinding tb;
MVKMTLSamplerStateBinding sb;
if (dstArrayElement >= _info.descriptorCount) {
dstArrayElement -= _info.descriptorCount;
return;
}
if (descriptorType != _info.descriptorType) {
dstArrayElement = 0;
if (_info.descriptorCount > descriptorCount)
descriptorCount = 0;
else {
descriptorCount -= _info.descriptorCount;
pImageInfo += _info.descriptorCount;
pBufferInfo += _info.descriptorCount;
pTexelBufferView += _info.descriptorCount;
}
return;
}
// Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding.
MVKShaderResourceBinding mtlIdxs = _mtlResourceIndexOffsets + dslMTLRezIdxOffsets;
for (uint32_t rezIdx = dstArrayElement;
rezIdx < _info.descriptorCount && rezIdx - dstArrayElement < descriptorCount;
rezIdx++) {
switch (_info.descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
const VkDescriptorBufferInfo& bufferInfo = pBufferInfo[rezIdx - dstArrayElement];
MVKBuffer* buffer = (MVKBuffer*)bufferInfo.buffer;
bb.mtlBuffer = buffer->getMTLBuffer();
bb.offset = bufferInfo.offset;
if (_applyToVertexStage) {
bb.index = mtlIdxs.vertexStage.bufferIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexBuffer(bb);
}
if (_applyToFragmentStage) {
bb.index = mtlIdxs.fragmentStage.bufferIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentBuffer(bb);
}
if (_applyToComputeStage) {
bb.index = mtlIdxs.computeStage.bufferIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindBuffer(bb);
}
break;
}
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
const VkDescriptorImageInfo& imageInfo = pImageInfo[rezIdx - dstArrayElement];
MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
tb.mtlTexture = imageView->getMTLTexture();
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
}
if (_applyToFragmentStage) {
tb.index = mtlIdxs.fragmentStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentTexture(tb);
}
if (_applyToComputeStage) {
tb.index = mtlIdxs.computeStage.textureIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindTexture(tb);
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
MVKBufferView* bufferView = (MVKBufferView*)pTexelBufferView[rezIdx - dstArrayElement];
tb.mtlTexture = bufferView->getMTLTexture();
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
}
if (_applyToFragmentStage) {
tb.index = mtlIdxs.fragmentStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentTexture(tb);
}
if (_applyToComputeStage) {
tb.index = mtlIdxs.computeStage.textureIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindTexture(tb);
}
break;
}
case VK_DESCRIPTOR_TYPE_SAMPLER: {
MVKSampler* sampler;
if (_immutableSamplers.empty())
sampler = (MVKSampler*)pImageInfo[rezIdx - dstArrayElement].sampler;
else
sampler = _immutableSamplers[rezIdx];
sb.mtlSamplerState = sampler->getMTLSamplerState();
if (_applyToVertexStage) {
sb.index = mtlIdxs.vertexStage.samplerIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexSamplerState(sb);
}
if (_applyToFragmentStage) {
sb.index = mtlIdxs.fragmentStage.samplerIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentSamplerState(sb);
}
if (_applyToComputeStage) {
sb.index = mtlIdxs.computeStage.samplerIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindSamplerState(sb);
}
break;
}
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
const VkDescriptorImageInfo& imageInfo = pImageInfo[rezIdx - dstArrayElement];
MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
MVKSampler* sampler = _immutableSamplers.empty() ? (MVKSampler*)imageInfo.sampler : _immutableSamplers[rezIdx];
tb.mtlTexture = imageView->getMTLTexture();
sb.mtlSamplerState = sampler->getMTLSamplerState();
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
sb.index = mtlIdxs.vertexStage.samplerIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexSamplerState(sb);
}
if (_applyToFragmentStage) {
tb.index = mtlIdxs.fragmentStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentTexture(tb);
sb.index = mtlIdxs.fragmentStage.samplerIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindFragmentSamplerState(sb);
}
if (_applyToComputeStage) {
tb.index = mtlIdxs.computeStage.textureIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindTexture(tb);
sb.index = mtlIdxs.computeStage.samplerIndex + rezIdx;
cmdEncoder->_computeResourcesState.bindSamplerState(sb);
}
break;
}
default:
break;
}
}
dstArrayElement = 0;
if (_info.descriptorCount > descriptorCount)
descriptorCount = 0;
else {
descriptorCount -= _info.descriptorCount;
pImageInfo += _info.descriptorCount;
pBufferInfo += _info.descriptorCount;
pTexelBufferView += _info.descriptorCount;
}
}
void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(SPIRVToMSLConverterContext& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex) {
@ -300,6 +466,7 @@ void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
vector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
if (_isPushDescriptorLayout) return;
uint32_t bindCnt = (uint32_t)_bindings.size();
for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
_bindings[bindIdx].bind(cmdEncoder, descSet->_bindings[bindIdx],
@ -308,6 +475,28 @@ void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
}
}
void MVKDescriptorSetLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
vector<VkWriteDescriptorSet>& descriptorWrites,
MVKShaderResourceBinding& dslMTLRezIdxOffsets) {
if (!_isPushDescriptorLayout) return;
for (const VkWriteDescriptorSet& descWrite : descriptorWrites) {
uint32_t bindIdx = descWrite.dstBinding;
uint32_t dstArrayElement = descWrite.dstArrayElement;
uint32_t descriptorCount = descWrite.descriptorCount;
const VkDescriptorImageInfo* pImageInfo = descWrite.pImageInfo;
const VkDescriptorBufferInfo* pBufferInfo = descWrite.pBufferInfo;
const VkBufferView* pTexelBufferView = descWrite.pTexelBufferView;
// Note: This will result in us walking off the end of the array
// in case there are too many updates... but that's ill-defined anyway.
for (; descriptorCount; bindIdx++) {
_bindings[bindIdx].push(cmdEncoder, dstArrayElement, descriptorCount,
descWrite.descriptorType, pImageInfo, pBufferInfo,
pTexelBufferView, dslMTLRezIdxOffsets);
}
}
}
void MVKDescriptorSetLayout::populateShaderConverterContext(SPIRVToMSLConverterContext& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex) {
@ -319,6 +508,7 @@ void MVKDescriptorSetLayout::populateShaderConverterContext(SPIRVToMSLConverterC
MVKDescriptorSetLayout::MVKDescriptorSetLayout(MVKDevice* device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {
_isPushDescriptorLayout = (pCreateInfo->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) != 0;
// Create the descriptor bindings
_bindings.reserve(pCreateInfo->bindingCount);
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
@ -616,6 +806,7 @@ VkResult MVKDescriptorPool::allocateDescriptorSets(uint32_t count,
for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
MVKDescriptorSetLayout* mvkDSL = (MVKDescriptorSetLayout*)pSetLayouts[dsIdx];
if (mvkDSL->isPushDescriptorLayout()) continue;
MVKDescriptorSet* mvkDescSet = new MVKDescriptorSet(_device, mvkDSL);
_allocatedSets.push_front(mvkDescSet);
pDescriptorSets[dsIdx] = (VkDescriptorSet)mvkDescSet;

View File

@ -77,6 +77,20 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2KHR* properties
if (properties) {
properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
properties->properties = _properties;
auto* next = (VkStructureType*)properties->pNext;
while (next) {
switch (*next) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
next = (VkStructureType*)pushDescProps->pNext;
break;
}
default:
next = *(VkStructureType**)(next+1);
break;
}
}
}
}

View File

@ -249,6 +249,7 @@ void MVKInstance::initProcAddrs() {
ADD_PROC_ADDR(vkGetPhysicalDeviceQueueFamilyProperties2KHR);
ADD_PROC_ADDR(vkGetPhysicalDeviceMemoryProperties2KHR);
ADD_PROC_ADDR(vkGetPhysicalDeviceSparseImageFormatProperties2KHR);
ADD_PROC_ADDR(vkCmdPushDescriptorSetKHR);
ADD_PROC_ADDR(vkGetMoltenVKConfigurationMVK);
ADD_PROC_ADDR(vkSetMoltenVKConfigurationMVK);
ADD_PROC_ADDR(vkGetPhysicalDeviceMetalFeaturesMVK);

View File

@ -50,6 +50,11 @@ public:
/** Populates the specified shader converter context. */
void populateShaderConverterContext(SPIRVToMSLConverterContext& context);
/** Updates a descriptor set in a command encoder. */
void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
std::vector<VkWriteDescriptorSet>& descriptorWrites,
uint32_t set);
/** Constructs an instance for the specified device. */
MVKPipelineLayout(MVKDevice* device, const VkPipelineLayoutCreateInfo* pCreateInfo);

View File

@ -54,6 +54,17 @@ void MVKPipelineLayout::bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
cmdEncoder->getPushConstants(VK_SHADER_STAGE_COMPUTE_BIT)->setMTLBufferIndex(_pushConstantsMTLResourceIndexOffsets.computeStage.bufferIndex);
}
void MVKPipelineLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
vector<VkWriteDescriptorSet>& descriptorWrites,
uint32_t set) {
_descriptorSetLayouts[set].pushDescriptorSet(cmdEncoder, descriptorWrites,
_dslMTLResourceIndexOffsets[set]);
cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->setMTLBufferIndex(_pushConstantsMTLResourceIndexOffsets.vertexStage.bufferIndex);
cmdEncoder->getPushConstants(VK_SHADER_STAGE_FRAGMENT_BIT)->setMTLBufferIndex(_pushConstantsMTLResourceIndexOffsets.fragmentStage.bufferIndex);
cmdEncoder->getPushConstants(VK_SHADER_STAGE_COMPUTE_BIT)->setMTLBufferIndex(_pushConstantsMTLResourceIndexOffsets.computeStage.bufferIndex);
}
void MVKPipelineLayout::populateShaderConverterContext(SPIRVToMSLConverterContext& context) {
context.resourceBindings.clear();

View File

@ -107,6 +107,11 @@ MVKLayer::MVKLayer() {
extTmplt.specVersion = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION;
_extensions.push_back(extTmplt);
memset(extTmplt.extensionName, 0, sizeof(extTmplt.extensionName));
strcpy(extTmplt.extensionName, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
extTmplt.specVersion = VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION;
_extensions.push_back(extTmplt);
#if MVK_IOS
memset(extTmplt.extensionName, 0, sizeof(extTmplt.extensionName));
strcpy(extTmplt.extensionName, VK_MVK_IOS_SURFACE_EXTENSION_NAME);

View File

@ -1677,6 +1677,22 @@ MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
}
#pragma mark -
#pragma mark VK_KHR_push_descriptor extension
MVK_PUBLIC_SYMBOL void vkCmdPushDescriptorSetKHR(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites) {
MVKCommandBuffer* cmdBuff = MVKCommandBuffer::getMVKCommandBuffer(commandBuffer);
mvkCmdPushDescriptorSet(cmdBuff, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites);
}
#pragma mark -
#pragma mark Loader and Layer ICD interface extension