From 8bca6709a18e457097174dd2ec63f4c88c628677 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 7 Jan 2020 22:25:49 -0500 Subject: [PATCH] Refactor descriptor binding files. Move MVKDescriptorBinding & MVKDescriptorSetLayoutBinding to new MVKDescriptorBinding.h/mm files. --- MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 12 + .../GPUObjects/MVKDescriptorBinding.h | 212 +++++ .../GPUObjects/MVKDescriptorBinding.mm | 849 ++++++++++++++++++ .../MoltenVK/GPUObjects/MVKDescriptorSet.h | 193 +--- .../MoltenVK/GPUObjects/MVKDescriptorSet.mm | 834 +---------------- 5 files changed, 1075 insertions(+), 1025 deletions(-) create mode 100644 MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.h create mode 100644 MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.mm diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 5cbd1272..fab66e18 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -157,6 +157,10 @@ A95B7D6A1D3EE486003183D3 /* MVKCommandEncoderState.h in Headers */ = {isa = PBXBuildFile; fileRef = A95B7D671D3EE486003183D3 /* MVKCommandEncoderState.h */; }; A95B7D6B1D3EE486003183D3 /* MVKCommandEncoderState.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */; }; A95B7D6C1D3EE486003183D3 /* MVKCommandEncoderState.mm in Sources */ = {isa = PBXBuildFile; fileRef = A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */; }; + A966A5DF23C535D000BBF9B4 /* MVKDescriptorBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = A966A5DC23C535D000BBF9B4 /* MVKDescriptorBinding.h */; }; + A966A5E023C535D000BBF9B4 /* MVKDescriptorBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = A966A5DC23C535D000BBF9B4 /* MVKDescriptorBinding.h */; }; + A966A5E123C535D000BBF9B4 /* MVKDescriptorBinding.mm in Sources */ = {isa = PBXBuildFile; fileRef = A966A5DE23C535D000BBF9B4 /* MVKDescriptorBinding.mm */; }; + A966A5E223C535D000BBF9B4 /* MVKDescriptorBinding.mm in Sources */ = {isa = PBXBuildFile; fileRef = A966A5DE23C535D000BBF9B4 /* MVKDescriptorBinding.mm */; }; A981494D1FB6A3F7005F00B4 /* MVKBaseObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */; }; A981494E1FB6A3F7005F00B4 /* MVKBaseObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */; }; A981494F1FB6A3F7005F00B4 /* MVKBaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */; }; @@ -373,6 +377,8 @@ A95870F71C90D29F009EB096 /* MVKCommandResourceFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCommandResourceFactory.mm; sourceTree = ""; }; A95B7D671D3EE486003183D3 /* MVKCommandEncoderState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommandEncoderState.h; sourceTree = ""; }; A95B7D681D3EE486003183D3 /* MVKCommandEncoderState.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCommandEncoderState.mm; sourceTree = ""; }; + A966A5DC23C535D000BBF9B4 /* MVKDescriptorBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKDescriptorBinding.h; sourceTree = ""; }; + A966A5DE23C535D000BBF9B4 /* MVKDescriptorBinding.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKDescriptorBinding.mm; sourceTree = ""; }; A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKBaseObject.mm; sourceTree = ""; }; A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKBaseObject.h; sourceTree = ""; }; A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKEnvironment.h; sourceTree = ""; }; @@ -483,6 +489,8 @@ children = ( A94FB77F1C7DFB4800632CA3 /* MVKBuffer.h */, A94FB7801C7DFB4800632CA3 /* MVKBuffer.mm */, + A966A5DC23C535D000BBF9B4 /* MVKDescriptorBinding.h */, + A966A5DE23C535D000BBF9B4 /* MVKDescriptorBinding.mm */, A94FB7811C7DFB4800632CA3 /* MVKDescriptorSet.h */, A94FB7821C7DFB4800632CA3 /* MVKDescriptorSet.mm */, A94FB7831C7DFB4800632CA3 /* MVKDevice.h */, @@ -695,6 +703,7 @@ A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */, 4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */, A94FB7B81C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */, + A966A5DF23C535D000BBF9B4 /* MVKDescriptorBinding.h in Headers */, A94FB7C81C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */, A94FB7D01C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */, A9E53DF32100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */, @@ -763,6 +772,7 @@ A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */, 4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */, A94FB7B91C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */, + A966A5E023C535D000BBF9B4 /* MVKDescriptorBinding.h in Headers */, A94FB7C91C7DFB4800632CA3 /* MVKCmdDraw.h in Headers */, A94FB7D11C7DFB4800632CA3 /* MVKCommandBuffer.h in Headers */, A9E53DF42100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */, @@ -1004,6 +1014,7 @@ A98149551FB6A3F7005F00B4 /* MVKFoundation.cpp in Sources */, A94FB7E61C7DFB4800632CA3 /* MVKDevice.mm in Sources */, A9E53DF52100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */, + A966A5E123C535D000BBF9B4 /* MVKDescriptorBinding.mm in Sources */, A94FB7FA1C7DFB4800632CA3 /* MVKPipeline.mm in Sources */, A94FB8021C7DFB4800632CA3 /* MVKQueue.mm in Sources */, A9E53DD72100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m in Sources */, @@ -1060,6 +1071,7 @@ A98149561FB6A3F7005F00B4 /* MVKFoundation.cpp in Sources */, A94FB7E71C7DFB4800632CA3 /* MVKDevice.mm in Sources */, A9E53DF62100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */, + A966A5E223C535D000BBF9B4 /* MVKDescriptorBinding.mm in Sources */, A94FB7FB1C7DFB4800632CA3 /* MVKPipeline.mm in Sources */, A94FB8031C7DFB4800632CA3 /* MVKQueue.mm in Sources */, A9E53DD82100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m in Sources */, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.h new file mode 100644 index 00000000..7db844b6 --- /dev/null +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.h @@ -0,0 +1,212 @@ +/* + * MVKDescriptorBinding.h + * + * Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "MVKImage.h" +#include "MVKVector.h" +#include + +class MVKDescriptorBinding; +class MVKDescriptorSet; +class MVKDescriptorSetLayout; +class MVKCommandEncoder; + + +#pragma mark MVKShaderStageResourceBinding + +/** Indicates the Metal resource indexes used by a single shader stage in a descriptor binding. */ +typedef struct MVKShaderStageResourceBinding { + uint32_t bufferIndex = 0; + uint32_t textureIndex = 0; + uint32_t samplerIndex = 0; + + MVKShaderStageResourceBinding operator+ (const MVKShaderStageResourceBinding& rhs); + MVKShaderStageResourceBinding& operator+= (const MVKShaderStageResourceBinding& rhs); + +} MVKShaderStageResourceBinding; + + +#pragma mark MVKShaderResourceBinding + +/** Indicates the Metal resource indexes used by each shader stage in a descriptor binding. */ +typedef struct MVKShaderResourceBinding { + MVKShaderStageResourceBinding stages[kMVKShaderStageMax]; + + uint32_t getMaxBufferIndex(); + uint32_t getMaxTextureIndex(); + uint32_t getMaxSamplerIndex(); + + MVKShaderResourceBinding operator+ (const MVKShaderResourceBinding& rhs); + MVKShaderResourceBinding& operator+= (const MVKShaderResourceBinding& rhs); + +} MVKShaderResourceBinding; + + +#pragma mark - +#pragma mark MVKDescriptorSetLayoutBinding + +/** Represents a Vulkan descriptor set layout binding. */ +class MVKDescriptorSetLayoutBinding : public MVKBaseDeviceObject { + +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& 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, + uint32_t& descriptorsPushed, + VkDescriptorType descriptorType, + size_t stride, + const void* pData, + MVKShaderResourceBinding& dslMTLRezIdxOffsets); + + /** Populates the specified shader converter context, at the specified descriptor set binding. */ + void populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context, + MVKShaderResourceBinding& dslMTLRezIdxOffsets, + uint32_t dslIndex); + + /** Constructs an instance. */ + MVKDescriptorSetLayoutBinding(MVKDevice* device, + MVKDescriptorSetLayout* layout, + const VkDescriptorSetLayoutBinding* pBinding); + + MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding); + + /** Destuctor. */ + ~MVKDescriptorSetLayoutBinding() override; + +protected: + friend class MVKDescriptorBinding; + + void initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes, + MVKShaderStageResourceBinding* pDescSetCounts, + const VkDescriptorSetLayoutBinding* pBinding); + bool validate(MVKSampler* mvkSampler); + + MVKDescriptorSetLayout* _layout; + VkDescriptorSetLayoutBinding _info; + std::vector _immutableSamplers; + MVKShaderResourceBinding _mtlResourceIndexOffsets; + bool _applyToStage[kMVKShaderStageMax]; +}; + + +#pragma mark - +#pragma mark MVKDescriptorBinding + +/** Represents a Vulkan descriptor binding. */ +class MVKDescriptorBinding : public MVKBaseObject { + +public: + + /** Returns the Vulkan API opaque object controlling this object. */ + 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. + */ + uint32_t writeBindings(uint32_t srcStartIndex, + uint32_t dstStartIndex, + uint32_t count, + size_t stride, + const void* pData); + + /** + * Updates the specified content arrays from the internal element bindings. + * + * Depending on the descriptor type of the descriptor set, the binding content is + * 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. + */ + uint32_t readBindings(uint32_t srcStartIndex, + uint32_t dstStartIndex, + uint32_t count, + 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); + + /** 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 _imageBindings; + std::vector _bufferBindings; + std::vector _inlineBindings; + std::vector _texelBufferBindings; + std::vector> _mtlBuffers; + std::vector _mtlBufferOffsets; + std::vector> _mtlTextures; + std::vector> _mtlSamplers; + bool _hasDynamicSamplers; +}; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.mm new file mode 100644 index 00000000..45db4402 --- /dev/null +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorBinding.mm @@ -0,0 +1,849 @@ +/* + * MVKDescriptorBinding.mm + * + * Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MVKDescriptorBinding.h" +#include "MVKDescriptorSet.h" +#include "MVKBuffer.h" + +using namespace std; +using namespace mvk; + + +#pragma mark MVKShaderStageResourceBinding + +MVKShaderStageResourceBinding MVKShaderStageResourceBinding::operator+ (const MVKShaderStageResourceBinding& rhs) { + MVKShaderStageResourceBinding rslt; + rslt.bufferIndex = this->bufferIndex + rhs.bufferIndex; + rslt.textureIndex = this->textureIndex + rhs.textureIndex; + rslt.samplerIndex = this->samplerIndex + rhs.samplerIndex; + return rslt; +} + +MVKShaderStageResourceBinding& MVKShaderStageResourceBinding::operator+= (const MVKShaderStageResourceBinding& rhs) { + this->bufferIndex += rhs.bufferIndex; + this->textureIndex += rhs.textureIndex; + this->samplerIndex += rhs.samplerIndex; + return *this; +} + + +#pragma mark MVKShaderResourceBinding + +uint32_t MVKShaderResourceBinding::getMaxBufferIndex() { + return max({stages[kMVKShaderStageVertex].bufferIndex, stages[kMVKShaderStageTessCtl].bufferIndex, stages[kMVKShaderStageTessEval].bufferIndex, stages[kMVKShaderStageFragment].bufferIndex, stages[kMVKShaderStageCompute].bufferIndex}); +} + +uint32_t MVKShaderResourceBinding::getMaxTextureIndex() { + return max({stages[kMVKShaderStageVertex].textureIndex, stages[kMVKShaderStageTessCtl].textureIndex, stages[kMVKShaderStageTessEval].textureIndex, stages[kMVKShaderStageFragment].textureIndex, stages[kMVKShaderStageCompute].textureIndex}); +} + +uint32_t MVKShaderResourceBinding::getMaxSamplerIndex() { + return max({stages[kMVKShaderStageVertex].samplerIndex, stages[kMVKShaderStageTessCtl].samplerIndex, stages[kMVKShaderStageTessEval].samplerIndex, stages[kMVKShaderStageFragment].samplerIndex, stages[kMVKShaderStageCompute].samplerIndex}); +} + +MVKShaderResourceBinding MVKShaderResourceBinding::operator+ (const MVKShaderResourceBinding& rhs) { + MVKShaderResourceBinding rslt; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + rslt.stages[i] = this->stages[i] + rhs.stages[i]; + } + return rslt; +} + +MVKShaderResourceBinding& MVKShaderResourceBinding::operator+= (const MVKShaderResourceBinding& rhs) { + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + this->stages[i] += rhs.stages[i]; + } + return *this; +} + + +#pragma mark - +#pragma mark MVKDescriptorSetLayoutBinding + +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& dynamicOffsets, + uint32_t* pDynamicOffsetIndex) { + MVKMTLBufferBinding bb; + MVKMTLTextureBinding tb; + MVKMTLSamplerStateBinding sb; + NSUInteger bufferDynamicOffset = 0; + + // 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) { + + // After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + bufferDynamicOffset = dynamicOffsets[*pDynamicOffsetIndex]; + (*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; + 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; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: { + bb.mtlBuffer = descBinding._mtlBuffers[rezIdx]; + bb.offset = descBinding._mtlBufferOffsets[rezIdx]; + bb.size = descBinding._inlineBindings[rezIdx].dataSize; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + 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]; + if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && tb.mtlTexture) { + tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle(); + } else { + tb.swizzle = 0; + } + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_SAMPLER: { + sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx]; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { + tb.mtlTexture = descBinding._mtlTextures[rezIdx]; + if (tb.mtlTexture) { + tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle(); + } else { + tb.swizzle = 0; + } + sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx]; + 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; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } + } + } + } + break; + } + + default: + break; + } + } +} + +template +static const T& get(const void* pData, size_t stride, uint32_t index) { + return *(T*)((const char*)pData + stride * index); +} + +// A null cmdEncoder can be passed to perform a validation pass +void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder, + uint32_t& dstArrayElement, + uint32_t& descriptorCount, + uint32_t& descriptorsPushed, + VkDescriptorType descriptorType, + size_t stride, + const void* pData, + 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; + descriptorsPushed = _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 auto& bufferInfo = get(pData, stride, rezIdx - dstArrayElement); + MVKBuffer* buffer = (MVKBuffer*)bufferInfo.buffer; + bb.mtlBuffer = buffer->getMTLBuffer(); + bb.offset = buffer->getMTLBufferOffset() + bufferInfo.offset; + bb.size = (uint32_t)buffer->getByteCount(); + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: { + const auto& inlineUniformBlock = get(pData, stride, rezIdx - dstArrayElement); + bb.mtlBytes = inlineUniformBlock.pData; + bb.size = inlineUniformBlock.dataSize; + bb.isInline = true; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + const auto& imageInfo = get(pData, stride, rezIdx - dstArrayElement); + MVKImageView* imageView = (MVKImageView*)imageInfo.imageView; + tb.mtlTexture = imageView->getMTLTexture(); + if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && imageView) { + tb.swizzle = imageView->getPackedSwizzle(); + } else { + tb.swizzle = 0; + } + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { + auto* bufferView = get(pData, stride, rezIdx - dstArrayElement); + tb.mtlTexture = bufferView->getMTLTexture(); + tb.swizzle = 0; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_SAMPLER: { + MVKSampler* sampler; + if (_immutableSamplers.empty()) { + sampler = (MVKSampler*)get(pData, stride, rezIdx - dstArrayElement).sampler; + validate(sampler); + } else { + sampler = _immutableSamplers[rezIdx]; + } + sb.mtlSamplerState = sampler->getMTLSamplerState(); + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } + } + } + } + break; + } + + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { + const auto& imageInfo = get(pData, stride, rezIdx - dstArrayElement); + MVKImageView* imageView = (MVKImageView*)imageInfo.imageView; + tb.mtlTexture = imageView->getMTLTexture(); + if (imageView) { + tb.swizzle = imageView->getPackedSwizzle(); + } else { + tb.swizzle = 0; + } + MVKSampler* sampler; + if (_immutableSamplers.empty()) { + sampler = (MVKSampler*)imageInfo.sampler; + validate(sampler); + } else { + sampler = _immutableSamplers[rezIdx]; + } + sb.mtlSamplerState = sampler->getMTLSamplerState(); + 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; + if (i == kMVKShaderStageCompute) { + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } + if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } + } else { + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } + if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } + } + } + } + break; + } + + default: + break; + } + } + + dstArrayElement = 0; + if (_info.descriptorCount > descriptorCount) + descriptorCount = 0; + else { + descriptorCount -= _info.descriptorCount; + descriptorsPushed = _info.descriptorCount; + } +} + +// If depth compare is required, but unavailable on the device, the sampler can only be used as an immutable sampler +bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) { + if (mvkSampler->getRequiresConstExprSampler()) { + _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkUpdateDescriptorSets(): Depth texture samplers using a compare operation can only be used as immutable samplers on this device.")); + return false; + } + return true; +} + +void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(SPIRVToMSLConversionConfiguration& context, + MVKShaderResourceBinding& dslMTLRezIdxOffsets, + uint32_t dslIndex) { + + MVKSampler* mvkSamp = !_immutableSamplers.empty() ? _immutableSamplers.front() : nullptr; + + // Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding. + MVKShaderResourceBinding mtlIdxs = _mtlResourceIndexOffsets + dslMTLRezIdxOffsets; + + static const spv::ExecutionModel models[] = { + spv::ExecutionModelVertex, + spv::ExecutionModelTessellationControl, + spv::ExecutionModelTessellationEvaluation, + spv::ExecutionModelFragment, + spv::ExecutionModelGLCompute + }; + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + if (_applyToStage[i]) { + mvkPopulateShaderConverterContext(context, + mtlIdxs.stages[i], + models[i], + dslIndex, + _info.binding, + mvkSamp); + } + } +} + +MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device, + MVKDescriptorSetLayout* layout, + const VkDescriptorSetLayoutBinding* pBinding) : MVKBaseDeviceObject(device), _layout(layout) { + + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + // Determine if this binding is used by this shader stage + _applyToStage[i] = mvkAreAllFlagsEnabled(pBinding->stageFlags, mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage(i))); + // If this binding is used by the shader, set the Metal resource index + if (_applyToStage[i]) { + initMetalResourceIndexOffsets(&_mtlResourceIndexOffsets.stages[i], + &layout->_mtlResourceCounts.stages[i], pBinding); + } + } + + // If immutable samplers are defined, copy them in + if ( pBinding->pImmutableSamplers && + (pBinding->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + pBinding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ) { + _immutableSamplers.reserve(pBinding->descriptorCount); + for (uint32_t i = 0; i < pBinding->descriptorCount; i++) { + _immutableSamplers.push_back((MVKSampler*)pBinding->pImmutableSamplers[i]); + _immutableSamplers.back()->retain(); + } + } + + _info = *pBinding; + _info.pImmutableSamplers = nullptr; // Remove dangling pointer +} + +MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding) : + MVKBaseDeviceObject(binding._device), _layout(binding._layout), + _info(binding._info), _immutableSamplers(binding._immutableSamplers), + _mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets) { + + for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { + _applyToStage[i] = binding._applyToStage[i]; + } + for (MVKSampler* sampler : _immutableSamplers) { + sampler->retain(); + } +} + +MVKDescriptorSetLayoutBinding::~MVKDescriptorSetLayoutBinding() { + for (MVKSampler* sampler : _immutableSamplers) { + sampler->release(); + } +} + +// Sets the appropriate Metal resource indexes within this binding from the +// specified descriptor set binding counts, and updates those counts accordingly. +void MVKDescriptorSetLayoutBinding::initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes, + MVKShaderStageResourceBinding* pDescSetCounts, + const VkDescriptorSetLayoutBinding* pBinding) { + switch (pBinding->descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + pBindingIndexes->samplerIndex = pDescSetCounts->samplerIndex; + pDescSetCounts->samplerIndex += pBinding->descriptorCount; + + if (pBinding->descriptorCount > 1 && !_device->_pMetalFeatures->arrayOfSamplers) { + _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of samplers.", _device->getName())); + } + break; + + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + pBindingIndexes->textureIndex = pDescSetCounts->textureIndex; + pDescSetCounts->textureIndex += pBinding->descriptorCount; + pBindingIndexes->samplerIndex = pDescSetCounts->samplerIndex; + pDescSetCounts->samplerIndex += pBinding->descriptorCount; + + if (pBinding->descriptorCount > 1) { + if ( !_device->_pMetalFeatures->arrayOfTextures ) { + _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of textures.", _device->getName())); + } + if ( !_device->_pMetalFeatures->arrayOfSamplers ) { + _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of samplers.", _device->getName())); + } + } + break; + + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + pBindingIndexes->textureIndex = pDescSetCounts->textureIndex; + pDescSetCounts->textureIndex += pBinding->descriptorCount; + + if (pBinding->descriptorCount > 1 && !_device->_pMetalFeatures->arrayOfTextures) { + _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of textures.", _device->getName())); + } + 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: + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: + pBindingIndexes->bufferIndex = pDescSetCounts->bufferIndex; + pDescSetCounts->bufferIndex += pBinding->descriptorCount; + break; + + default: + break; + } +} + + +#pragma mark - +#pragma mark MVKDescriptorBinding + +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); + + 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(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(); + } + } + 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(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(); + } + } + 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(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(); + } + } + 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(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(); + } + } + 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(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(); + } + } + 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(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; + + 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); + + descType = _pBindingLayout->_info.descriptorType; + switch (_pBindingLayout->_info.descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + 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]; + } + 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]; + } + 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]; + } + 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(dstInlineUniformBlock.pData); + if (srcInlineUniformBlock.dataSize != 0) { + dstInlineUniformBlock.pData = reinterpret_cast(new uint8_t*[srcInlineUniformBlock.dataSize]); + if (srcInlineUniformBlock.pData) { + memcpy(const_cast(dstInlineUniformBlock.pData), srcInlineUniformBlock.pData, 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 + 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); + 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; + } + + // Okay to hold layout as a pointer. From the Vulkan spec... + // "VkDescriptorSetLayout objects may be accessed by commands that operate on descriptor + // sets allocated using that layout, and those descriptor sets must not be updated with + // vkUpdateDescriptorSets after the descriptor set layout has been destroyed. + _pBindingLayout = pBindingLayout; +} + +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()); + } +} diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h index 46a5e2fa..8c58e87a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h @@ -18,112 +18,16 @@ #pragma once -#include "MVKDevice.h" -#include "MVKImage.h" +#include "MVKDescriptorBinding.h" #include "MVKVector.h" -#include #include #include -#include class MVKDescriptorPool; -class MVKDescriptorBinding; -class MVKDescriptorSet; -class MVKDescriptorSetLayout; class MVKPipelineLayout; class MVKCommandEncoder; -#pragma mark MVKShaderStageResourceBinding - -/** Indicates the Metal resource indexes used by a single shader stage in a descriptor binding. */ -typedef struct MVKShaderStageResourceBinding { - uint32_t bufferIndex = 0; - uint32_t textureIndex = 0; - uint32_t samplerIndex = 0; - - MVKShaderStageResourceBinding operator+ (const MVKShaderStageResourceBinding& rhs); - MVKShaderStageResourceBinding& operator+= (const MVKShaderStageResourceBinding& rhs); - -} MVKShaderStageResourceBinding; - - -#pragma mark MVKShaderResourceBinding - -/** Indicates the Metal resource indexes used by each shader stage in a descriptor binding. */ -typedef struct MVKShaderResourceBinding { - MVKShaderStageResourceBinding stages[kMVKShaderStageMax]; - - uint32_t getMaxBufferIndex(); - uint32_t getMaxTextureIndex(); - uint32_t getMaxSamplerIndex(); - - MVKShaderResourceBinding operator+ (const MVKShaderResourceBinding& rhs); - MVKShaderResourceBinding& operator+= (const MVKShaderResourceBinding& rhs); - -} MVKShaderResourceBinding; - - -#pragma mark - -#pragma mark MVKDescriptorSetLayoutBinding - -/** Represents a Vulkan descriptor set layout binding. */ -class MVKDescriptorSetLayoutBinding : public MVKBaseDeviceObject { - -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& 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, - uint32_t& descriptorsPushed, - VkDescriptorType descriptorType, - size_t stride, - const void* pData, - MVKShaderResourceBinding& dslMTLRezIdxOffsets); - - /** Populates the specified shader converter context, at the specified descriptor set binding. */ - void populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context, - MVKShaderResourceBinding& dslMTLRezIdxOffsets, - uint32_t dslIndex); - - /** Constructs an instance. */ - MVKDescriptorSetLayoutBinding(MVKDevice* device, - MVKDescriptorSetLayout* layout, - const VkDescriptorSetLayoutBinding* pBinding); - - MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding); - - /** Destuctor. */ - ~MVKDescriptorSetLayoutBinding() override; - -protected: - friend class MVKDescriptorBinding; - friend class MVKPipelineLayout; - - void initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes, - MVKShaderStageResourceBinding* pDescSetCounts, - const VkDescriptorSetLayoutBinding* pBinding); - bool validate(MVKSampler* mvkSampler); - - MVKDescriptorSetLayout* _layout; - VkDescriptorSetLayoutBinding _info; - std::vector _immutableSamplers; - MVKShaderResourceBinding _mtlResourceIndexOffsets; - bool _applyToStage[kMVKShaderStageMax]; -}; - - #pragma mark - #pragma mark MVKDescriptorSetLayout @@ -190,101 +94,6 @@ protected: }; -#pragma mark - -#pragma mark MVKDescriptorBinding - -/** Represents a Vulkan descriptor binding. */ -class MVKDescriptorBinding : public MVKBaseObject { - -public: - - /** Returns the Vulkan API opaque object controlling this object. */ - 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. - */ - uint32_t writeBindings(uint32_t srcStartIndex, - uint32_t dstStartIndex, - uint32_t count, - size_t stride, - const void* pData); - - /** - * Updates the specified content arrays from the internal element bindings. - * - * Depending on the descriptor type of the descriptor set, the binding content is - * 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. - */ - uint32_t readBindings(uint32_t srcStartIndex, - uint32_t dstStartIndex, - uint32_t count, - 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); - - /** 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 _imageBindings; - std::vector _bufferBindings; - std::vector _inlineBindings; - std::vector _texelBufferBindings; - std::vector> _mtlBuffers; - std::vector _mtlBufferOffsets; - std::vector> _mtlTextures; - std::vector> _mtlSamplers; - bool _hasDynamicSamplers; -}; - - #pragma mark - #pragma mark MVKDescriptorSet diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index f2a1b50f..c85c74ec 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -1,5 +1,5 @@ /* - * MVKDescriptorSetLayout.mm + * MVKDescriptorSet.mm * * Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com) * @@ -17,534 +17,10 @@ */ #include "MVKDescriptorSet.h" -#include "MVKCommandBuffer.h" -#include "MVKBuffer.h" -#include "MVKFoundation.h" -#include "MVKLogging.h" -#include "mvk_datatypes.hpp" -#include -using namespace std; using namespace mvk; -#pragma mark MVKShaderStageResourceBinding - -MVKShaderStageResourceBinding MVKShaderStageResourceBinding::operator+ (const MVKShaderStageResourceBinding& rhs) { - MVKShaderStageResourceBinding rslt; - rslt.bufferIndex = this->bufferIndex + rhs.bufferIndex; - rslt.textureIndex = this->textureIndex + rhs.textureIndex; - rslt.samplerIndex = this->samplerIndex + rhs.samplerIndex; - return rslt; -} - -MVKShaderStageResourceBinding& MVKShaderStageResourceBinding::operator+= (const MVKShaderStageResourceBinding& rhs) { - this->bufferIndex += rhs.bufferIndex; - this->textureIndex += rhs.textureIndex; - this->samplerIndex += rhs.samplerIndex; - return *this; -} - - -#pragma mark MVKShaderResourceBinding - -uint32_t MVKShaderResourceBinding::getMaxBufferIndex() { - return max({stages[kMVKShaderStageVertex].bufferIndex, stages[kMVKShaderStageTessCtl].bufferIndex, stages[kMVKShaderStageTessEval].bufferIndex, stages[kMVKShaderStageFragment].bufferIndex, stages[kMVKShaderStageCompute].bufferIndex}); -} - -uint32_t MVKShaderResourceBinding::getMaxTextureIndex() { - return max({stages[kMVKShaderStageVertex].textureIndex, stages[kMVKShaderStageTessCtl].textureIndex, stages[kMVKShaderStageTessEval].textureIndex, stages[kMVKShaderStageFragment].textureIndex, stages[kMVKShaderStageCompute].textureIndex}); -} - -uint32_t MVKShaderResourceBinding::getMaxSamplerIndex() { - return max({stages[kMVKShaderStageVertex].samplerIndex, stages[kMVKShaderStageTessCtl].samplerIndex, stages[kMVKShaderStageTessEval].samplerIndex, stages[kMVKShaderStageFragment].samplerIndex, stages[kMVKShaderStageCompute].samplerIndex}); -} - -MVKShaderResourceBinding MVKShaderResourceBinding::operator+ (const MVKShaderResourceBinding& rhs) { - MVKShaderResourceBinding rslt; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - rslt.stages[i] = this->stages[i] + rhs.stages[i]; - } - return rslt; -} - -MVKShaderResourceBinding& MVKShaderResourceBinding::operator+= (const MVKShaderResourceBinding& rhs) { - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - this->stages[i] += rhs.stages[i]; - } - return *this; -} - - -#pragma mark - -#pragma mark MVKDescriptorSetLayoutBinding - -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& dynamicOffsets, - uint32_t* pDynamicOffsetIndex) { - MVKMTLBufferBinding bb; - MVKMTLTextureBinding tb; - MVKMTLSamplerStateBinding sb; - NSUInteger bufferDynamicOffset = 0; - - // 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) { - - // After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - bufferDynamicOffset = dynamicOffsets[*pDynamicOffsetIndex]; - (*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; - 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; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: { - bb.mtlBuffer = descBinding._mtlBuffers[rezIdx]; - bb.offset = descBinding._mtlBufferOffsets[rezIdx]; - bb.size = descBinding._inlineBindings[rezIdx].dataSize; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - 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]; - if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && tb.mtlTexture) { - tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle(); - } else { - tb.swizzle = 0; - } - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_SAMPLER: { - sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx]; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { - tb.mtlTexture = descBinding._mtlTextures[rezIdx]; - if (tb.mtlTexture) { - tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle(); - } else { - tb.swizzle = 0; - } - sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx]; - 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; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } - } - } - break; - } - - default: - break; - } - } -} - -template -static const T& get(const void* pData, size_t stride, uint32_t index) { - return *(T*)((const char*)pData + stride * index); -} - -// A null cmdEncoder can be passed to perform a validation pass -void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder, - uint32_t& dstArrayElement, - uint32_t& descriptorCount, - uint32_t& descriptorsPushed, - VkDescriptorType descriptorType, - size_t stride, - const void* pData, - 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; - descriptorsPushed = _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 auto& bufferInfo = get(pData, stride, rezIdx - dstArrayElement); - MVKBuffer* buffer = (MVKBuffer*)bufferInfo.buffer; - bb.mtlBuffer = buffer->getMTLBuffer(); - bb.offset = buffer->getMTLBufferOffset() + bufferInfo.offset; - bb.size = (uint32_t)buffer->getByteCount(); - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: { - const auto& inlineUniformBlock = get(pData, stride, rezIdx - dstArrayElement); - bb.mtlBytes = inlineUniformBlock.pData; - bb.size = inlineUniformBlock.dataSize; - bb.isInline = true; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { - const auto& imageInfo = get(pData, stride, rezIdx - dstArrayElement); - MVKImageView* imageView = (MVKImageView*)imageInfo.imageView; - tb.mtlTexture = imageView->getMTLTexture(); - if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && imageView) { - tb.swizzle = imageView->getPackedSwizzle(); - } else { - tb.swizzle = 0; - } - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { - auto* bufferView = get(pData, stride, rezIdx - dstArrayElement); - tb.mtlTexture = bufferView->getMTLTexture(); - tb.swizzle = 0; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - tb.index = mtlIdxs.stages[i].textureIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_SAMPLER: { - MVKSampler* sampler; - if (_immutableSamplers.empty()) { - sampler = (MVKSampler*)get(pData, stride, rezIdx - dstArrayElement).sampler; - validate(sampler); - } else { - sampler = _immutableSamplers[rezIdx]; - } - sb.mtlSamplerState = sampler->getMTLSamplerState(); - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } - } - } - break; - } - - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { - const auto& imageInfo = get(pData, stride, rezIdx - dstArrayElement); - MVKImageView* imageView = (MVKImageView*)imageInfo.imageView; - tb.mtlTexture = imageView->getMTLTexture(); - if (imageView) { - tb.swizzle = imageView->getPackedSwizzle(); - } else { - tb.swizzle = 0; - } - MVKSampler* sampler; - if (_immutableSamplers.empty()) { - sampler = (MVKSampler*)imageInfo.sampler; - validate(sampler); - } else { - sampler = _immutableSamplers[rezIdx]; - } - sb.mtlSamplerState = sampler->getMTLSamplerState(); - 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; - if (i == kMVKShaderStageCompute) { - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); } - if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); } - } else { - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); } - if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); } - } - } - } - break; - } - - default: - break; - } - } - - dstArrayElement = 0; - if (_info.descriptorCount > descriptorCount) - descriptorCount = 0; - else { - descriptorCount -= _info.descriptorCount; - descriptorsPushed = _info.descriptorCount; - } -} - -// If depth compare is required, but unavailable on the device, the sampler can only be used as an immutable sampler -bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) { - if (mvkSampler->getRequiresConstExprSampler()) { - _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkUpdateDescriptorSets(): Depth texture samplers using a compare operation can only be used as immutable samplers on this device.")); - return false; - } - return true; -} - -void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(SPIRVToMSLConversionConfiguration& context, - MVKShaderResourceBinding& dslMTLRezIdxOffsets, - uint32_t dslIndex) { - - MVKSampler* mvkSamp = !_immutableSamplers.empty() ? _immutableSamplers.front() : nullptr; - - // Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding. - MVKShaderResourceBinding mtlIdxs = _mtlResourceIndexOffsets + dslMTLRezIdxOffsets; - - static const spv::ExecutionModel models[] = { - spv::ExecutionModelVertex, - spv::ExecutionModelTessellationControl, - spv::ExecutionModelTessellationEvaluation, - spv::ExecutionModelFragment, - spv::ExecutionModelGLCompute - }; - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - if (_applyToStage[i]) { - mvkPopulateShaderConverterContext(context, - mtlIdxs.stages[i], - models[i], - dslIndex, - _info.binding, - mvkSamp); - } - } -} - -MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(MVKDevice* device, - MVKDescriptorSetLayout* layout, - const VkDescriptorSetLayoutBinding* pBinding) : MVKBaseDeviceObject(device), _layout(layout) { - - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - // Determine if this binding is used by this shader stage - _applyToStage[i] = mvkAreAllFlagsEnabled(pBinding->stageFlags, mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage(i))); - // If this binding is used by the shader, set the Metal resource index - if (_applyToStage[i]) { - initMetalResourceIndexOffsets(&_mtlResourceIndexOffsets.stages[i], - &layout->_mtlResourceCounts.stages[i], pBinding); - } - } - - // If immutable samplers are defined, copy them in - if ( pBinding->pImmutableSamplers && - (pBinding->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || - pBinding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ) { - _immutableSamplers.reserve(pBinding->descriptorCount); - for (uint32_t i = 0; i < pBinding->descriptorCount; i++) { - _immutableSamplers.push_back((MVKSampler*)pBinding->pImmutableSamplers[i]); - _immutableSamplers.back()->retain(); - } - } - - _info = *pBinding; - _info.pImmutableSamplers = nullptr; // Remove dangling pointer -} - -MVKDescriptorSetLayoutBinding::MVKDescriptorSetLayoutBinding(const MVKDescriptorSetLayoutBinding& binding) : - MVKBaseDeviceObject(binding._device), _layout(binding._layout), - _info(binding._info), _immutableSamplers(binding._immutableSamplers), - _mtlResourceIndexOffsets(binding._mtlResourceIndexOffsets) { - - for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) { - _applyToStage[i] = binding._applyToStage[i]; - } - for (MVKSampler* sampler : _immutableSamplers) { - sampler->retain(); - } -} - -MVKDescriptorSetLayoutBinding::~MVKDescriptorSetLayoutBinding() { - for (MVKSampler* sampler : _immutableSamplers) { - sampler->release(); - } -} - -// Sets the appropriate Metal resource indexes within this binding from the -// specified descriptor set binding counts, and updates those counts accordingly. -void MVKDescriptorSetLayoutBinding::initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes, - MVKShaderStageResourceBinding* pDescSetCounts, - const VkDescriptorSetLayoutBinding* pBinding) { - switch (pBinding->descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - pBindingIndexes->samplerIndex = pDescSetCounts->samplerIndex; - pDescSetCounts->samplerIndex += pBinding->descriptorCount; - - if (pBinding->descriptorCount > 1 && !_device->_pMetalFeatures->arrayOfSamplers) { - _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of samplers.", _device->getName())); - } - break; - - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - pBindingIndexes->textureIndex = pDescSetCounts->textureIndex; - pDescSetCounts->textureIndex += pBinding->descriptorCount; - pBindingIndexes->samplerIndex = pDescSetCounts->samplerIndex; - pDescSetCounts->samplerIndex += pBinding->descriptorCount; - - if (pBinding->descriptorCount > 1) { - if ( !_device->_pMetalFeatures->arrayOfTextures ) { - _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of textures.", _device->getName())); - } - if ( !_device->_pMetalFeatures->arrayOfSamplers ) { - _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of samplers.", _device->getName())); - } - } - break; - - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - pBindingIndexes->textureIndex = pDescSetCounts->textureIndex; - pDescSetCounts->textureIndex += pBinding->descriptorCount; - - if (pBinding->descriptorCount > 1 && !_device->_pMetalFeatures->arrayOfTextures) { - _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of textures.", _device->getName())); - } - 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: - case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: - pBindingIndexes->bufferIndex = pDescSetCounts->bufferIndex; - pDescSetCounts->bufferIndex += pBinding->descriptorCount; - break; - - default: - break; - } -} - - #pragma mark - #pragma mark MVKDescriptorSetLayout @@ -713,314 +189,6 @@ MVKDescriptorSetLayout::~MVKDescriptorSetLayout() { } -#pragma mark - -#pragma mark MVKDescriptorBinding - -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); - - 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(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(); - } - } - 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(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(); - } - } - 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(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(); - } - } - 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(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(); - } - } - 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(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(); - } - } - 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(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; - - 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); - - descType = _pBindingLayout->_info.descriptorType; - switch (_pBindingLayout->_info.descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - 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]; - } - 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]; - } - 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]; - } - 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(dstInlineUniformBlock.pData); - if (srcInlineUniformBlock.dataSize != 0) { - dstInlineUniformBlock.pData = reinterpret_cast(new uint8_t*[srcInlineUniformBlock.dataSize]); - if (srcInlineUniformBlock.pData) { - memcpy(const_cast(dstInlineUniformBlock.pData), srcInlineUniformBlock.pData, 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 - 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); - 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; - } - - // Okay to hold layout as a pointer. From the Vulkan spec... - // "VkDescriptorSetLayout objects may be accessed by commands that operate on descriptor - // sets allocated using that layout, and those descriptor sets must not be updated with - // vkUpdateDescriptorSets after the descriptor set layout has been destroyed. - _pBindingLayout = pBindingLayout; -} - -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()); - } -} - - #pragma mark - #pragma mark MVKDescriptorSet