diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index dbadfdd1..3d6f6f5e 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -30,7 +30,7 @@ Released TBD - Fix tessellated indirect draws using wrong kernels to map parameters. - Work around potential Metal bug with stage-in indirect buffers. - Fix zero local threadgroup size in indirect tessellated rendering. -- Fix crash with multisample layered rendering on older macOS devices. +- Fix crash when clearing attachments using layered rendering on older macOS devices. - Fixes to Metal renderpass layered rendering settings. - `MoltenVKShaderConverter` tool: Add MSL version and platform command-line options. - Allow building external dependency libraries in `Debug` mode. diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index 519e1960..c26ecbfc 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -115,7 +115,7 @@ public: private: uint32_t _firstViewport; - MVKVectorInline _mtlViewports; + MVKVectorInline _mtlViewports; }; @@ -134,7 +134,7 @@ public: private: uint32_t _firstScissor; - MVKVectorInline _mtlScissors; + MVKVectorInline _mtlScissors; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h index 91d7a655..31fd02ab 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h @@ -243,8 +243,8 @@ protected: std::vector _clearRects; std::vector _vertices; - simd::float4 _clearColors[kMVKAttachmentFormatCount]; - VkClearValue _vkClearValues[kMVKAttachmentFormatCount]; + simd::float4 _clearColors[kMVKClearAttachmentCount]; + VkClearValue _vkClearValues[kMVKClearAttachmentCount]; MVKRPSKeyClearAtt _rpsKey; uint32_t _mtlStencilValue; bool _isClearingDepth; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 0ea39255..2149cca0 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -816,7 +816,7 @@ void MVKCmdClearAttachments::setContent(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { - _rpsKey = kMVKRPSKeyClearAttDefault; + _rpsKey.reset(); _mtlStencilValue = 0; _isClearingDepth = false; _isClearingStencil = false; @@ -831,26 +831,26 @@ void MVKCmdClearAttachments::setContent(uint32_t attachmentCount, if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)) { uint32_t caIdx = clrAtt.colorAttachment; // Might be VK_ATTACHMENT_UNUSED if (caIdx != VK_ATTACHMENT_UNUSED) { - _rpsKey.enable(caIdx); + _rpsKey.enableAttachment(caIdx); _vkClearValues[caIdx] = clrAtt.clearValue; } } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT)) { _isClearingDepth = true; - _rpsKey.enable(kMVKAttachmentFormatDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); mtlDepthVal = mvkMTLClearDepthFromVkClearValue(clrAtt.clearValue); } if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT)) { _isClearingStencil = true; - _rpsKey.enable(kMVKAttachmentFormatDepthStencilIndex); + _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex); _mtlStencilValue = mvkMTLClearStencilFromVkClearValue(clrAtt.clearValue); } } // The depth value (including vertex position Z value) is held in the last index. - _clearColors[kMVKAttachmentFormatDepthStencilIndex] = { mtlDepthVal, mtlDepthVal, mtlDepthVal, mtlDepthVal }; + _clearColors[kMVKClearAttachmentDepthStencilIndex] = { mtlDepthVal, mtlDepthVal, mtlDepthVal, mtlDepthVal }; _clearRects.clear(); _clearRects.reserve(rectCount); @@ -932,8 +932,9 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { uint32_t vtxCnt = (uint32_t)_vertices.size(); uint32_t vtxBuffIdx = getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex); - // Populate the render pipeline state attachment key with attachment info from the subpass. + // Populate the render pipeline state attachment key with info from the subpass and framebuffer. _rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount()); + if (cmdEncoder->_isUsingLayeredRendering) { _rpsKey.enableLayeredRendering(); } uint32_t caCnt = subpass->getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { @@ -945,7 +946,7 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) { VkFormat vkAttFmt = subpass->getDepthStencilFormat(); MTLPixelFormat mtlAttFmt = cmdPool->getMTLPixelFormatFromVkFormat(vkAttFmt); - _rpsKey.attachmentMTLPixelFormats[kMVKAttachmentFormatDepthStencilIndex] = mtlAttFmt; + _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlAttFmt; bool isClearingDepth = _isClearingDepth && mvkMTLPixelFormatIsDepthFormat(mtlAttFmt); bool isClearingStencil = _isClearingStencil && mvkMTLPixelFormatIsStencilFormat(mtlAttFmt); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 8e2fa9b2..c2d0356b 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -420,6 +420,9 @@ public: /** The size of the threadgroup for the compute shader. */ MTLSize _mtlThreadgroupSize; + /** Indicates whether the current render subpass is rendering to an array (layered) framebuffer. */ + bool _isUsingLayeredRendering; + #pragma mark Construction diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 9ba1692f..09356b48 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -234,6 +234,7 @@ void MVKCommandBuffer::recordDraw(MVKLoadStoreOverrideMixin* mvkDraw) { void MVKCommandEncoder::encode(id mtlCmdBuff) { _subpassContents = VK_SUBPASS_CONTENTS_INLINE; _renderSubpassIndex = 0; + _isUsingLayeredRendering = false; _mtlCmdBuffer = mtlCmdBuff; // not retained @@ -280,7 +281,12 @@ void MVKCommandEncoder::setSubpass(VkSubpassContents subpassContents, uint32_t s _subpassContents = subpassContents; _renderSubpassIndex = subpassIndex; - beginMetalRenderPass(loadOverride, storeOverride); + _isUsingLayeredRendering = ((_framebuffer->getLayerCount() > 1) && + _device->_pMetalFeatures->layeredRendering && + (_device->_pMetalFeatures->multisampleLayeredRendering || + (getSubpass()->getSampleCount() == VK_SAMPLE_COUNT_1_BIT))); + + beginMetalRenderPass(loadOverride, storeOverride); } // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder. @@ -293,11 +299,7 @@ void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride, bool storeOverri mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer(); // Only set the layered rendering properties if layered rendering is supported and the framebuffer really has multiple layers - if ((_framebuffer->getLayerCount() > 1) && - _device->_pMetalFeatures->layeredRendering && - (_device->_pMetalFeatures->multisampleLayeredRendering || - (getSubpass()->getSampleCount() == VK_SAMPLE_COUNT_1_BIT))) { - + if (_isUsingLayeredRendering) { VkExtent2D fbExtent = _framebuffer->getExtent2D(); mtlRPDesc.renderTargetWidthMVK = min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width); mtlRPDesc.renderTargetHeightMVK = min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 87646d25..843c2098 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -151,7 +151,7 @@ protected: void encodeImpl(uint32_t stage) override; void resetImpl() override; - MVKVectorInline _mtlViewports, _mtlDynamicViewports; + MVKVectorInline _mtlViewports, _mtlDynamicViewports; }; @@ -180,7 +180,7 @@ protected: void encodeImpl(uint32_t stage) override; void resetImpl() override; - MVKVectorInline _mtlScissors, _mtlDynamicScissors; + MVKVectorInline _mtlScissors, _mtlDynamicScissors; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h index efabe554..253580fb 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h @@ -20,7 +20,6 @@ #include "MVKDevice.h" #include "MVKCommandBuffer.h" -#include "MVKCommandResourceFactory.h" #include "MVKCommandEncodingPool.h" #include "MVKCommand.h" #include "MVKCmdPipeline.h" diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index a9ddfb0e..55bef820 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -74,8 +74,9 @@ namespace std { #pragma mark - #pragma mark MVKRPSKeyClearAtt -#define kMVKAttachmentFormatCount 9 -#define kMVKAttachmentFormatDepthStencilIndex (kMVKAttachmentFormatCount - 1) +#define kMVKClearAttachmentCount (kMVKCachedColorAttachmentCount + 1) +#define kMVKClearAttachmentDepthStencilIndex (kMVKClearAttachmentCount - 1) +#define kMVKClearAttachmentLayeredRenderingBitIndex kMVKClearAttachmentCount /** * Key to use for looking up cached MTLRenderPipelineState instances. @@ -85,37 +86,40 @@ namespace std { * 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 attachmentMTLPixelFormats[kMVKClearAttachmentCount]; uint16_t mtlSampleCount; - uint32_t enabledFlags; + uint16_t flags; // bitcount > kMVKClearAttachmentLayeredRenderingBitIndex const static uint32_t bitFlag = 1; - void enable(uint32_t attIdx) { mvkEnableFlag(enabledFlags, bitFlag << attIdx); } + void enableAttachment(uint32_t attIdx) { mvkEnableFlag(flags, bitFlag << attIdx); } - bool isEnabled(uint32_t attIdx) { return mvkIsAnyFlagEnabled(enabledFlags, bitFlag << attIdx); } + bool isAttachmentEnabled(uint32_t attIdx) { return mvkIsAnyFlagEnabled(flags, bitFlag << attIdx); } + + void enableLayeredRendering() { mvkEnableFlag(flags, bitFlag << kMVKClearAttachmentLayeredRenderingBitIndex); } + + bool isLayeredRenderingEnabled() { return mvkIsAnyFlagEnabled(flags, bitFlag << kMVKClearAttachmentLayeredRenderingBitIndex); } bool operator==(const MVKRPSKeyClearAtt_t& rhs) const { - return ((enabledFlags == rhs.enabledFlags) && + return ((flags == rhs.flags) && (mtlSampleCount == rhs.mtlSampleCount) && (memcmp(attachmentMTLPixelFormats, rhs.attachmentMTLPixelFormats, sizeof(attachmentMTLPixelFormats)) == 0)); } std::size_t hash() const { - std::size_t hash = mvkHash(&enabledFlags); + std::size_t hash = mvkHash(&flags); hash = mvkHash(&mtlSampleCount, 1, hash); - return mvkHash(attachmentMTLPixelFormats, kMVKAttachmentFormatCount, hash); + return mvkHash(attachmentMTLPixelFormats, kMVKClearAttachmentCount, hash); } - MVKRPSKeyClearAtt_t() { + void reset() { memset(this, 0, sizeof(*this)); mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(VK_SAMPLE_COUNT_1_BIT); } -} MVKRPSKeyClearAtt; + MVKRPSKeyClearAtt_t() { reset(); } -/** An instance populated with default values, for use in resetting other instances to default state. */ -const MVKRPSKeyClearAtt kMVKRPSKeyClearAttDefault; +} MVKRPSKeyClearAtt; /** * Hash structure implementation for MVKRPSKeyClearAtt in std namespace, diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index da458bc5..29d56a7f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -95,12 +95,12 @@ id MVKCommandResourceFactory::newCmdClearMTLRenderPipeli plDesc.sampleCount = attKey.mtlSampleCount; plDesc.inputPrimitiveTopologyMVK = MTLPrimitiveTopologyClassTriangle; - for (uint32_t caIdx = 0; caIdx < kMVKAttachmentFormatDepthStencilIndex; caIdx++) { + for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx]; colorDesc.pixelFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]; - colorDesc.writeMask = attKey.isEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone; + colorDesc.writeMask = attKey.isAttachmentEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone; } - MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKAttachmentFormatDepthStencilIndex]; + MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex]; if (mvkMTLPixelFormatIsDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; } if (mvkMTLPixelFormatIsStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; } @@ -181,7 +181,6 @@ id MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg& id MVKCommandResourceFactory::getClearVertFunction(MVKRPSKeyClearAtt& attKey) { id mtlFunc = nil; - bool allowLayers = _device->_pMetalFeatures->layeredRendering && (attKey.mtlSampleCount == 1 || _device->_pMetalFeatures->multisampleLayeredRendering); @autoreleasepool { NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ]; [msl appendLineMVK: @"#include "]; @@ -197,7 +196,7 @@ id MVKCommandResourceFactory::getClearVertFunction(MVKRPSKeyClearAt [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; [msl appendLineMVK: @" float4 v_position [[position]];"]; - [msl appendFormat: @" uint layer%s;", allowLayers ? " [[render_target_array_index]]" : ""]; + [msl appendFormat: @" uint layer%s;", attKey.isLayeredRenderingEnabled() ? " [[render_target_array_index]]" : ""]; [msl appendLineMVK: @"} VaryingsPos;"]; [msl appendLineMVK]; @@ -232,8 +231,8 @@ id MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAt [msl appendLineMVK: @"} ClearColorsIn;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; - for (uint32_t caIdx = 0; caIdx < kMVKAttachmentFormatDepthStencilIndex; caIdx++) { - if (attKey.isEnabled(caIdx)) { + for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + if (attKey.isAttachmentEnabled(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" %@4 color%u [[color(%u)]];", typeStr, caIdx, caIdx]; [msl appendLineMVK]; @@ -246,8 +245,8 @@ id MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAt [msl appendFormat: @"fragment ClearColorsOut %@(VaryingsPos varyings [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName]; [msl appendLineMVK]; [msl appendLineMVK: @" ClearColorsOut ccOut;"]; - for (uint32_t caIdx = 0; caIdx < kMVKAttachmentFormatDepthStencilIndex; caIdx++) { - if (attKey.isEnabled(caIdx)) { + for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) { + if (attKey.isAttachmentEnabled(caIdx)) { NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]); [msl appendFormat: @" ccOut.color%u = %@4(ccIn.colors[%u]);", caIdx, typeStr, caIdx]; [msl appendLineMVK]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 129e6eed..5680d9a0 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -67,8 +67,8 @@ class MVKCommandResourceFactory; const static uint32_t kMVKVertexContentBufferIndex = 0; // Parameters to define the sizing of inline collections -const static uint32_t kMVKCachedViewportCount = 16; -const static uint32_t kMVKCachedScissorCount = 16; +const static uint32_t kMVKCachedViewportScissorCount = 16; +const static uint32_t kMVKCachedColorAttachmentCount = 8; #pragma mark - diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index d2fdfd56..d2ea1af3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1002,13 +1002,13 @@ void MVKPhysicalDevice::initProperties() { // Limits #if MVK_IOS if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily2_v1] ) { - _properties.limits.maxColorAttachments = 8; + _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; } else { - _properties.limits.maxColorAttachments = 4; + _properties.limits.maxColorAttachments = 4; // < kMVKCachedColorAttachmentCount } #endif #if MVK_MACOS - _properties.limits.maxColorAttachments = 8; + _properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount; #endif _properties.limits.maxFragmentOutputAttachments = _properties.limits.maxColorAttachments; @@ -1038,7 +1038,7 @@ void MVKPhysicalDevice::initProperties() { float maxVPDim = max(_properties.limits.maxViewportDimensions[0], _properties.limits.maxViewportDimensions[1]); _properties.limits.viewportBoundsRange[0] = (-2.0 * maxVPDim); _properties.limits.viewportBoundsRange[1] = (2.0 * maxVPDim) - 1; - _properties.limits.maxViewports = _features.multiViewport ? 16 : 1; + _properties.limits.maxViewports = _features.multiViewport ? kMVKCachedViewportScissorCount : 1; _properties.limits.maxImageDimension3D = (2 * KIBI); _properties.limits.maxImageArrayLayers = (2 * KIBI); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 63c94ff7..b14f33c2 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -608,6 +608,11 @@ void MVKImage::validateConfig(const VkImageCreateInfo* pCreateInfo) { setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, depth/stencil formats may only be used with 2D images.")); } + bool isAttachment = mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); + if (isAttachment && (pCreateInfo->arrayLayers > 1) && !_device->_pMetalFeatures->layeredRendering) { + setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to array (layered) attachments.")); + } + if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)) { setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal does not allow uncompressed views of compressed images.")); } @@ -635,8 +640,8 @@ VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreate validSamples = VK_SAMPLE_COUNT_1_BIT; } - if ( !_device->_pMetalFeatures->multisampleLayeredRendering && mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))) { + bool isAttachment = mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); + if (isAttachment && !_device->_pMetalFeatures->multisampleLayeredRendering) { setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to multisampled array (layered) attachments. Setting sample count to 1.")); validSamples = VK_SAMPLE_COUNT_1_BIT; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index a685e4ce..39f85433 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -236,8 +236,8 @@ protected: VkPipelineRasterizationStateCreateInfo _rasterInfo; VkPipelineDepthStencilStateCreateInfo _depthStencilInfo; - MVKVectorInline _mtlViewports; - MVKVectorInline _mtlScissors; + MVKVectorInline _mtlViewports; + MVKVectorInline _mtlScissors; MTLComputePipelineDescriptor* _mtlTessControlStageDesc = nil;