Each MVKDescriptorBinding respresents only one resource slot.

Remove arrays of slots from MVKDescriptorBinding. For array types, multiple
MVKDescriptorBindings map to one corresponding MVKDescriptorLayoutBinding.
Simplify logic of copying and writing to descriptors.
This commit is contained in:
Bill Hollings 2020-01-09 17:57:00 -05:00
parent 8bca6709a1
commit 2c6f33e793
4 changed files with 239 additions and 377 deletions

View File

@ -69,12 +69,23 @@ public:
/** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override;
/** Encodes this binding layout and the specified descriptor set binding on the specified command encoder. */
void bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorBinding& descBinding,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
/** Returns the binding number of this layout. */
inline uint32_t getBinding() { return _info.binding; }
/** Returns the number of descriptors in this layout. */
inline uint32_t getDescriptorCount() { return _info.descriptorCount; }
/**
* Encodes the descriptors in the descriptor set that are specified by this layout,
* starting with the descriptor at the index, on the the command encoder.
* Returns the number of descriptors that were encoded.
*/
uint32_t bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
uint32_t descStartIndex,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
MVKVector<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,
@ -91,14 +102,12 @@ public:
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex);
/** Constructs an instance. */
MVKDescriptorSetLayoutBinding(MVKDevice* device,
MVKDescriptorSetLayout* layout,
const VkDescriptorSetLayoutBinding* pBinding);
MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding);
/** Destuctor. */
~MVKDescriptorSetLayoutBinding() override;
protected:
@ -129,84 +138,46 @@ public:
MVKVulkanAPIObject* getVulkanAPIObject() override;
/**
* Updates the internal element bindings from the specified content.
*
* Depending on the descriptor type of the descriptor set, the binding content is
* extracted from one of the specified pImageInfo, pBufferInfo, or pTexelBufferView
* arrays, and the other arrays are ignored (and may be a null pointer).
*
* The srcStartIndex parameter indicates the index of the initial pDescriptor element
* at which to start reading, and the dstStartIndex parameter indicates the index of
* the initial internal element at which to start writing.
*
* The count parameter indicates how many internal elements should be updated, and
* may be larger than the number of descriptors that can be updated in this instance.
* If count is larger than the number of internal elements remaining after dstStartIndex,
* only the remaining elements will be updated, and the number of pDescriptors that were
* not read will be returned, so that the remaining unread pDescriptors can be read by
* another MVKDescriptorBinding instance within the same descriptor set. If all of the
* remaining pDescriptors are read by this intance, this function returns zero, indicating
* that there is nothing left to be read by another MVKDescriptorBinding instance.
* Updates the internal binding from the specified content. The format of the content depends
* on the descriptor type, and is extracted from pData at the location given by srcIndex * stride.
*/
uint32_t writeBindings(uint32_t srcStartIndex,
uint32_t dstStartIndex,
uint32_t count,
size_t stride,
const void* pData);
void writeBinding(uint32_t srcIndex, size_t stride, const void* pData);
/**
* Updates the specified content arrays from the internal element bindings.
* Updates the specified content arrays from the internal binding.
*
* Depending on the descriptor type of the descriptor set, the binding content is
* placed into one of the specified pImageInfo, pBufferInfo, or pTexelBufferView
* placed into one of the specified pImageInfo, pBufferInfo, or pTexelBufferView
* arrays, and the other arrays are ignored (and may be a null pointer).
*
* The srcStartIndex parameter indicates the index of the initial internal element
* at which to start reading, and the dstStartIndex parameter indicates the index of
* the initial pDescriptor element at which to start writing.
*
* The count parameter indicates how many internal elements should be read, and may
* be larger than the number of descriptors that can be read from this instance.
* If count is larger than the number of internal elements remaining after srcStartIndex,
* only the remaining elements will be read, and the number of pDescriptors that were not
* updated will be returned, so that the remaining pDescriptors can be updated by another
* MVKDescriptorBinding instance within the same descriptor set. If all of the remaining
* pDescriptors are updated by this intance, this function returns zero, indicating that
* there is nothing left to be updated by another MVKDescriptorBinding instance.
* The dstIndex parameter indicates the index of the initial descriptor element
* at which to start writing.
*/
uint32_t readBindings(uint32_t srcStartIndex,
uint32_t dstStartIndex,
uint32_t count,
VkDescriptorType& descType,
VkDescriptorImageInfo* pImageInfo,
VkDescriptorBufferInfo* pBufferInfo,
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock);
void readBinding(uint32_t dstIndex,
VkDescriptorType& descType,
VkDescriptorImageInfo* pImageInfo,
VkDescriptorBufferInfo* pBufferInfo,
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock);
/** Returns whether this instance represents the specified Vulkan binding point. */
bool hasBinding(uint32_t binding);
MVKDescriptorBinding(MVKDescriptorSet* pDescSet, MVKDescriptorSetLayoutBinding* pBindingLayout, uint32_t index);
/** Constructs an instance. */
MVKDescriptorBinding(MVKDescriptorSet* pDescSet, MVKDescriptorSetLayoutBinding* pBindingLayout);
/** Destructor. */
~MVKDescriptorBinding();
protected:
friend class MVKDescriptorSetLayoutBinding;
void initMTLSamplers(MVKDescriptorSetLayoutBinding* pBindingLayout);
bool validate(MVKSampler* mvkSampler) { return _pBindingLayout->validate(mvkSampler); }
MVKDescriptorSet* _pDescSet;
MVKDescriptorSetLayoutBinding* _pBindingLayout;
std::vector<VkDescriptorImageInfo> _imageBindings;
std::vector<VkDescriptorBufferInfo> _bufferBindings;
std::vector<VkWriteDescriptorSetInlineUniformBlockEXT> _inlineBindings;
std::vector<VkBufferView> _texelBufferBindings;
std::vector<id<MTLBuffer>> _mtlBuffers;
std::vector<NSUInteger> _mtlBufferOffsets;
std::vector<id<MTLTexture>> _mtlTextures;
std::vector<id<MTLSamplerState>> _mtlSamplers;
bool _hasDynamicSamplers;
VkDescriptorImageInfo _imageBinding = {};
VkDescriptorBufferInfo _bufferBinding = {};
VkWriteDescriptorSetInlineUniformBlockEXT _inlineBinding = {};
VkBufferView _texelBufferBinding = nullptr;
id<MTLBuffer> _mtlBuffer = nil;
NSUInteger _mtlBufferOffset = 0;
id<MTLTexture> _mtlTexture = nil;
id<MTLSamplerState> _mtlSampler = nil;
bool _hasDynamicSampler;
};

View File

@ -78,11 +78,12 @@ MVKShaderResourceBinding& MVKShaderResourceBinding::operator+= (const MVKShaderR
MVKVulkanAPIObject* MVKDescriptorSetLayoutBinding::getVulkanAPIObject() { return _layout; };
// A null cmdEncoder can be passed to perform a validation pass
void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorBinding& descBinding,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
uint32_t MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
uint32_t descStartIndex,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLBufferBinding bb;
MVKMTLTextureBinding tb;
MVKMTLSamplerStateBinding sb;
@ -91,8 +92,12 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
// 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 = 0; rezIdx < _info.descriptorCount; rezIdx++) {
switch (_info.descriptorType) {
uint32_t descCnt = _info.descriptorCount;
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
MVKDescriptorBinding* descBinding = descSet->getDescriptor(descStartIndex + descIdx);
switch (_info.descriptorType) {
// After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
@ -101,13 +106,13 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
(*pDynamicOffsetIndex)++; // Move on to next dynamic offset (and feedback to caller)
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
MVKBuffer* mvkBuff = (MVKBuffer*)descBinding._bufferBindings[rezIdx].buffer;
bb.mtlBuffer = descBinding._mtlBuffers[rezIdx];
bb.offset = descBinding._mtlBufferOffsets[rezIdx] + bufferDynamicOffset;
MVKBuffer* mvkBuff = (MVKBuffer*)descBinding->_bufferBinding.buffer;
bb.mtlBuffer = descBinding->_mtlBuffer;
bb.offset = descBinding->_mtlBufferOffset + bufferDynamicOffset;
bb.size = mvkBuff ? (uint32_t)mvkBuff->getByteCount() : 0;
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
bb.index = mtlIdxs.stages[i].bufferIndex + descIdx;
if (i == kMVKShaderStageCompute) {
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
} else {
@ -119,12 +124,12 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
}
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
bb.mtlBuffer = descBinding._mtlBuffers[rezIdx];
bb.offset = descBinding._mtlBufferOffsets[rezIdx];
bb.size = descBinding._inlineBindings[rezIdx].dataSize;
bb.mtlBuffer = descBinding->_mtlBuffer;
bb.offset = descBinding->_mtlBufferOffset;
bb.size = descBinding->_inlineBinding.dataSize;
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
bb.index = mtlIdxs.stages[i].bufferIndex + descIdx;
if (i == kMVKShaderStageCompute) {
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
} else {
@ -140,15 +145,15 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
tb.mtlTexture = descBinding._mtlTextures[rezIdx];
tb.mtlTexture = descBinding->_mtlTexture;
if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && tb.mtlTexture) {
tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle();
tb.swizzle = ((MVKImageView*)descBinding->_imageBinding.imageView)->getPackedSwizzle();
} else {
tb.swizzle = 0;
}
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
tb.index = mtlIdxs.stages[i].textureIndex + rezIdx;
tb.index = mtlIdxs.stages[i].textureIndex + descIdx;
if (i == kMVKShaderStageCompute) {
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
} else {
@ -160,10 +165,10 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
}
case VK_DESCRIPTOR_TYPE_SAMPLER: {
sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx];
sb.mtlSamplerState = descBinding->_mtlSampler;
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx;
sb.index = mtlIdxs.stages[i].samplerIndex + descIdx;
if (i == kMVKShaderStageCompute) {
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); }
} else {
@ -175,17 +180,17 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
}
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
tb.mtlTexture = descBinding._mtlTextures[rezIdx];
tb.mtlTexture = descBinding->_mtlTexture;
if (tb.mtlTexture) {
tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle();
tb.swizzle = ((MVKImageView*)descBinding->_imageBinding.imageView)->getPackedSwizzle();
} else {
tb.swizzle = 0;
}
sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx];
sb.mtlSamplerState = descBinding->_mtlSampler;
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
tb.index = mtlIdxs.stages[i].textureIndex + rezIdx;
sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx;
tb.index = mtlIdxs.stages[i].textureIndex + descIdx;
sb.index = mtlIdxs.stages[i].samplerIndex + descIdx;
if (i == kMVKShaderStageCompute) {
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); }
@ -202,6 +207,7 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
break;
}
}
return descCnt;
}
template<typename T>
@ -546,155 +552,129 @@ void MVKDescriptorSetLayoutBinding::initMetalResourceIndexOffsets(MVKShaderStage
MVKVulkanAPIObject* MVKDescriptorBinding::getVulkanAPIObject() { return _pDescSet->getVulkanAPIObject(); };
uint32_t MVKDescriptorBinding::writeBindings(uint32_t srcStartIndex,
uint32_t dstStartIndex,
uint32_t count,
size_t stride,
const void* pData) {
uint32_t dstCnt = MIN(count, _pBindingLayout->_info.descriptorCount - dstStartIndex);
void MVKDescriptorBinding::writeBinding(uint32_t srcIndex, size_t stride, const void* pData) {
switch (_pBindingLayout->_info.descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcStartIndex + i);
auto* oldSampler = (MVKSampler*)_imageBindings[dstIdx].sampler;
_imageBindings[dstIdx] = *pImgInfo;
_imageBindings[dstIdx].imageView = nullptr; // Sampler only. Guard against app not explicitly clearing ImageView.
if (_hasDynamicSamplers) {
auto* mvkSampler = (MVKSampler*)pImgInfo->sampler;
validate(mvkSampler);
mvkSampler->retain();
_mtlSamplers[dstIdx] = mvkSampler ? mvkSampler->getMTLSamplerState() : nil;
} else {
_imageBindings[dstIdx].sampler = nullptr; // Guard against app not explicitly clearing Sampler.
}
if (oldSampler) {
oldSampler->release();
}
case VK_DESCRIPTOR_TYPE_SAMPLER: {
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcIndex);
auto* oldSampler = (MVKSampler*)_imageBinding.sampler;
_imageBinding = *pImgInfo;
_imageBinding.imageView = nullptr; // Sampler only. Guard against app not explicitly clearing ImageView.
if (_hasDynamicSampler) {
auto* mvkSampler = (MVKSampler*)pImgInfo->sampler;
validate(mvkSampler);
mvkSampler->retain();
_mtlSampler = mvkSampler ? mvkSampler->getMTLSamplerState() : nil;
} else {
_imageBinding.sampler = nullptr; // Guard against app not explicitly clearing Sampler.
}
if (oldSampler) {
oldSampler->release();
}
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcStartIndex + i);
auto* mvkImageView = (MVKImageView*)pImgInfo->imageView;
auto* oldImageView = (MVKImageView*)_imageBindings[dstIdx].imageView;
auto* oldSampler = (MVKSampler*)_imageBindings[dstIdx].sampler;
mvkImageView->retain();
_imageBindings[dstIdx] = *pImgInfo;
_mtlTextures[dstIdx] = mvkImageView ? mvkImageView->getMTLTexture() : nil;
if (_hasDynamicSamplers) {
auto* mvkSampler = (MVKSampler*)pImgInfo->sampler;
validate(mvkSampler);
mvkSampler->retain();
_mtlSamplers[dstIdx] = mvkSampler ? mvkSampler->getMTLSamplerState() : nil;
} else {
_imageBindings[dstIdx].sampler = nullptr; // Guard against app not explicitly clearing Sampler.
}
if (oldImageView) {
oldImageView->release();
}
if (oldSampler) {
oldSampler->release();
}
}
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcIndex);
auto* mvkImageView = (MVKImageView*)pImgInfo->imageView;
auto* oldImageView = (MVKImageView*)_imageBinding.imageView;
auto* oldSampler = (MVKSampler*)_imageBinding.sampler;
mvkImageView->retain();
_imageBinding = *pImgInfo;
_mtlTexture = mvkImageView ? mvkImageView->getMTLTexture() : nil;
if (_hasDynamicSampler) {
auto* mvkSampler = (MVKSampler*)pImgInfo->sampler;
validate(mvkSampler);
mvkSampler->retain();
_mtlSampler = mvkSampler ? mvkSampler->getMTLSamplerState() : nil;
} else {
_imageBinding.sampler = nullptr; // Guard against app not explicitly clearing Sampler.
}
if (oldImageView) {
oldImageView->release();
}
if (oldSampler) {
oldSampler->release();
}
break;
}
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcStartIndex + i);
auto* mvkImageView = (MVKImageView*)pImgInfo->imageView;
auto* oldImageView = (MVKImageView*)_imageBindings[dstIdx].imageView;
if (mvkImageView) {
mvkImageView->retain();
}
_imageBindings[dstIdx] = *pImgInfo;
_imageBindings[dstIdx].sampler = nullptr; // ImageView only. Guard against app not explicitly clearing Sampler.
_mtlTextures[dstIdx] = mvkImageView ? mvkImageView->getMTLTexture() : nil;
if (oldImageView) {
oldImageView->release();
}
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcIndex);
auto* mvkImageView = (MVKImageView*)pImgInfo->imageView;
auto* oldImageView = (MVKImageView*)_imageBinding.imageView;
if (mvkImageView) {
mvkImageView->retain();
}
_imageBinding = *pImgInfo;
_imageBinding.sampler = nullptr; // ImageView only. Guard against app not explicitly clearing Sampler.
_mtlTexture = mvkImageView ? mvkImageView->getMTLTexture() : nil;
if (oldImageView) {
oldImageView->release();
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto* pBuffInfo = &get<VkDescriptorBufferInfo>(pData, stride, srcStartIndex + i);
auto* oldBuff = (MVKBuffer*)_bufferBindings[dstIdx].buffer;
_bufferBindings[dstIdx] = *pBuffInfo;
auto* mtlBuff = (MVKBuffer*)pBuffInfo->buffer;
if (mtlBuff) {
mtlBuff->retain();
}
_mtlBuffers[dstIdx] = mtlBuff ? mtlBuff->getMTLBuffer() : nil;
_mtlBufferOffsets[dstIdx] = mtlBuff ? (mtlBuff->getMTLBufferOffset() + pBuffInfo->offset) : 0;
if (oldBuff) {
oldBuff->release();
}
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
const auto* pBuffInfo = &get<VkDescriptorBufferInfo>(pData, stride, srcIndex);
auto* oldBuff = (MVKBuffer*)_bufferBinding.buffer;
_bufferBinding = *pBuffInfo;
auto* mtlBuff = (MVKBuffer*)pBuffInfo->buffer;
if (mtlBuff) {
mtlBuff->retain();
}
_mtlBuffer = mtlBuff ? mtlBuff->getMTLBuffer() : nil;
_mtlBufferOffset = mtlBuff ? (mtlBuff->getMTLBufferOffset() + pBuffInfo->offset) : 0;
if (oldBuff) {
oldBuff->release();
}
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto* pBuffView = &get<VkBufferView>(pData, stride, srcStartIndex + i);
auto* mvkBuffView = (MVKBufferView*)*pBuffView;
auto* oldBuffView = (MVKBufferView*)_texelBufferBindings[dstIdx];
if (mvkBuffView) {
mvkBuffView->retain();
}
_texelBufferBindings[dstIdx] = *pBuffView;
_mtlTextures[dstIdx] = mvkBuffView ? mvkBuffView->getMTLTexture() : nil;
if (oldBuffView) {
oldBuffView->release();
}
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
const auto* pBuffView = &get<VkBufferView>(pData, stride, srcIndex);
auto* mvkBuffView = (MVKBufferView*)*pBuffView;
auto* oldBuffView = (MVKBufferView*)_texelBufferBinding;
if (mvkBuffView) {
mvkBuffView->retain();
}
_texelBufferBinding = *pBuffView;
_mtlTexture = mvkBuffView ? mvkBuffView->getMTLTexture() : nil;
if (oldBuffView) {
oldBuffView->release();
}
break;
}
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
for (uint32_t i = 0; i < dstCnt; i++) {
uint32_t dstIdx = dstStartIndex + i;
const auto& srcInlineUniformBlock = get<VkWriteDescriptorSetInlineUniformBlockEXT>(pData, stride, srcStartIndex + i);
auto& dstInlineUniformBlock = _inlineBindings[dstIdx];
if (srcInlineUniformBlock.dataSize != 0) {
MTLResourceOptions mtlBuffOpts = MTLResourceStorageModeShared | MTLResourceCPUCacheModeDefaultCache;
_mtlBuffers[dstIdx] = [_pDescSet->getMTLDevice() newBufferWithBytes:srcInlineUniformBlock.pData length:srcInlineUniformBlock.dataSize options:mtlBuffOpts];
} else {
_mtlBuffers[dstIdx] = nil;
}
dstInlineUniformBlock.dataSize = srcInlineUniformBlock.dataSize;
dstInlineUniformBlock.pData = nullptr;
}
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
const auto& srcInlineUniformBlock = get<VkWriteDescriptorSetInlineUniformBlockEXT>(pData, stride, srcIndex);
auto& dstInlineUniformBlock = _inlineBinding;
if (srcInlineUniformBlock.dataSize != 0) {
MTLResourceOptions mtlBuffOpts = MTLResourceStorageModeShared | MTLResourceCPUCacheModeDefaultCache;
_mtlBuffer = [_pDescSet->getMTLDevice() newBufferWithBytes:srcInlineUniformBlock.pData length:srcInlineUniformBlock.dataSize options:mtlBuffOpts];
} else {
_mtlBuffer = nil;
}
dstInlineUniformBlock.dataSize = srcInlineUniformBlock.dataSize;
dstInlineUniformBlock.pData = nullptr;
break;
}
default:
break;
}
return count - dstCnt;
}
uint32_t MVKDescriptorBinding::readBindings(uint32_t srcStartIndex,
uint32_t dstStartIndex,
uint32_t count,
VkDescriptorType& descType,
VkDescriptorImageInfo* pImageInfo,
VkDescriptorBufferInfo* pBufferInfo,
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock) {
uint32_t srcCnt = MIN(count, _pBindingLayout->_info.descriptorCount - srcStartIndex);
void MVKDescriptorBinding::readBinding(uint32_t dstIndex,
VkDescriptorType& descType,
VkDescriptorImageInfo* pImageInfo,
VkDescriptorBufferInfo* pBufferInfo,
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock) {
descType = _pBindingLayout->_info.descriptorType;
switch (_pBindingLayout->_info.descriptorType) {
@ -703,103 +683,56 @@ uint32_t MVKDescriptorBinding::readBindings(uint32_t srcStartIndex,
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
for (uint32_t i = 0; i < srcCnt; i++) {
pImageInfo[dstStartIndex + i] = _imageBindings[srcStartIndex + i];
}
pImageInfo[dstIndex] = _imageBinding;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
for (uint32_t i = 0; i < srcCnt; i++) {
pBufferInfo[dstStartIndex + i] = _bufferBindings[srcStartIndex + i];
}
pBufferInfo[dstIndex] = _bufferBinding;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
for (uint32_t i = 0; i < srcCnt; i++) {
pTexelBufferView[dstStartIndex + i] = _texelBufferBindings[srcStartIndex + i];
}
pTexelBufferView[dstIndex] = _texelBufferBinding;
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
for (uint32_t i = 0; i < srcCnt; i++) {
const auto& srcInlineUniformBlock = _inlineBindings[srcStartIndex + i];
auto& dstInlineUniformBlock = pInlineUniformBlock[dstStartIndex + i];
if (dstInlineUniformBlock.pData && dstInlineUniformBlock.pData != srcInlineUniformBlock.pData)
delete [] reinterpret_cast<const uint8_t*>(dstInlineUniformBlock.pData);
if (srcInlineUniformBlock.dataSize != 0) {
dstInlineUniformBlock.pData = reinterpret_cast<const void*>(new uint8_t*[srcInlineUniformBlock.dataSize]);
if (srcInlineUniformBlock.pData) {
memcpy(const_cast<void*>(dstInlineUniformBlock.pData), srcInlineUniformBlock.pData, srcInlineUniformBlock.dataSize);
}
} else {
dstInlineUniformBlock.pData = nullptr;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
const auto& srcInlineUniformBlock = _inlineBinding;
auto& dstInlineUniformBlock = pInlineUniformBlock[dstIndex];
if (dstInlineUniformBlock.pData && dstInlineUniformBlock.pData != srcInlineUniformBlock.pData)
delete [] reinterpret_cast<const uint8_t*>(dstInlineUniformBlock.pData);
if (srcInlineUniformBlock.dataSize != 0) {
dstInlineUniformBlock.pData = reinterpret_cast<const void*>(new uint8_t*[srcInlineUniformBlock.dataSize]);
if (srcInlineUniformBlock.pData) {
memcpy(const_cast<void*>(dstInlineUniformBlock.pData), srcInlineUniformBlock.pData, srcInlineUniformBlock.dataSize);
}
dstInlineUniformBlock.dataSize = srcInlineUniformBlock.dataSize;
} else {
dstInlineUniformBlock.pData = nullptr;
}
dstInlineUniformBlock.dataSize = srcInlineUniformBlock.dataSize;
break;
}
default:
break;
}
return count - srcCnt;
}
bool MVKDescriptorBinding::hasBinding(uint32_t binding) {
return _pBindingLayout->_info.binding == binding;
}
MVKDescriptorBinding::MVKDescriptorBinding(MVKDescriptorSet* pDescSet, MVKDescriptorSetLayoutBinding* pBindingLayout) : _pDescSet(pDescSet) {
uint32_t descCnt = pBindingLayout->_info.descriptorCount;
// Create space for the binding and Metal resources and populate with NULL and zero values
MVKDescriptorBinding::MVKDescriptorBinding(MVKDescriptorSet* pDescSet, MVKDescriptorSetLayoutBinding* pBindingLayout, uint32_t index) : _pDescSet(pDescSet) {
switch (pBindingLayout->_info.descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
_imageBindings.resize(descCnt, VkDescriptorImageInfo());
initMTLSamplers(pBindingLayout);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
_imageBindings.resize(descCnt, VkDescriptorImageInfo());
_mtlTextures.resize(descCnt, nil);
initMTLSamplers(pBindingLayout);
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
_imageBindings.resize(descCnt, VkDescriptorImageInfo());
_mtlTextures.resize(descCnt, nil);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
_bufferBindings.resize(descCnt, VkDescriptorBufferInfo());
_mtlBuffers.resize(descCnt, nil);
_mtlBufferOffsets.resize(descCnt, 0);
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
static const VkWriteDescriptorSetInlineUniformBlockEXT inlineUniformBlock {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT, nullptr, 0, nullptr};
_inlineBindings.resize(descCnt, inlineUniformBlock);
_mtlBuffers.resize(descCnt, nil);
_mtlBufferOffsets.resize(descCnt, 0);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
// If the descriptor set layout binding contains immutable samplers, immediately populate
// the corresponding Metal sampler in this descriptor from it. Otherwise add a null
// placeholder that will be populated dynamically at a later time.
auto imtblSamps = pBindingLayout->_immutableSamplers;
_hasDynamicSampler = imtblSamps.empty();
_mtlSampler = _hasDynamicSampler ? nil : imtblSamps[index]->getMTLSamplerState();
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
_texelBufferBindings.resize(descCnt, nil);
_mtlTextures.resize(descCnt, nil);
break;
default:
break;
}
@ -812,38 +745,8 @@ MVKDescriptorBinding::MVKDescriptorBinding(MVKDescriptorSet* pDescSet, MVKDescri
}
MVKDescriptorBinding::~MVKDescriptorBinding() {
for (const VkDescriptorImageInfo& imgInfo : _imageBindings) {
if (imgInfo.imageView) {
((MVKImageView*)imgInfo.imageView)->release();
}
if (imgInfo.sampler) {
((MVKSampler*)imgInfo.sampler)->release();
}
}
for (const VkDescriptorBufferInfo& buffInfo : _bufferBindings) {
if (buffInfo.buffer) {
((MVKBuffer*)buffInfo.buffer)->release();
}
}
for (VkBufferView buffView : _texelBufferBindings) {
if (buffView) {
((MVKBufferView*)buffView)->release();
}
}
}
/**
* If the descriptor set layout binding contains immutable samplers, immediately populate
* the corresponding Metal sampler in this descriptor binding from it. Otherwise add a null
* placeholder that will be populated dynamically at a later time.
*/
void MVKDescriptorBinding::initMTLSamplers(MVKDescriptorSetLayoutBinding* pBindingLayout) {
uint32_t descCnt = pBindingLayout->_info.descriptorCount;
auto imtblSamps = pBindingLayout->_immutableSamplers;
_hasDynamicSamplers = imtblSamps.empty();
_mtlSamplers.reserve(descCnt);
for (uint32_t i = 0; i < descCnt; i++) {
_mtlSamplers.push_back(_hasDynamicSamplers ? nil : imtblSamps[i]->getMTLSamplerState());
}
if (_imageBinding.imageView) { ((MVKImageView*)_imageBinding.imageView)->release(); }
if (_imageBinding.sampler) { ((MVKSampler*)_imageBinding.sampler)->release(); }
if (_bufferBinding.buffer) { ((MVKBuffer*)_bufferBinding.buffer)->release(); }
if (_texelBufferBinding) { ((MVKBufferView*)_texelBufferBinding)->release(); }
}

View File

@ -85,6 +85,7 @@ protected:
void propogateDebugName() override {}
void addDescriptorPool(MVKDescriptorPool* mvkDescPool) { _descriptorPools.insert(mvkDescPool); }
void removeDescriptorPool(MVKDescriptorPool* mvkDescPool) { _descriptorPools.erase(mvkDescPool); }
uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex);
MVKVectorInline<MVKDescriptorSetLayoutBinding, 1> _bindings;
std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
@ -128,12 +129,12 @@ public:
MVKDescriptorSet(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {}
protected:
friend class MVKDescriptorSetLayout;
friend class MVKDescriptorSetLayoutBinding;
friend class MVKDescriptorPool;
void propogateDebugName() override {}
void setLayout(MVKDescriptorSetLayout* layout);
MVKDescriptorBinding* getBinding(uint32_t binding);
inline MVKDescriptorBinding* getDescriptor(uint32_t index) { return &_bindings[index]; }
MVKDescriptorSetLayout* _pLayout = nullptr;
MVKVectorInline<MVKDescriptorBinding, 1> _bindings;
@ -170,10 +171,8 @@ public:
/** Removes the pool associated with a descriptor set layout. */
void removeDescriptorSetPool(MVKDescriptorSetLayout* mvkDescSetLayout);
/** Constructs an instance for the specified device. */
MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo);
/** Destructor. */
~MVKDescriptorPool() override;
protected:
@ -247,7 +246,3 @@ void mvkPopulateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& c
uint32_t descriptorSetIndex,
uint32_t bindingIndex,
MVKSampler* immutableSampler);

View File

@ -24,21 +24,31 @@ using namespace mvk;
#pragma mark -
#pragma mark MVKDescriptorSetLayout
// Look through the layout bindings looking for the binding number, accumulating the number
// of descriptors in each layout binding as we go, then add the element index.
uint32_t MVKDescriptorSetLayout::getDescriptorIndex(uint32_t binding, uint32_t elementIndex) {
uint32_t descIdx = 0;
for (auto& dslBind : _bindings) {
if (dslBind.getBinding() == binding) { break; }
descIdx += dslBind.getDescriptorCount();
}
return descIdx + elementIndex;
}
// A null cmdEncoder can be passed to perform a validation pass
void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
if (_isPushDescriptorLayout) return;
clearConfigurationResult();
uint32_t bindCnt = (uint32_t)_bindings.size();
for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
_bindings[bindIdx].bind(cmdEncoder, descSet->_bindings[bindIdx],
dslMTLRezIdxOffsets, dynamicOffsets,
pDynamicOffsetIndex);
for (uint32_t descIdx = 0, bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
descIdx += _bindings[bindIdx].bind(cmdEncoder, descSet, descIdx,
dslMTLRezIdxOffsets, dynamicOffsets,
pDynamicOffsetIndex);
}
}
@ -195,20 +205,13 @@ MVKDescriptorSetLayout::~MVKDescriptorSetLayout() {
template<typename DescriptorAction>
void MVKDescriptorSet::writeDescriptorSets(const DescriptorAction* pDescriptorAction,
size_t stride, const void* pData) {
uint32_t dstStartIdx = pDescriptorAction->dstArrayElement;
uint32_t binding = pDescriptorAction->dstBinding;
uint32_t origCnt = pDescriptorAction->descriptorCount;
uint32_t remainCnt = origCnt;
MVKDescriptorBinding* mvkDescBind = getBinding(binding);
while (mvkDescBind && remainCnt > 0) {
uint32_t srcStartIdx = origCnt - remainCnt;
remainCnt = mvkDescBind->writeBindings(srcStartIdx, dstStartIdx, remainCnt,
stride, pData);
binding++; // If not consumed, move to next consecutive binding point
mvkDescBind = getBinding(binding);
dstStartIdx = 0; // Subsequent bindings start reading at first element
}
uint32_t dstStartIdx = _pLayout->getDescriptorIndex(pDescriptorAction->dstBinding,
pDescriptorAction->dstArrayElement);
uint32_t descCnt = pDescriptorAction->descriptorCount;
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
_bindings[dstStartIdx + descIdx].writeBinding(descIdx, stride, pData);
}
}
// Create concrete implementations of the three variations of the writeDescriptorSets() function.
@ -226,39 +229,29 @@ void MVKDescriptorSet::readDescriptorSets(const VkCopyDescriptorSet* pDescriptor
VkDescriptorBufferInfo* pBufferInfo,
VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock) {
uint32_t srcStartIdx = pDescriptorCopy->srcArrayElement;
uint32_t binding = pDescriptorCopy->srcBinding;
uint32_t origCnt = pDescriptorCopy->descriptorCount;
uint32_t remainCnt = origCnt;
MVKDescriptorBinding* mvkDescBind = getBinding(binding);
while (mvkDescBind && remainCnt > 0) {
uint32_t dstStartIdx = origCnt - remainCnt;
remainCnt = mvkDescBind->readBindings(srcStartIdx, dstStartIdx, remainCnt, descType,
pImageInfo, pBufferInfo, pTexelBufferView, pInlineUniformBlock);
binding++; // If not consumed, move to next consecutive binding point
mvkDescBind = getBinding(binding);
srcStartIdx = 0; // Subsequent bindings start reading at first element
}
}
// Returns the binding instance that is assigned the specified
// binding number, or returns null if no such binding exists.
MVKDescriptorBinding* MVKDescriptorSet::getBinding(uint32_t binding) {
for (auto& mvkDB : _bindings) { if (mvkDB.hasBinding(binding)) { return &mvkDB; } }
return nullptr;
uint32_t srcStartIdx = _pLayout->getDescriptorIndex(pDescriptorCopy->srcBinding,
pDescriptorCopy->srcArrayElement);
uint32_t descCnt = pDescriptorCopy->descriptorCount;
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
_bindings[srcStartIdx + descIdx].readBinding(descIdx, descType, pImageInfo, pBufferInfo,
pTexelBufferView, pInlineUniformBlock);
}
}
// If the layout has changed, create the binding slots, each referencing a corresponding binding layout
void MVKDescriptorSet::setLayout(MVKDescriptorSetLayout* layout) {
if (layout != _pLayout) {
_pLayout = layout;
uint32_t bindCnt = (uint32_t)layout->_bindings.size();
if (layout == _pLayout) { return; }
_bindings.clear();
_bindings.reserve(bindCnt);
for (uint32_t i = 0; i < bindCnt; i++) {
_bindings.emplace_back(this, &layout->_bindings[i]);
_pLayout = layout;
_bindings.clear();
uint32_t bindCnt = (uint32_t)layout->_bindings.size();
for (uint32_t bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
MVKDescriptorSetLayoutBinding* dslBind = &layout->_bindings[bindIdx];
uint32_t descCnt = dslBind->getDescriptorCount();
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
_bindings.emplace_back(this, dslBind, descIdx);
}
}
}