From 164680b68642068b9174c2bc1d1f7875a275e78b Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 18 Apr 2018 20:48:34 -0400 Subject: [PATCH 1/2] Support depth clip mode only from MTLFeatureSet_iOS_GPUFamily2_v4 onwards. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 6dd5139d..8bee051a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -330,8 +330,10 @@ void MVKPhysicalDevice::initMetalFeatures() { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v4] ) { _metalFeatures.mslVersion = SPIRVToMSLConverterOptions::makeMSLVersion(2); _metalFeatures.ioSurfaces = true; - _metalFeatures.depthClipMode = true; } + if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily2_v4] ) { + _metalFeatures.depthClipMode = true; + } #endif #if MVK_MACOS From a80a85f82f76c12d22fdfcd85482bd478308d7e3 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Thu, 19 Apr 2018 18:36:00 -0400 Subject: [PATCH 2/2] MVKCmdClearAttachments & MVKCmdClearImage support multisampled attachments and images. --- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 13 ++-- .../Commands/MVKCommandEncoderState.mm | 2 - .../Commands/MVKCommandResourceFactory.h | 66 +++++++++---------- .../Commands/MVKCommandResourceFactory.mm | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h | 6 ++ MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm | 17 +++++ .../MoltenVK/GPUObjects/MVKShaderModule.h | 4 +- .../MoltenVK/GPUObjects/MVKShaderModule.mm | 4 +- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 2 +- 12 files changed, 71 insertions(+), 50 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index e64b7529..2e84f061 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -708,7 +708,7 @@ void MVKCmdClearAttachments::setContent(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { - _rpsKey.reset(); + _rpsKey = kMVKRPSKeyClearAttDefault; _mtlStencilValue = 0; _isClearingDepth = false; _isClearingStencil = false; @@ -814,11 +814,11 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D(); populateVertices(fbExtent.width, fbExtent.height); uint32_t vtxCnt = (uint32_t)_vertices.size(); - uint32_t vtxBuffIdx = getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex); - // Populate the render pipeline state attachment key with - // the format of each color attachment used by the subpass + // Populate the render pipeline state attachment key with attachment info from the subpass. + _rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount()); + uint32_t caCnt = subpass->getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { VkFormat vkAttFmt = subpass->getColorAttachmentFormat(caIdx); @@ -868,9 +868,10 @@ void MVKCmdClearImage::setContent(VkImage image, _image = (MVKImage*)image; _imgLayout = imageLayout; _isDepthStencilClear = isDepthStencilClear; + _mtlStencilValue = 0; - _rpsKey.reset(); - _mtlStencilValue = 0; + _rpsKey = kMVKRPSKeyClearAttDefault; + _rpsKey.mtlSampleCount = _image->getSampleCount(); if (_isDepthStencilClear) { _rpsKey.enable(kMVKAttachmentFormatDepthStencilIndex); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index c28dd911..551ff11f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -167,8 +167,6 @@ void MVKDepthStencilCommandEncoderState:: setDepthStencilState(VkPipelineDepthSt setStencilState(_depthStencilData.frontFaceStencilData, vkDepthStencilInfo.front, vkDepthStencilInfo.stencilTestEnable); setStencilState(_depthStencilData.backFaceStencilData, vkDepthStencilInfo.back, vkDepthStencilInfo.stencilTestEnable); - _depthStencilData.clearHash(); // Hash will change - markDirty(); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index 5086bfd5..66163b95 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -20,6 +20,7 @@ #include "MVKDevice.h" #include "MVKFoundation.h" +#include "mvk_datatypes.h" #include #import @@ -33,13 +34,16 @@ /** * Key to use for looking up cached MTLRenderPipelineState instances. - * Holds the formats for each color attachment plus one depth/stencil attachment. + * Indicates which attachments are used, and holds the Metal pixel formats for each + * color attachment plus one depth/stencil attachment. Also holds the Metal sample count. * * This structure can be used as a key in a std::map and std::unordered_map. */ typedef struct MVKRPSKeyClearAtt_t { uint16_t attachmentMTLPixelFormats[kMVKAttachmentFormatCount]; + uint16_t mtlSampleCount; uint32_t enabledFlags; + const static uint32_t bitFlag = 1; void enable(uint32_t attIdx) { mvkEnableFlag(enabledFlags, bitFlag << attIdx); } @@ -55,14 +59,26 @@ typedef struct MVKRPSKeyClearAtt_t { bool operator==(const MVKRPSKeyClearAtt_t& rhs) const { return ((enabledFlags == rhs.enabledFlags) && + (mtlSampleCount == rhs.mtlSampleCount) && (memcmp(attachmentMTLPixelFormats, rhs.attachmentMTLPixelFormats, sizeof(attachmentMTLPixelFormats)) == 0)); } - void reset() { memset(this, 0, sizeof(*this)); } + std::size_t hash() const { + std::size_t hash = mvkHash(&enabledFlags); + hash = mvkHash(&mtlSampleCount, 1, hash); + return mvkHash(attachmentMTLPixelFormats, kMVKAttachmentFormatCount, hash); + } + + MVKRPSKeyClearAtt_t() { + memset(this, 0, sizeof(*this)); + mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(VK_SAMPLE_COUNT_1_BIT); + } - MVKRPSKeyClearAtt_t() { reset(); } } MVKRPSKeyClearAtt; +/** An instance populated with default values, for use in resetting other instances to default state. */ +const MVKRPSKeyClearAtt kMVKRPSKeyClearAttDefault; + /** * Hash structure implementation for MVKRPSKeyClearAtt in std namespace, * so MVKRPSKeyClearAtt can be used as a key in a std::map and std::unordered_map. @@ -70,10 +86,7 @@ typedef struct MVKRPSKeyClearAtt_t { namespace std { template <> struct hash { - std::size_t operator()(const MVKRPSKeyClearAtt& k) const { - std::size_t hash = mvkHash(&k.enabledFlags, 1); - return mvkHash(k.attachmentMTLPixelFormats, kMVKAttachmentFormatCount, hash); - } + std::size_t operator()(const MVKRPSKeyClearAtt& k) const { return k.hash(); } }; } @@ -126,29 +139,18 @@ const MVKMTLStencilDescriptorData kMVKMTLStencilDescriptorDataDefault; * change as early as possible. */ typedef struct MVKMTLDepthStencilDescriptorData_t { - std::size_t _hash; uint8_t depthCompareFunction; /**< The depth compare function (interpreted as MTLCompareFunction). */ bool depthWriteEnabled; /**< Indicates whether depth writing is enabled. */ MVKMTLStencilDescriptorData frontFaceStencilData; MVKMTLStencilDescriptorData backFaceStencilData; - std::size_t hash() { - if ( !_hash ) { _hash = mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); } - return _hash; - } - void clearHash() { _hash = 0; } + bool operator==(const MVKMTLDepthStencilDescriptorData_t& rhs) const { + return (memcmp(this, &rhs, sizeof(*this)) == 0); + } - bool operator==(const MVKMTLDepthStencilDescriptorData_t& rhs) const { - MVKMTLDepthStencilDescriptorData_t* pLHS = (MVKMTLDepthStencilDescriptorData_t*)this; - MVKMTLDepthStencilDescriptorData_t* pRHS = (MVKMTLDepthStencilDescriptorData_t*)&rhs; - - if (pLHS == pRHS) { return true; } - if (!pLHS) { return false; } - if (!pRHS) { return false; } - if (pLHS->hash() != pRHS->hash()) { return false; } - - return (memcmp(pLHS, pRHS, sizeof(*this)) == 0); - } + std::size_t hash() const { + return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); + } MVKMTLDepthStencilDescriptorData_t() { @@ -156,7 +158,6 @@ typedef struct MVKMTLDepthStencilDescriptorData_t { // even if the structure contains alignment gaps. memset(this, 0, sizeof(*this)); - _hash = 0; depthCompareFunction = MTLCompareFunctionAlways; depthWriteEnabled = false; @@ -171,11 +172,8 @@ const MVKMTLDepthStencilDescriptorData kMVKMTLDepthStencilDescriptorDataDefault; namespace std { template <> - struct hash { - std::size_t operator()(const MVKMTLDepthStencilDescriptorData_t& k) const { - MVKMTLDepthStencilDescriptorData_t* pK = (MVKMTLDepthStencilDescriptorData_t*)&k; - return pK->hash(); - } + struct hash { + std::size_t operator()(const MVKMTLDepthStencilDescriptorData& k) const { return k.hash(); } }; } @@ -202,6 +200,10 @@ typedef struct MVKImageDescriptorData_t { return (memcmp(this, &rhs, sizeof(*this)) == 0); } + std::size_t hash() const { + return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); + } + MVKImageDescriptorData_t() { memset(this, 0, sizeof(*this)); } } __attribute__((aligned(sizeof(uint64_t)))) MVKImageDescriptorData; @@ -213,9 +215,7 @@ typedef struct MVKImageDescriptorData_t { namespace std { template <> struct hash { - std::size_t operator()(const MVKImageDescriptorData& k) const { - return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t)); - } + std::size_t operator()(const MVKImageDescriptorData& k) const { return k.hash(); } }; } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index e2e85571..a09a6ab7 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -97,6 +97,7 @@ id MVKCommandResourceFactory::newCmdClearMTLRenderPipeli plDesc.label = [NSString stringWithFormat: @"CmdClearAttachments%s", fragFuncSfx.data()]; plDesc.vertexFunction = getFunctionNamed("vtxCmdClearAttachments"); plDesc.fragmentFunction = getFunctionNamed((string("fragCmdClearAttachments") + fragFuncSfx).data()); + plDesc.sampleCount = attKey.mtlSampleCount; for (uint32_t caIdx = 0; caIdx < kMVKAttachmentFormatDepthStencilIndex; caIdx++) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 8bee051a..51bc7208 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -360,7 +360,7 @@ void MVKPhysicalDevice::initMetalFeatures() { #endif for (uint32_t sc = VK_SAMPLE_COUNT_1_BIT; sc <= VK_SAMPLE_COUNT_64_BIT; sc <<= 1) { - if ([_mtlDevice supportsTextureSampleCount: sc]) { + if ([_mtlDevice supportsTextureSampleCount: mvkSampleCountFromVkSampleCountFlagBits((VkSampleCountFlagBits)sc)]) { _metalFeatures.supportedSampleCounts |= sc; } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index 159ebec6..3e83c415 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -76,7 +76,7 @@ public: inline uint32_t getLayerCount() { return _arrayLayers; } /** Returns the number of samples for each pixel of this image. */ - inline uint32_t getSampleCount() { return _samples; } + inline VkSampleCountFlagBits getSampleCount() { return _samples; } /** * Returns the number of bytes per image row at the specified zero-based mip level. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 37f1c00f..2a2d046e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -582,7 +582,7 @@ MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCrea _mtlTexture = nil; _mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components); - _mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() > 1)); + _mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT)); initMTLTextureViewSupport(); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 50a20803..776a9012 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -44,6 +44,9 @@ public: /** Returns the format of the depth/stencil attachment. */ VkFormat getDepthStencilFormat(); + /** Returns the Vulkan sample count of the attachments used in this subpass. */ + VkSampleCountFlagBits getSampleCount(); + /** * Populates the specified Metal MTLRenderPassDescriptor with content from this * instance, the specified framebuffer, and the specified array of clear values. @@ -92,6 +95,9 @@ public: /** Returns the Vulkan format of this attachment. */ VkFormat getFormat(); + /** Returns the Vulkan sample count of this attachment. */ + VkSampleCountFlagBits getSampleCount(); + /** * Populates the specified Metal color attachment description with the load and store actions for * the specified render subpass, and returns whether the load action will clear the attachment. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 9a8b931b..39e6b1c6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -43,6 +43,21 @@ VkFormat MVKRenderSubpass::getDepthStencilFormat() { return _renderPass->_attachments[rpAttIdx].getFormat(); } +VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() { + for (auto& ca : _colorAttachments) { + uint32_t rpAttIdx = ca.attachment; + if (rpAttIdx != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[rpAttIdx].getSampleCount(); + } + } + uint32_t rpAttIdx = _depthStencilAttachment.attachment; + if (rpAttIdx != VK_ATTACHMENT_UNUSED) { + return _renderPass->_attachments[rpAttIdx].getSampleCount(); + } + + return VK_SAMPLE_COUNT_1_BIT; +} + void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc, MVKFramebuffer* framebuffer, vector& clearValues, @@ -192,6 +207,8 @@ MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, VkFormat MVKRenderPassAttachment::getFormat() { return _info.format; } +VkSampleCountFlagBits MVKRenderPassAttachment::getSampleCount() { return _info.samples; } + bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc, MVKRenderSubpass* subpass, bool isRenderingEntireAttachment, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h index 2e0e4a3e..19234210 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h @@ -131,9 +131,7 @@ typedef struct MVKShaderModuleKey_t { namespace std { template <> struct hash { - std::size_t operator()(const MVKShaderModuleKey& k) const { - return k.codeHash; - } + std::size_t operator()(const MVKShaderModuleKey& k) const { return k.codeHash; } }; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index 0b9120bd..07dc7dd4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -305,7 +305,7 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device, size_t mslCodeLen = pCreateInfo->codeSize - hdrSize; uint64_t startTime = _device->getPerformanceTimestamp(); - codeHash = mvkHash(&magicNum, 1); + codeHash = mvkHash(&magicNum); codeHash = mvkHash(pMSLCode, mslCodeLen, codeHash); _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime); @@ -320,7 +320,7 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device, size_t mslCodeLen = pCreateInfo->codeSize - hdrSize; uint64_t startTime = _device->getPerformanceTimestamp(); - codeHash = mvkHash(&magicNum, 1); + codeHash = mvkHash(&magicNum); codeHash = mvkHash(pMSLCode, mslCodeLen, codeHash); _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime); diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index 5bd8d2a4..fd0a40e0 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -255,7 +255,7 @@ const T& mvkClamp(const T& val, const T& lower, const T& upper) { * value returned by previous calls as the seed in subsequent calls. */ template -std::size_t mvkHash(const N* pVals, std::size_t count, std::size_t seed = 5381) { +std::size_t mvkHash(const N* pVals, std::size_t count = 1, std::size_t seed = 5381) { std::size_t hash = seed; for (std::size_t i = 0; i < count; i++) { hash = ((hash << 5) + hash) ^ pVals[i]; } return hash;