Merge pull request #1878 from billhollings/dyn-rend-separate-depth-stencil

Support separate depth and stencil attachments during dynamic rendering
This commit is contained in:
Bill Hollings 2023-04-28 12:38:29 -04:00 committed by GitHub
commit e50cb32127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 605 additions and 592 deletions

View File

@ -21,6 +21,7 @@ Released TBD
- Add support for extensions:
- `VK_KHR_map_memory2`
- Support BC compression on iOS/tvOS where available (iOS/tvOS 16.4 and above and supported by the GPU).
- Support separate depth and stencil attachments during dynamic rendering.
- Fix memory leak when waiting on timeline semaphores.
- Ensure shaders that use `PhysicalStorageBufferAddresses` encode the use of the associated `MTLBuffer`.
- Disable pipeline cache compression prior to macOS 10.15 and iOS/tvOS 13.0.

View File

@ -262,7 +262,7 @@ protected:
// Concrete template class implementations.
typedef MVKCmdSetViewport<1> MVKCmdSetViewport1;
typedef MVKCmdSetViewport<kMVKCachedViewportScissorCount> MVKCmdSetViewportMulti;
typedef MVKCmdSetViewport<kMVKMaxViewportScissorCount> MVKCmdSetViewportMulti;
#pragma mark -
@ -292,7 +292,7 @@ protected:
// Concrete template class implementations.
typedef MVKCmdSetScissor<1> MVKCmdSetScissor1;
typedef MVKCmdSetScissor<kMVKCachedViewportScissorCount> MVKCmdSetScissorMulti;
typedef MVKCmdSetScissor<kMVKMaxViewportScissorCount> MVKCmdSetScissorMulti;
#pragma mark -

View File

@ -282,7 +282,7 @@ void MVKCmdSetViewport<N>::encode(MVKCommandEncoder* cmdEncoder) {
}
template class MVKCmdSetViewport<1>;
template class MVKCmdSetViewport<kMVKCachedViewportScissorCount>;
template class MVKCmdSetViewport<kMVKMaxViewportScissorCount>;
#pragma mark -
@ -309,7 +309,7 @@ void MVKCmdSetScissor<N>::encode(MVKCommandEncoder* cmdEncoder) {
}
template class MVKCmdSetScissor<1>;
template class MVKCmdSetScissor<kMVKCachedViewportScissorCount>;
template class MVKCmdSetScissor<kMVKMaxViewportScissorCount>;
#pragma mark -

View File

@ -284,8 +284,6 @@ protected:
float _mtlDepthVal;
uint32_t _mtlStencilValue;
MVKCommandUse _commandUse;
bool _isClearingDepth;
bool _isClearingStencil;
};
@ -326,7 +324,7 @@ protected:
VkClearValue& getClearValue(uint32_t attIdx) override { return _vkClearValues[attIdx]; }
void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) override { _vkClearValues[attIdx] = clearValue; }
VkClearValue _vkClearValues[kMVKCachedColorAttachmentCount];
VkClearValue _vkClearValues[kMVKMaxColorAttachmentCount];
};
typedef MVKCmdClearMultiAttachments<1> MVKCmdClearMultiAttachments1;

View File

@ -1260,8 +1260,6 @@ VkResult MVKCmdClearAttachments<N>::setContent(MVKCommandBuffer* cmdBuff,
_commandUse = cmdUse;
_mtlDepthVal = 0.0;
_mtlStencilValue = 0;
_isClearingDepth = false;
_isClearingStencil = false;
MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
// For each attachment to be cleared, mark it so in the render pipeline state
@ -1279,14 +1277,12 @@ VkResult MVKCmdClearAttachments<N>::setContent(MVKCommandBuffer* cmdBuff,
}
if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT)) {
_isClearingDepth = true;
_rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex);
_rpsKey.enableAttachment(kMVKClearAttachmentDepthIndex);
_mtlDepthVal = pixFmts->getMTLClearDepthValue(clrAtt.clearValue);
}
if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT)) {
_isClearingStencil = true;
_rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex);
_rpsKey.enableAttachment(kMVKClearAttachmentStencilIndex);
_mtlStencilValue = pixFmts->getMTLClearStencilValue(clrAtt.clearValue);
}
}
@ -1443,31 +1439,24 @@ void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha};
}
// The depth value (including vertex position Z value) is held in the last index.
clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal };
// The depth value is the vertex position Z value.
clearColors[kMVKClearAttachmentDepthIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal };
VkFormat vkAttFmt = subpass->getDepthStencilFormat();
MTLPixelFormat mtlAttFmt = pixFmts->getMTLPixelFormat(vkAttFmt);
_rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlAttFmt;
_rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex] = pixFmts->getMTLPixelFormat(subpass->getDepthFormat());
if ( !subpass->isDepthAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentDepthIndex); }
bool isClearingDepth = _isClearingDepth && pixFmts->isDepthFormat(mtlAttFmt);
bool isClearingStencil = _isClearingStencil && pixFmts->isStencilFormat(mtlAttFmt);
if (!isClearingDepth && !isClearingStencil) {
// If the subpass attachment isn't actually used, don't try to clear it.
_rpsKey.disableAttachment(kMVKClearAttachmentDepthStencilIndex);
}
_rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex] = pixFmts->getMTLPixelFormat(subpass->getStencilFormat());
if ( !subpass->isStencilAttachmentUsed() ) { _rpsKey.disableAttachment(kMVKClearAttachmentStencilIndex); }
if (!_rpsKey.isAnyAttachmentEnabled()) {
// Nothing to do.
return;
}
if ( !_rpsKey.isAnyAttachmentEnabled() ) { return; }
// Render the clear colors to the attachments
MVKCommandEncodingPool* cmdEncPool = cmdEncoder->getCommandEncodingPool();
id<MTLRenderCommandEncoder> mtlRendEnc = cmdEncoder->_mtlRenderEncoder;
[mtlRendEnc pushDebugGroup: getMTLDebugGroupLabel()];
[mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdClearMTLRenderPipelineState(_rpsKey)];
[mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isClearingDepth, isClearingStencil)];
[mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(_rpsKey.isAttachmentUsed(kMVKClearAttachmentDepthIndex),
_rpsKey.isAttachmentUsed(kMVKClearAttachmentStencilIndex))];
[mtlRendEnc setStencilReferenceValue: _mtlStencilValue];
[mtlRendEnc setCullMode: MTLCullModeNone];
[mtlRendEnc setTriangleFillMode: MTLTriangleFillModeFill];

View File

@ -401,10 +401,17 @@ void MVKCommandEncoder::beginRendering(MVKCommand* rendCmd, const VkRenderingInf
? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
: VK_SUBPASS_CONTENTS_INLINE);
uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2;
MVKImageView* attachments[maxAttCnt];
uint32_t maxAttCnt = (pRenderingInfo->colorAttachmentCount + 2) * 2;
MVKImageView* imageViews[maxAttCnt];
VkClearValue clearValues[maxAttCnt];
uint32_t attCnt = mvkGetAttachments(pRenderingInfo, attachments, clearValues);
uint32_t attCnt = 0;
MVKRenderingAttachmentIterator attIter(pRenderingInfo);
attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void {
imageViews[attCnt] = (MVKImageView*)(isResolveAttachment ? pAttInfo->resolveImageView : pAttInfo->imageView);
clearValues[attCnt] = pAttInfo->clearValue;
attCnt++;
});
// If we're resuming a suspended renderpass, continue to use the existing renderpass
// (with updated rendering flags) and framebuffer. Otherwise, create new transient
@ -419,13 +426,14 @@ void MVKCommandEncoder::beginRendering(MVKCommand* rendCmd, const VkRenderingInf
mvkRP->setRenderingFlags(pRenderingInfo->flags);
mvkFB = _pEncodingContext->getFramebuffer();
} else {
mvkRP = mvkCreateRenderPass(getDevice(), pRenderingInfo);
mvkFB = mvkCreateFramebuffer(getDevice(), pRenderingInfo, mvkRP);
auto* mvkDev = getDevice();
mvkRP = mvkDev->createRenderPass(pRenderingInfo, nullptr);
mvkFB = mvkDev->createFramebuffer(pRenderingInfo, nullptr);
}
beginRenderpass(rendCmd, contents, mvkRP, mvkFB,
pRenderingInfo->renderArea,
MVKArrayRef(clearValues, attCnt),
MVKArrayRef(attachments, attCnt),
MVKArrayRef(imageViews, attCnt),
MVKArrayRef<MVKArrayRef<MTLSamplePosition>>(),
kMVKCommandUseBeginRendering);

View File

@ -152,7 +152,7 @@ public:
protected:
void encodeImpl(uint32_t stage) override;
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports, _dynamicViewports;
MVKSmallVector<VkViewport, kMVKMaxViewportScissorCount> _viewports, _dynamicViewports;
};
@ -180,7 +180,7 @@ public:
protected:
void encodeImpl(uint32_t stage) override;
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors, _dynamicScissors;
MVKSmallVector<VkRect2D, kMVKMaxViewportScissorCount> _scissors, _dynamicScissors;
};

View File

@ -328,15 +328,12 @@ void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() {
MVKCommandEncoderState::beginMetalRenderPass();
MVKRenderSubpass* mvkSubpass = _cmdEncoder->getSubpass();
MVKPixelFormats* pixFmts = _cmdEncoder->getPixelFormats();
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkSubpass->getDepthStencilFormat());
bool prevHasDepthAttachment = _hasDepthAttachment;
_hasDepthAttachment = pixFmts->isDepthFormat(mtlDSFormat);
_hasDepthAttachment = mvkSubpass->isDepthAttachmentUsed();
if (_hasDepthAttachment != prevHasDepthAttachment) { markDirty(); }
bool prevHasStencilAttachment = _hasStencilAttachment;
_hasStencilAttachment = pixFmts->isStencilFormat(mtlDSFormat);
_hasStencilAttachment = mvkSubpass->isStencilAttachmentUsed();
if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); }
}

View File

@ -107,9 +107,11 @@ namespace std {
#pragma mark -
#pragma mark MVKRPSKeyClearAtt
#define kMVKClearAttachmentCount (kMVKCachedColorAttachmentCount + 1)
#define kMVKClearAttachmentDepthStencilIndex (kMVKClearAttachmentCount - 1)
#define kMVKClearAttachmentLayeredRenderingBitIndex kMVKClearAttachmentCount
const static uint32_t kMVKClearColorAttachmentCount = kMVKMaxColorAttachmentCount;
const static uint32_t kMVKClearAttachmentDepthIndex = kMVKClearColorAttachmentCount;
const static uint32_t kMVKClearAttachmentStencilIndex = kMVKClearAttachmentDepthIndex + 1;
const static uint32_t kMVKClearAttachmentCount = kMVKClearAttachmentStencilIndex + 1;
const static uint32_t kMVKClearAttachmentLayeredRenderingBitIndex = kMVKClearAttachmentStencilIndex + 1;
/**
* Key to use for looking up cached MTLRenderPipelineState instances.

View File

@ -113,6 +113,8 @@ id<MTLSamplerState> MVKCommandResourceFactory::newCmdBlitImageMTLSamplerState(MT
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey,
MVKVulkanAPIDeviceObject* owner) {
MVKPixelFormats* pixFmts = getPixelFormats();
id<MTLFunction> vtxFunc = newClearVertFunction(attKey); // temp retain
id<MTLFunction> fragFunc = newClearFragFunction(attKey); // temp retain
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retain
@ -122,15 +124,17 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipeli
plDesc.sampleCount = attKey.mtlSampleCount;
plDesc.inputPrimitiveTopologyMVK = MTLPrimitiveTopologyClassTriangle;
for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) {
for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) {
MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx];
colorDesc.pixelFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx];
colorDesc.writeMask = attKey.isAttachmentEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone;
}
MVKPixelFormats* pixFmts = getPixelFormats();
MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex];
if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; }
if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; }
MTLPixelFormat mtlDepthFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthIndex];
if (pixFmts->isDepthFormat(mtlDepthFormat)) { plDesc.depthAttachmentPixelFormat = mtlDepthFormat; }
MTLPixelFormat mtlStencilFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKClearAttachmentStencilIndex];
if (pixFmts->isStencilFormat(mtlStencilFormat)) { plDesc.stencilAttachmentPixelFormat = mtlStencilFormat; }
MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor;
@ -273,7 +277,7 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
[msl appendLineMVK: @" return out;"];
[msl appendLineMVK: @"}"];
// MVKLogDebug("\n%s", msl.UTF8String);
// MVKLogInfo("\n%s", msl.UTF8String);
return newMTLFunction(msl, funcName);
}
@ -303,12 +307,13 @@ id<MTLFunction> MVKCommandResourceFactory::newClearVertFunction(MVKRPSKeyClearAt
[msl appendFormat: @"vertex VaryingsPos %@(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) {", funcName];
[msl appendLineMVK];
[msl appendLineMVK: @" VaryingsPos varyings;"];
[msl appendLineMVK: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0);"];
[msl appendFormat: @" varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[%d].r, 1.0);", kMVKClearAttachmentDepthIndex];
[msl appendLineMVK];
[msl appendLineMVK: @" varyings.layer = uint(attributes.a_position.w);"];
[msl appendLineMVK: @" return varyings;"];
[msl appendLineMVK: @"}"];
// MVKLogDebug("\n%s", msl.UTF8String);
// MVKLogInfo("\n%s", msl.UTF8String);
return newMTLFunction(msl, funcName);
}
@ -329,7 +334,7 @@ id<MTLFunction> MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAt
[msl appendLineMVK: @"} ClearColorsIn;"];
[msl appendLineMVK];
[msl appendLineMVK: @"typedef struct {"];
for (uint32_t caIdx = 0; caIdx < kMVKClearAttachmentDepthStencilIndex; caIdx++) {
for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) {
if (attKey.isAttachmentUsed(caIdx)) {
NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]);
[msl appendFormat: @" %@4 color%u [[color(%u)]];", typeStr, caIdx, caIdx];
@ -343,7 +348,7 @@ id<MTLFunction> MVKCommandResourceFactory::newClearFragFunction(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 < kMVKClearAttachmentDepthStencilIndex; caIdx++) {
for (uint32_t caIdx = 0; caIdx < kMVKClearColorAttachmentCount; caIdx++) {
if (attKey.isAttachmentUsed(caIdx)) {
NSString* typeStr = getMTLFormatTypeString((MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx]);
[msl appendFormat: @" ccOut.color%u = %@4(ccIn.colors[%u]);", caIdx, typeStr, caIdx];
@ -353,7 +358,7 @@ id<MTLFunction> MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAt
[msl appendLineMVK: @" return ccOut;"];
[msl appendLineMVK: @"}"];
// MVKLogDebug("\n%s", msl.UTF8String);
// MVKLogInfo("\n%s", msl.UTF8String);
return newMTLFunction(msl, funcName);
}

View File

@ -80,8 +80,8 @@ const static uint32_t kMVKQueueFamilyCount = 4;
const static uint32_t kMVKQueueCountPerQueueFamily = 1; // Must be 1. See comments in MVKPhysicalDevice::getQueueFamilies()
const static uint32_t kMVKMinSwapchainImageCount = 2;
const static uint32_t kMVKMaxSwapchainImageCount = 3;
const static uint32_t kMVKCachedViewportScissorCount = 16;
const static uint32_t kMVKCachedColorAttachmentCount = 8;
const static uint32_t kMVKMaxColorAttachmentCount = 8;
const static uint32_t kMVKMaxViewportScissorCount = 16;
const static uint32_t kMVKMaxDescriptorSetCount = SPIRV_CROSS_NAMESPACE::kMaxArgumentBuffers;
#if !MVK_XCODE_12
@ -631,6 +631,8 @@ public:
MVKFramebuffer* createFramebuffer(const VkFramebufferCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator);
MVKFramebuffer* createFramebuffer(const VkRenderingInfo* pRenderingInfo,
const VkAllocationCallbacks* pAllocator);
void destroyFramebuffer(MVKFramebuffer* mvkFB,
const VkAllocationCallbacks* pAllocator);
@ -638,6 +640,8 @@ public:
const VkAllocationCallbacks* pAllocator);
MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo,
const VkAllocationCallbacks* pAllocator);
MVKRenderPass* createRenderPass(const VkRenderingInfo* pRenderingInfo,
const VkAllocationCallbacks* pAllocator);
void destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator);

View File

@ -2269,17 +2269,17 @@ void MVKPhysicalDevice::initFeatures() {
void MVKPhysicalDevice::initLimits() {
#if MVK_TVOS
_properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount;
_properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount;
#endif
#if MVK_IOS
if (supportsMTLFeatureSet(iOS_GPUFamily2_v1)) {
_properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount;
_properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount;
} else {
_properties.limits.maxColorAttachments = 4; // < kMVKCachedColorAttachmentCount
_properties.limits.maxColorAttachments = 4; // < kMVKMaxColorAttachmentCount
}
#endif
#if MVK_MACOS
_properties.limits.maxColorAttachments = kMVKCachedColorAttachmentCount;
_properties.limits.maxColorAttachments = kMVKMaxColorAttachmentCount;
#endif
_properties.limits.maxFragmentOutputAttachments = _properties.limits.maxColorAttachments;
@ -2309,7 +2309,7 @@ void MVKPhysicalDevice::initLimits() {
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 ? kMVKCachedViewportScissorCount : 1;
_properties.limits.maxViewports = _features.multiViewport ? kMVKMaxViewportScissorCount : 1;
_properties.limits.maxImageDimension3D = _metalFeatures.maxTextureLayers;
_properties.limits.maxImageArrayLayers = _metalFeatures.maxTextureLayers;
@ -3893,6 +3893,11 @@ MVKFramebuffer* MVKDevice::createFramebuffer(const VkFramebufferCreateInfo* pCre
return new MVKFramebuffer(this, pCreateInfo);
}
MVKFramebuffer* MVKDevice::createFramebuffer(const VkRenderingInfo* pRenderingInfo,
const VkAllocationCallbacks* pAllocator) {
return new MVKFramebuffer(this, pRenderingInfo);
}
void MVKDevice::destroyFramebuffer(MVKFramebuffer* mvkFB,
const VkAllocationCallbacks* pAllocator) {
if (mvkFB) { mvkFB->destroy(); }
@ -3908,6 +3913,11 @@ MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo2* pCreat
return new MVKRenderPass(this, pCreateInfo);
}
MVKRenderPass* MVKDevice::createRenderPass(const VkRenderingInfo* pRenderingInfo,
const VkAllocationCallbacks* pAllocator) {
return new MVKRenderPass(this, pRenderingInfo);
}
void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator) {
if (mvkRP) { mvkRP->destroy(); }

View File

@ -58,6 +58,8 @@ public:
MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo);
MVKFramebuffer(MVKDevice* device, const VkRenderingInfo* pRenderingInfo);
~MVKFramebuffer() override;
protected:
@ -69,12 +71,3 @@ protected:
VkExtent2D _extent;
uint32_t _layerCount;
};
#pragma mark -
#pragma mark Support functions
/** Returns an image-less MVKFramebuffer object created from the rendering info. */
MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device,
const VkRenderingInfo* pRenderingInfo,
MVKRenderPass* mvkRenderPass);

View File

@ -82,8 +82,8 @@ id<MTLTexture> MVKFramebuffer::getDummyAttachmentMTLTexture(MVKRenderSubpass* su
MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
const VkFramebufferCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
_extent = { .width = pCreateInfo->width, .height = pCreateInfo->height };
_layerCount = pCreateInfo->layers;
_extent = { .width = pCreateInfo->width, .height = pCreateInfo->height };
// If this is not an image-less framebuffer, add the attachments
if ( !mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) ) {
@ -94,51 +94,25 @@ MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
}
}
MVKFramebuffer::~MVKFramebuffer() {
[_mtlDummyTex release];
}
MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) {
_layerCount = pRenderingInfo->layerCount;
#pragma mark -
#pragma mark Support functions
MVKFramebuffer* mvkCreateFramebuffer(MVKDevice* device,
const VkRenderingInfo* pRenderingInfo,
MVKRenderPass* mvkRenderPass) {
uint32_t attCnt = 0;
VkExtent3D fbExtent = {};
_extent = {};
for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) {
auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx];
if (clrAtt.imageView) {
fbExtent = ((MVKImageView*)clrAtt.imageView)->getExtent3D();
attCnt++;
if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) {
attCnt++;
_extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)clrAtt.imageView)->getExtent3D());
}
}
if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) {
_extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pDepthAttachment->imageView)->getExtent3D());
}
auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment;
if (pDSAtt) {
if (pDSAtt->imageView) {
fbExtent = ((MVKImageView*)pDSAtt->imageView)->getExtent3D();
attCnt++;
}
if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) {
attCnt++;
if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) {
_extent = mvkVkExtent2DFromVkExtent3D(((MVKImageView*)pRenderingInfo->pStencilAttachment->imageView)->getExtent3D());
}
}
VkFramebufferCreateInfo fbCreateInfo;
fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbCreateInfo.pNext = nullptr;
fbCreateInfo.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
fbCreateInfo.renderPass = (VkRenderPass)mvkRenderPass;
fbCreateInfo.attachmentCount = attCnt;
fbCreateInfo.pAttachments = nullptr;
fbCreateInfo.width = fbExtent.width;
fbCreateInfo.height = fbExtent.height;
fbCreateInfo.layers = pRenderingInfo->layerCount;
return device->createFramebuffer(&fbCreateInfo, nullptr);
MVKFramebuffer::~MVKFramebuffer() {
[_mtlDummyTex release];
}

View File

@ -560,6 +560,9 @@ public:
/** Returns the 3D extent of this image at the specified mipmap level. */
VkExtent3D getExtent3D(uint8_t planeIndex = 0, uint32_t mipLevel = 0) { return _image->getExtent3D(planeIndex, mipLevel); }
/** Return the underlying image. */
MVKImage* getImage() { return _image; }
#pragma mark Metal
/** Returns the Metal texture underlying this image view. */

View File

@ -346,17 +346,12 @@ protected:
void markIfUsingPhysicalStorageBufferAddressesCapability(SPIRVToMSLConversionResultInfo& resultsInfo,
MVKShaderStage stage);
const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr;
VkPipelineTessellationStateCreateInfo _tessInfo;
VkPipelineRasterizationStateCreateInfo _rasterInfo;
VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
MVKSmallVector<VkViewport, kMVKMaxViewportScissorCount> _viewports;
MVKSmallVector<VkRect2D, kMVKMaxViewportScissorCount> _scissors;
MVKSmallVector<VkDynamicState> _dynamicState;
MVKSmallVector<MTLSamplePosition> _customSamplePositions;
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
@ -364,7 +359,12 @@ protected:
MVKSmallVector<MVKStagedMTLArgumentEncoders> _mtlArgumentEncoders;
MVKSmallVector<MVKStagedDescriptorBindingUse> _descriptorBindingUse;
MVKSmallVector<MVKShaderStage> _stagesUsingPhysicalStorageBufferAddressesCapability;
std::unordered_map<uint32_t, id<MTLRenderPipelineState>> _multiviewMTLPipelineStates;
const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pTessEvalSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pFragmentSS = nullptr;
MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil;
id<MTLFunction> _mtlTessVertexFunctions[3] = {nil, nil, nil};
@ -373,18 +373,17 @@ protected:
id<MTLComputePipelineState> _mtlTessVertexStageIndex32State = nil;
id<MTLComputePipelineState> _mtlTessControlStageState = nil;
id<MTLRenderPipelineState> _mtlPipelineState = nil;
std::unordered_map<uint32_t, id<MTLRenderPipelineState>> _multiviewMTLPipelineStates;
float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 };
MTLCullMode _mtlCullMode;
MTLWinding _mtlFrontWinding;
MTLTriangleFillMode _mtlFillMode;
MTLDepthClipMode _mtlDepthClipMode;
MTLPrimitiveType _mtlPrimitiveType;
float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 };
uint32_t _outputControlPointCount;
MVKShaderImplicitRezBinding _reservedVertexAttributeBufferCount;
MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _outputControlPointCount;
uint32_t _tessCtlPatchOutputBufferIndex = 0;
uint32_t _tessCtlLevelBufferIndex = 0;
@ -408,7 +407,6 @@ protected:
bool _needsFragmentViewRangeBuffer = false;
bool _isRasterizing = false;
bool _isRasterizingColor = false;
bool _isRasterizingDepthStencil = false;
bool _isUsingCustomSamplePositions = false;
};

View File

@ -401,7 +401,6 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo);
_isRasterizing = !isRasterizationDisabled(pCreateInfo);
_isRasterizingColor = _isRasterizing && mvkHasColorAttachments(pRendInfo);
_isRasterizingDepthStencil = _isRasterizing && mvkGetDepthStencilFormat(pRendInfo) != VK_FORMAT_UNDEFINED;
// Get the tessellation shaders, if present. Do this now, because we need to extract
// reflection data from them that informs everything else.
@ -488,8 +487,9 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device,
initCustomSamplePositions(pCreateInfo);
// Depth stencil content - clearing will disable depth and stencil testing
// Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth attachment
mvkSetOrClear(&_depthStencilInfo, _isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr);
// Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth or stencil attachment format
bool isRasterizingDepthStencil = _isRasterizing && (pRendInfo->depthAttachmentFormat || pRendInfo->stencilAttachmentFormat);
mvkSetOrClear(&_depthStencilInfo, isRasterizingDepthStencil ? pCreateInfo->pDepthStencilState : nullptr);
// Viewports and scissors - must ignore allowed bad pViewportState pointer if rasterization is disabled
auto pVPState = _isRasterizing ? pCreateInfo->pViewportState : nullptr;
@ -1469,16 +1469,19 @@ void MVKGraphicsPipeline::addFragmentOutputToPipeline(MTLRenderPipelineDescripto
}
}
// Depth & stencil attachments
// Depth & stencil attachment formats
MVKPixelFormats* pixFmts = getPixelFormats();
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo));
if (pixFmts->isDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; }
if (pixFmts->isStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; }
// In Vulkan, it's perfectly valid to render with no attachments. In Metal we need to check for
// support for it. If we have no attachments, then we may have to add a dummy attachment.
if (!caCnt && !pixFmts->isDepthFormat(mtlDSFormat) && !pixFmts->isStencilFormat(mtlDSFormat) &&
!getDevice()->_pMetalFeatures->renderWithoutAttachments) {
MTLPixelFormat mtlDepthPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat);
if (pixFmts->isDepthFormat(mtlDepthPixFmt)) { plDesc.depthAttachmentPixelFormat = mtlDepthPixFmt; }
MTLPixelFormat mtlStencilPixFmt = pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat);
if (pixFmts->isStencilFormat(mtlStencilPixFmt)) { plDesc.stencilAttachmentPixelFormat = mtlStencilPixFmt; }
// In Vulkan, it's perfectly valid to render without any attachments. In Metal, if that
// isn't supported, and we have no attachments, then we have to add a dummy attachment.
if (!getDevice()->_pMetalFeatures->renderWithoutAttachments &&
!caCnt && !pRendInfo->depthAttachmentFormat && !pRendInfo->stencilAttachmentFormat) {
MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[0];
colorDesc.pixelFormat = MTLPixelFormatR8Unorm;
@ -1554,7 +1557,6 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu
const VkPipelineRenderingCreateInfo* pRendInfo = getRenderingCreateInfo(pCreateInfo);
MVKPixelFormats* pixFmts = getPixelFormats();
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(mvkGetDepthStencilFormat(pRendInfo));
// Disable any unused color attachments, because Metal validation can complain if the
// fragment shader outputs a color value without a corresponding color attachment.
@ -1574,8 +1576,8 @@ void MVKGraphicsPipeline::initShaderConversionConfig(SPIRVToMSLConversionConfigu
shaderConfig.options.mslOptions.ios_support_base_vertex_instance = getDevice()->_pMetalFeatures->baseVertexInstanceDrawing;
shaderConfig.options.mslOptions.texture_1D_as_2D = mvkConfig().texture1DAs2D;
shaderConfig.options.mslOptions.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode;
shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(mtlDSFormat);
shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(mtlDSFormat);
shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat));
shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat));
shaderConfig.options.shouldFlipVertexY = mvkConfig().shaderConversionFlipVertexY;
shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle;
shaderConfig.options.mslOptions.tess_domain_origin_lower_left = pTessDomainOriginState && pTessDomainOriginState->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;

View File

@ -54,9 +54,6 @@ public:
/** Returns whether this subpass has any color attachments. */
bool hasColorAttachments();
/** Returns whether this subpass has a depth/stencil attachment. */
bool hasDepthStencilAttachment() { return _depthStencilAttachment.attachment != VK_ATTACHMENT_UNUSED; }
/** Returns the number of color attachments, which may be zero for depth-only rendering. */
uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); }
@ -69,8 +66,17 @@ public:
/** Returns whether or not the color attachment is used as both a color attachment and an input attachment. */
bool isColorAttachmentAlsoInputAttachment(uint32_t colorAttIdx);
/** Returns the format of the depth/stencil attachment. */
VkFormat getDepthStencilFormat();
/** Returns whether or not the depth attachment is being used. */
bool isDepthAttachmentUsed() { return _depthAttachment.attachment != VK_ATTACHMENT_UNUSED; }
/** Returns whether or not the stencil attachment is being used. */
bool isStencilAttachmentUsed() { return _stencilAttachment.attachment != VK_ATTACHMENT_UNUSED; }
/** Return the depth attachment format. */
VkFormat getDepthFormat();
/** Return the stencil attachment format. */
VkFormat getStencilFormat();
/** Returns the Vulkan sample count of the attachments used in this subpass. */
VkSampleCountFlagBits getSampleCount();
@ -146,10 +152,11 @@ public:
MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo);
private:
MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo);
protected:
friend class MVKRenderPass;
friend class MVKRenderPassAttachment;
friend class MVKAttachmentDescription;
uint32_t getViewMaskGroupForMetalPass(uint32_t passIdx);
MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx);
@ -162,8 +169,10 @@ private:
MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
MVKSmallVector<VkFormat, kMVKDefaultAttachmentCount> _colorAttachmentFormats;
VkPipelineRenderingCreateInfo _pipelineRenderingCreateInfo;
VkAttachmentReference2 _depthStencilAttachment;
VkAttachmentReference2 _depthStencilResolveAttachment;
VkAttachmentReference2 _depthAttachment;
VkAttachmentReference2 _stencilAttachment;
VkAttachmentReference2 _depthResolveAttachment;
VkAttachmentReference2 _stencilResolveAttachment;
VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE;
VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE;
VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT;
@ -172,10 +181,10 @@ private:
#pragma mark -
#pragma mark MVKRenderPassAttachment
#pragma mark MVKAttachmentDescription
/** Represents an attachment within a Vulkan render pass. */
class MVKRenderPassAttachment : public MVKBaseObject {
class MVKAttachmentDescription : public MVKBaseObject {
public:
@ -218,13 +227,20 @@ public:
/** Returns whether this attachment should be cleared in the subpass. */
bool shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil);
MVKRenderPassAttachment(MVKRenderPass* renderPass,
MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkAttachmentDescription* pCreateInfo);
MVKRenderPassAttachment(MVKRenderPass* renderPass,
MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkAttachmentDescription2* pCreateInfo);
MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkRenderingAttachmentInfo* pAttInfo,
bool isResolveAttachment);
protected:
friend class MVKRenderPass;
friend class MVKRenderSubpass;
bool isFirstUseOfAttachment(MVKRenderSubpass* subpass);
bool isLastUseOfAttachment(MVKRenderSubpass* subpass);
MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass,
@ -234,7 +250,7 @@ protected:
bool canResolveFormat,
bool isStencil,
bool storeOverride);
void validateFormat();
void linkToSubpasses();
VkAttachmentDescription2 _info;
MVKRenderPass* _renderPass;
@ -282,13 +298,15 @@ public:
MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo);
MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo);
protected:
friend class MVKRenderSubpass;
friend class MVKRenderPassAttachment;
friend class MVKAttachmentDescription;
void propagateDebugName() override {}
MVKSmallVector<MVKRenderPassAttachment> _attachments;
MVKSmallVector<MVKAttachmentDescription> _attachments;
MVKSmallVector<MVKRenderSubpass> _subpasses;
MVKSmallVector<VkSubpassDependency2> _subpassDependencies;
VkRenderingFlags _renderingFlags = 0;
@ -297,21 +315,47 @@ protected:
#pragma mark -
#pragma mark Support functions
#pragma mark MVKRenderingAttachmentIterator
/** Returns a MVKRenderPass object created from the rendering info. */
MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo);
typedef std::function<void(const VkRenderingAttachmentInfo* pAttInfo,
VkImageAspectFlagBits aspect,
bool isResolveAttachment)> MVKRenderingAttachmentInfoOperation;
/**
* Extracts the usable attachments and their clear values from the rendering info,
* and sets them in the corresponding arrays, which must be large enough to hold
* all of the extracted values, and returns the number of attachments extracted.
* For consistency, the clear value of any resolve attachments are populated,
* even though they are ignored.
* Iterates the attachments in a VkRenderingInfo, and processes an operation
* on each attachment, once for the imageView, and once for the resolveImageView.
*
* Attachments are sequentially processed in this order:
* [color, color-resolve], ...,
* depth, depth-resolve,
* stencil, stencil-resolve
* skipping any attachments that do not have a VkImageView
*/
uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo,
MVKImageView* attachments[],
VkClearValue clearValues[]);
class MVKRenderingAttachmentIterator : public MVKBaseObject {
public:
MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; }
/** Iterates the attachments with the specified lambda function. */
void iterate(MVKRenderingAttachmentInfoOperation attOperation);
MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo);
protected:
void handleAttachment(const VkRenderingAttachmentInfo* pAttInfo,
VkImageAspectFlagBits aspect,
MVKRenderingAttachmentInfoOperation attOperation);
const VkRenderingAttachmentInfo* getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt,
const VkRenderingAttachmentInfo* pAltAtt,
bool isStencil);
VkRenderingInfo _renderingInfo;
};
#pragma mark -
#pragma mark Support functions
/** Returns whether the view mask uses multiview. */
static constexpr bool mvkIsMultiview(uint32_t viewMask) { return viewMask != 0; }
@ -322,9 +366,6 @@ bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, ui
/** Returns whether any attachment is being used. */
bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo);
/** Extracts and returns the combined depth/stencil format . */
VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo);
/**
* Extracts the first view, number of views, and the portion of the mask
* to be rendered from the lowest clump of set bits in a view mask.

View File

@ -53,9 +53,7 @@ VkFormat MVKRenderSubpass::getColorAttachmentFormat(uint32_t colorAttIdx) {
}
bool MVKRenderSubpass::isColorAttachmentUsed(uint32_t colorAttIdx) {
if (colorAttIdx >= _colorAttachments.size()) {
return false;
}
if (colorAttIdx >= _colorAttachments.size()) { return false; }
return _colorAttachments[colorAttIdx].attachment != VK_ATTACHMENT_UNUSED;
}
@ -72,10 +70,12 @@ bool MVKRenderSubpass::isColorAttachmentAlsoInputAttachment(uint32_t colorAttIdx
return false;
}
VkFormat MVKRenderSubpass::getDepthStencilFormat() {
uint32_t rpAttIdx = _depthStencilAttachment.attachment;
if (rpAttIdx == VK_ATTACHMENT_UNUSED) { return VK_FORMAT_UNDEFINED; }
return _renderPass->_attachments[rpAttIdx].getFormat();
VkFormat MVKRenderSubpass::getDepthFormat() {
return isDepthAttachmentUsed() ? _renderPass->_attachments[_depthAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED;
}
VkFormat MVKRenderSubpass::getStencilFormat() {
return isStencilAttachmentUsed() ? _renderPass->_attachments[_stencilAttachment.attachment].getFormat() : VK_FORMAT_UNDEFINED;
}
VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() {
@ -85,11 +85,12 @@ VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() {
return _renderPass->_attachments[rpAttIdx].getSampleCount();
}
}
uint32_t rpAttIdx = _depthStencilAttachment.attachment;
if (rpAttIdx != VK_ATTACHMENT_UNUSED) {
return _renderPass->_attachments[rpAttIdx].getSampleCount();
if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) {
return _renderPass->_attachments[_depthAttachment.attachment].getSampleCount();
}
if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) {
return _renderPass->_attachments[_stencilAttachment.attachment].getSampleCount();
}
return VK_SAMPLE_COUNT_1_BIT;
}
@ -176,7 +177,7 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
}
// Configure the color attachment
MVKRenderPassAttachment* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx];
MVKAttachmentDescription* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx];
if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this, attachments[clrRPAttIdx],
isRenderingEntireAttachment,
hasResolveAttachment, canResolveFormat,
@ -193,44 +194,54 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
}
}
// Populate the Metal depth and stencil attachments
uint32_t dsRPAttIdx = _depthStencilAttachment.attachment;
uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx];
MVKImageView* dsImage = attachments[dsRPAttIdx];
MVKImageView* dsRslvImage = nullptr;
MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0);
// Populate the Metal depth attachment
uint32_t depthRPAttIdx = _depthAttachment.attachment;
if (depthRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKAttachmentDescription* depthMVKRPAtt = &_renderPass->_attachments[depthRPAttIdx];
MVKImageView* depthImage = attachments[depthRPAttIdx];
if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
dsRslvImage = attachments[dsRslvRPAttIdx];
MVKImageView* depthRslvImage = nullptr;
uint32_t depthRslvRPAttIdx = _depthResolveAttachment.attachment;
if (depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
depthRslvImage = attachments[depthRslvRPAttIdx];
}
if (pixFmts->isDepthFormat(mtlDSFormat)) {
MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment;
bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE);
if (hasResolveAttachment) {
dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc);
bool hasDepthResolve = depthRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE;
if (hasDepthResolve) {
depthRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc);
mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode);
if (isMultiview()) {
mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx);
}
}
if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, dsImage,
if (depthMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, depthImage,
isRenderingEntireAttachment,
hasResolveAttachment, true,
hasDepthResolve, true,
false, loadOverride)) {
mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]);
mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[depthRPAttIdx]);
}
if (isMultiview()) {
mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
}
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
// Populate the Metal stencil attachment
uint32_t stencilRPAttIdx = _stencilAttachment.attachment;
if (stencilRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKAttachmentDescription* stencilMVKRPAtt = &_renderPass->_attachments[stencilRPAttIdx];
MVKImageView* stencilImage = attachments[stencilRPAttIdx];
MVKImageView* stencilRslvImage = nullptr;
uint32_t stencilRslvRPAttIdx = _stencilResolveAttachment.attachment;
if (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
stencilRslvImage = attachments[stencilRslvRPAttIdx];
}
MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment;
bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE);
if (hasResolveAttachment) {
dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc);
bool hasStencilResolve = (stencilRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE);
if (hasStencilResolve) {
stencilRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc);
#if MVK_MACOS_OR_IOS
mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode);
#endif
@ -238,21 +249,20 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx);
}
}
if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, dsImage,
if (stencilMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, stencilImage,
isRenderingEntireAttachment,
hasResolveAttachment, true,
hasStencilResolve, true,
true, loadOverride)) {
mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]);
mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[stencilRPAttIdx]);
}
if (isMultiview()) {
mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
}
}
}
// Vulkan supports rendering without attachments, but older Metal does not.
// If Metal does not support rendering without attachments, create a dummy attachment to pass Metal validation.
if (caUsedCnt == 0 && dsRPAttIdx == VK_ATTACHMENT_UNUSED) {
if (caUsedCnt == 0 && depthRPAttIdx == VK_ATTACHMENT_UNUSED && stencilRPAttIdx == VK_ATTACHMENT_UNUSED) {
if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) {
mtlRPDesc.defaultRasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount);
} else {
@ -285,42 +295,42 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
_renderPass->_attachments[clrRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[clrRPAttIdx], isRenderingEntireAttachment, hasResolveAttachment, canResolveFormat, caIdx, false, storeOverride);
}
}
uint32_t dsRPAttIdx = _depthStencilAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
bool hasResolveAttachment = _depthStencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED;
bool hasDepthResolveAttachment = hasResolveAttachment && _depthResolveMode != VK_RESOLVE_MODE_NONE;
bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE;
bool canResolveFormat = true;
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasDepthResolveAttachment, canResolveFormat, 0, false, storeOverride);
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, attachments[dsRPAttIdx], isRenderingEntireAttachment, hasStencilResolveAttachment, canResolveFormat, 0, true, storeOverride);
if (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[_depthAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_depthAttachment.attachment], isRenderingEntireAttachment,
(_depthResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE),
true, 0, false, storeOverride);
}
if (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[_stencilAttachment.attachment].encodeStoreAction(cmdEncoder, this, attachments[_stencilAttachment.attachment], isRenderingEntireAttachment,
(_stencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE),
true, 0, true, storeOverride);
}
}
void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
const MVKArrayRef<VkClearValue> clearValues) {
uint32_t attIdx;
uint32_t caCnt = getColorAttachmentCount();
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
attIdx = _colorAttachments[caIdx].attachment;
uint32_t attIdx = _colorAttachments[caIdx].attachment;
if ((attIdx != VK_ATTACHMENT_UNUSED) && _renderPass->_attachments[attIdx].shouldClearAttachment(this, false)) {
clearAtts.push_back( { VK_IMAGE_ASPECT_COLOR_BIT, caIdx, clearValues[attIdx] } );
}
}
attIdx = _depthStencilAttachment.attachment;
if (attIdx != VK_ATTACHMENT_UNUSED) {
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
MTLPixelFormat mtlDSFmt = pixFmts->getMTLPixelFormat(getDepthStencilFormat());
auto& rpAtt = _renderPass->_attachments[attIdx];
VkImageAspectFlags aspectMask = 0;
if (rpAtt.shouldClearAttachment(this, false) && pixFmts->isDepthFormat(mtlDSFmt)) {
mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
// If depth and stencil both need clearing and are the same attachment, just clear once, otherwise, clear them separately.
bool shouldClearDepth = (_depthAttachment.attachment != VK_ATTACHMENT_UNUSED &&
_renderPass->_attachments[_depthAttachment.attachment].shouldClearAttachment(this, false));
bool shouldClearStencil = (_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED &&
_renderPass->_attachments[_stencilAttachment.attachment].shouldClearAttachment(this, true));
if (shouldClearDepth && shouldClearStencil && _depthAttachment.attachment == _stencilAttachment.attachment) {
clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_depthAttachment.attachment] } );
} else {
if (shouldClearDepth) {
clearAtts.push_back( { VK_IMAGE_ASPECT_DEPTH_BIT, 0, clearValues[_depthAttachment.attachment] } );
}
if (rpAtt.shouldClearAttachment(this, true) && pixFmts->isStencilFormat(mtlDSFmt)) {
mvkEnableFlags(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
}
if (aspectMask) {
clearAtts.push_back( { aspectMask, 0, clearValues[attIdx] } );
if (shouldClearStencil) {
clearAtts.push_back( { VK_IMAGE_ASPECT_STENCIL_BIT, 0, clearValues[_stencilAttachment.attachment] } );
}
}
}
@ -328,18 +338,24 @@ void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
void MVKRenderSubpass::populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects,
MVKCommandEncoder* cmdEncoder,
uint32_t caIdx, VkImageAspectFlags aspectMask) {
uint32_t attIdx;
assert(this == cmdEncoder->getSubpass());
if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
attIdx = _depthStencilAttachment.attachment;
if (attIdx != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder);
if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)) {
uint32_t clrAttIdx = _colorAttachments[caIdx].attachment;
if (clrAttIdx != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[clrAttIdx].populateMultiviewClearRects(clearRects, cmdEncoder);
}
return;
}
attIdx = _colorAttachments[caIdx].attachment;
if (attIdx != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder);
// If depth and stencil are the same attachment, only clear once.
if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) &&
_depthAttachment.attachment != VK_ATTACHMENT_UNUSED) {
_renderPass->_attachments[_depthAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder);
}
if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT) &&
_stencilAttachment.attachment != VK_ATTACHMENT_UNUSED &&
_stencilAttachment.attachment != _depthAttachment.attachment) {
_renderPass->_attachments[_stencilAttachment.attachment].populateMultiviewClearRects(clearRects, cmdEncoder);
}
}
@ -368,8 +384,12 @@ MVKMTLFmtCaps MVKRenderSubpass::getRequiredFormatCapabilitiesForAttachmentAt(uin
break;
}
}
if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); }
if (_depthStencilResolveAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); }
if (_depthAttachment.attachment == rpAttIdx || _stencilAttachment.attachment == rpAttIdx) {
mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt);
}
if (_depthResolveAttachment.attachment == rpAttIdx || _stencilResolveAttachment.attachment == rpAttIdx) {
mvkEnableFlags(caps, kMVKMTLFmtCapsResolve);
}
return caps;
}
@ -405,9 +425,7 @@ void MVKRenderSubpass::resolveUnresolvableAttachments(MVKCommandEncoder* cmdEnco
}
}
// Must be called after renderpass has both subpasses and attachments bound
void MVKRenderSubpass::populatePipelineRenderingCreateInfo() {
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
_pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
_pipelineRenderingCreateInfo.pNext = nullptr;
@ -415,69 +433,15 @@ void MVKRenderSubpass::populatePipelineRenderingCreateInfo() {
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
_colorAttachmentFormats.push_back(getColorAttachmentFormat(caIdx));
}
_pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data();
_pipelineRenderingCreateInfo.colorAttachmentCount = caCnt;
VkFormat dsFmt = getDepthStencilFormat();
MTLPixelFormat dsMTLFmt = pixFmts->getMTLPixelFormat(dsFmt);
_pipelineRenderingCreateInfo.depthAttachmentFormat = pixFmts->isDepthFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED;
_pipelineRenderingCreateInfo.stencilAttachmentFormat = pixFmts->isStencilFormat(dsMTLFmt) ? dsFmt : VK_FORMAT_UNDEFINED;
_pipelineRenderingCreateInfo.pColorAttachmentFormats = _colorAttachmentFormats.data();
_pipelineRenderingCreateInfo.depthAttachmentFormat = getDepthFormat();
_pipelineRenderingCreateInfo.stencilAttachmentFormat = getStencilFormat();
}
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
const VkSubpassDescription* pCreateInfo,
const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects,
uint32_t viewMask) {
_renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size();
_pipelineRenderingCreateInfo.viewMask = viewMask;
static const VkAttachmentReference2 _unusedAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED, 0};
// Add attachments
_inputAttachments.reserve(pCreateInfo->inputAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i];
_inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
}
if (pInputAspects && pInputAspects->aspectReferenceCount) {
for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) {
const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i];
if (aspectRef.subpass == _subpassIndex) {
_inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask;
}
}
}
_colorAttachments.reserve(pCreateInfo->colorAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i];
_colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
}
if (pCreateInfo->pResolveAttachments) {
_resolveAttachments.reserve(pCreateInfo->colorAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i];
_resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
}
}
if (pCreateInfo->pDepthStencilAttachment) {
_depthStencilAttachment.attachment = pCreateInfo->pDepthStencilAttachment->attachment;
_depthStencilAttachment.layout = pCreateInfo->pDepthStencilAttachment->layout;
} else {
_depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED;
}
_depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED;
_preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
_preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
}
}
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
const VkSubpassDescription2* pCreateInfo) {
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo) {
VkSubpassDescriptionDepthStencilResolve* pDSResolveInfo = nullptr;
for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
@ -512,37 +476,170 @@ MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
}
}
if (pCreateInfo->pDepthStencilAttachment) {
_depthStencilAttachment = *pCreateInfo->pDepthStencilAttachment;
} else {
_depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED;
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
_depthAttachment = _unusedAttachment;
_stencilAttachment = _unusedAttachment;
const auto* pDSAtt = pCreateInfo->pDepthStencilAttachment;
if (pDSAtt && pDSAtt->attachment != VK_ATTACHMENT_UNUSED) {
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSAtt->attachment].getFormat());
if (pixFmts->isDepthFormat(mtlDSFormat)) {
_depthAttachment = *pCreateInfo->pDepthStencilAttachment;
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
_stencilAttachment = *pCreateInfo->pDepthStencilAttachment;
}
}
if (pDSResolveInfo && pDSResolveInfo->pDepthStencilResolveAttachment) {
_depthStencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment;
_depthResolveAttachment = _unusedAttachment;
_stencilResolveAttachment = _unusedAttachment;
const auto* pDSRslvAtt = pDSResolveInfo ? pDSResolveInfo->pDepthStencilResolveAttachment : nullptr;
if (pDSRslvAtt && pDSRslvAtt->attachment != VK_ATTACHMENT_UNUSED) {
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[pDSRslvAtt->attachment].getFormat());
if (pixFmts->isDepthFormat(mtlDSFormat)) {
_depthResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment;
_depthResolveMode = pDSResolveInfo->depthResolveMode;
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
_stencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment;
_stencilResolveMode = pDSResolveInfo->stencilResolveMode;
} else {
_depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED;
}
}
_preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
_preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
}
populatePipelineRenderingCreateInfo();
}
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
const VkSubpassDescription* pCreateInfo,
const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects,
uint32_t viewMask) {
_renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size();
_pipelineRenderingCreateInfo.viewMask = viewMask;
// Add attachments
_inputAttachments.reserve(pCreateInfo->inputAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i];
_inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT});
}
if (pInputAspects && pInputAspects->aspectReferenceCount) {
for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) {
const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i];
if (aspectRef.subpass == _subpassIndex) {
_inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask;
}
}
}
_colorAttachments.reserve(pCreateInfo->colorAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i];
_colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT});
}
if (pCreateInfo->pResolveAttachments) {
_resolveAttachments.reserve(pCreateInfo->colorAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i];
_resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, VK_IMAGE_ASPECT_COLOR_BIT});
}
}
_depthAttachment = _unusedAttachment;
_stencilAttachment = _unusedAttachment;
if (pCreateInfo->pDepthStencilAttachment) {
auto* dsAtt = pCreateInfo->pDepthStencilAttachment;
uint32_t dsAttIdx = dsAtt->attachment;
if (dsAttIdx != VK_ATTACHMENT_UNUSED) {
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
MTLPixelFormat mtlDSFormat = pixFmts->getMTLPixelFormat(_renderPass->_attachments[dsAttIdx].getFormat());
if (pixFmts->isDepthFormat(mtlDSFormat)) {
_depthAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_DEPTH_BIT};
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
_stencilAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, dsAtt->attachment, dsAtt->layout, VK_IMAGE_ASPECT_STENCIL_BIT};
}
}
}
_depthResolveAttachment = _unusedAttachment;
_stencilResolveAttachment = _unusedAttachment;
_preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
_preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
}
populatePipelineRenderingCreateInfo();
}
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, const VkRenderingInfo* pRenderingInfo) {
_renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size();
_pipelineRenderingCreateInfo.viewMask = pRenderingInfo->viewMask;
_depthAttachment = _unusedAttachment;
_depthResolveAttachment = _unusedAttachment;
_stencilAttachment = _unusedAttachment;
_stencilResolveAttachment = _unusedAttachment;
uint32_t attIdx = 0;
MVKRenderingAttachmentIterator attIter(pRenderingInfo);
attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void {
VkAttachmentReference2 attRef = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, attIdx++, pAttInfo->imageLayout, aspect};
switch (aspect) {
case VK_IMAGE_ASPECT_COLOR_BIT:
if (isResolveAttachment) {
_resolveAttachments.push_back(attRef);
} else {
_colorAttachments.push_back(attRef);
}
break;
case VK_IMAGE_ASPECT_DEPTH_BIT:
if (isResolveAttachment) {
_depthResolveAttachment = attRef;
_depthResolveMode = pAttInfo->resolveMode;
} else {
_depthAttachment = attRef;
}
break;
case VK_IMAGE_ASPECT_STENCIL_BIT:
if (isResolveAttachment) {
_stencilResolveAttachment = attRef;
_stencilResolveMode = pAttInfo->resolveMode;
} else {
_stencilAttachment = attRef;
}
break;
default:
break;
}
});
populatePipelineRenderingCreateInfo();
}
#pragma mark -
#pragma mark MVKRenderPassAttachment
#pragma mark MVKAttachmentDescription
MVKVulkanAPIObject* MVKRenderPassAttachment::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); };
MVKVulkanAPIObject* MVKAttachmentDescription::getVulkanAPIObject() { return _renderPass->getVulkanAPIObject(); };
VkFormat MVKRenderPassAttachment::getFormat() { return _info.format; }
VkFormat MVKAttachmentDescription::getFormat() { return _info.format; }
VkSampleCountFlagBits MVKRenderPassAttachment::getSampleCount() { return _info.samples; }
VkSampleCountFlagBits MVKAttachmentDescription::getSampleCount() { return _info.samples; }
bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc,
bool MVKAttachmentDescription::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc,
MVKRenderSubpass* subpass,
MVKImageView* attachment,
bool isRenderingEntireAttachment,
@ -597,7 +694,7 @@ bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRende
return (mtlLA == MTLLoadActionClear);
}
void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder,
void MVKAttachmentDescription::encodeStoreAction(MVKCommandEncoder* cmdEncoder,
MVKRenderSubpass* subpass,
MVKImageView* attachment,
bool isRenderingEntireAttachment,
@ -630,7 +727,7 @@ void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder,
}
}
void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder) {
void MVKAttachmentDescription::populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder) {
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
uint32_t clearMask = subpass->getViewMaskGroupForMetalPass(cmdEncoder->getMultiviewPassIndex()) & _firstUseViewMasks[subpass->_subpassIndex];
@ -643,7 +740,7 @@ void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVector<VkClear
} while (clearMask);
}
bool MVKRenderPassAttachment::isFirstUseOfAttachment(MVKRenderSubpass* subpass) {
bool MVKAttachmentDescription::isFirstUseOfAttachment(MVKRenderSubpass* subpass) {
if ( subpass->isMultiview() ) {
return _firstUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask;
} else {
@ -651,7 +748,7 @@ bool MVKRenderPassAttachment::isFirstUseOfAttachment(MVKRenderSubpass* subpass)
}
}
bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) {
bool MVKAttachmentDescription::isLastUseOfAttachment(MVKRenderSubpass* subpass) {
if ( subpass->isMultiview() ) {
return _lastUseViewMasks[subpass->_subpassIndex] == subpass->_pipelineRenderingCreateInfo.viewMask;
} else {
@ -659,7 +756,7 @@ bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) {
}
}
MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subpass,
MTLStoreAction MVKAttachmentDescription::getMTLStoreAction(MVKRenderSubpass* subpass,
bool isRenderingEntireAttachment,
bool isMemorylessAttachment,
bool hasResolveAttachment,
@ -690,7 +787,7 @@ MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subp
return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment, canResolveFormat);
}
bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) {
bool MVKAttachmentDescription::shouldClearAttachment(MVKRenderSubpass* subpass, bool isStencil) {
// If the renderpass is being resumed after being suspended, don't clear this attachment.
if (mvkIsAnyFlagEnabled(_renderPass->getRenderingFlags(), VK_RENDERING_RESUMING_BIT_KHR)) { return false; }
@ -705,7 +802,8 @@ bool MVKRenderPassAttachment::shouldClearAttachment(MVKRenderSubpass* subpass, b
return loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR;
}
void MVKRenderPassAttachment::validateFormat() {
// Must be called after renderpass has both subpasses and attachments bound
void MVKAttachmentDescription::linkToSubpasses() {
// Validate pixel format is supported
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) {
@ -715,7 +813,7 @@ void MVKRenderPassAttachment::validateFormat() {
// Determine the indices of the first and last render subpasses to use this attachment.
_firstUseSubpassIdx = kMVKUndefinedLargeUInt32;
_lastUseSubpassIdx = 0;
if ( _renderPass->isMultiview() ) {
if (_renderPass->_subpasses[0].isMultiview()) {
_firstUseViewMasks.reserve(_renderPass->_subpasses.size());
_lastUseViewMasks.reserve(_renderPass->_subpasses.size());
}
@ -746,7 +844,7 @@ void MVKRenderPassAttachment::validateFormat() {
}
}
MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkAttachmentDescription* pCreateInfo) {
_info.flags = pCreateInfo->flags;
_info.format = pCreateInfo->format;
@ -759,17 +857,41 @@ MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
_info.finalLayout = pCreateInfo->finalLayout;
_renderPass = renderPass;
_attachmentIndex = uint32_t(_renderPass->_attachments.size());
validateFormat();
}
MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkAttachmentDescription2* pCreateInfo) {
_info = *pCreateInfo;
_renderPass = renderPass;
_attachmentIndex = uint32_t(_renderPass->_attachments.size());
}
validateFormat();
MVKAttachmentDescription::MVKAttachmentDescription(MVKRenderPass* renderPass,
const VkRenderingAttachmentInfo* pAttInfo,
bool isResolveAttachment) {
if (isResolveAttachment) {
_info.flags = 0;
_info.format = ((MVKImageView*)pAttInfo->resolveImageView)->getVkFormat();
_info.samples = VK_SAMPLE_COUNT_1_BIT;
_info.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
_info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
_info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
_info.initialLayout = pAttInfo->resolveImageLayout;
_info.finalLayout = pAttInfo->resolveImageLayout;
} else {
_info.flags = 0;
_info.format = ((MVKImageView*)pAttInfo->imageView)->getVkFormat();
_info.samples = ((MVKImageView*)pAttInfo->imageView)->getSampleCount();
_info.loadOp = pAttInfo->loadOp;
_info.storeOp = pAttInfo->storeOp;
_info.stencilLoadOp = pAttInfo->loadOp;
_info.stencilStoreOp = pAttInfo->storeOp;
_info.initialLayout = pAttInfo->imageLayout;
_info.finalLayout = pAttInfo->imageLayout;
}
_renderPass = renderPass;
_attachmentIndex = uint32_t(_renderPass->_attachments.size());
}
@ -786,8 +908,6 @@ VkExtent2D MVKRenderPass::getRenderAreaGranularity() {
return { 1, 1 };
}
bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); }
MVKRenderPass::MVKRenderPass(MVKDevice* device,
const VkRenderPassCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
@ -815,7 +935,13 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device,
viewOffsets = pMultiviewCreateInfo->pViewOffsets;
}
// Add subpasses and dependencies first
// Add attachments first so subpasses can access them during creation
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
_attachments.emplace_back(this, &pCreateInfo->pAttachments[i]);
}
// Add subpasses and dependencies
_subpasses.reserve(pCreateInfo->subpassCount);
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
_subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i], pInputAspectCreateInfo, viewMasks ? viewMasks[i] : 0);
@ -837,23 +963,22 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device,
_subpassDependencies.push_back(dependency);
}
// Add attachments after subpasses, so each attachment can link to subpasses
// Link attachments to subpasses
for (auto& att : _attachments) {
att.linkToSubpasses();
}
}
MVKRenderPass::MVKRenderPass(MVKDevice* device,
const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
// Add attachments first so subpasses can access them during creation
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
_attachments.emplace_back(this, &pCreateInfo->pAttachments[i]);
}
// Populate additional subpass info after attachments added.
for (auto& mvkSP : _subpasses) {
mvkSP.populatePipelineRenderingCreateInfo();
}
}
MVKRenderPass::MVKRenderPass(MVKDevice* device,
const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
// Add subpasses and dependencies first
// Add subpasses and dependencies
_subpasses.reserve(pCreateInfo->subpassCount);
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
_subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i]);
@ -863,214 +988,85 @@ MVKRenderPass::MVKRenderPass(MVKDevice* device,
_subpassDependencies.push_back(pCreateInfo->pDependencies[i]);
}
// Add attachments after subpasses, so each attachment can link to subpasses
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
_attachments.emplace_back(this, &pCreateInfo->pAttachments[i]);
// Link attachments to subpasses
for (auto& att : _attachments) {
att.linkToSubpasses();
}
}
// Populate additional subpass info after attachments added.
for (auto& mvkSP : _subpasses) {
mvkSP.populatePipelineRenderingCreateInfo();
MVKRenderPass::MVKRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) : MVKVulkanAPIDeviceObject(device) {
_renderingFlags = pRenderingInfo->flags;
// Add attachments first so subpasses can access them during creation
uint32_t attCnt = 0;
MVKRenderingAttachmentIterator attIter(pRenderingInfo);
attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void { attCnt++; });
_attachments.reserve(attCnt);
attIter.iterate([&](const VkRenderingAttachmentInfo* pAttInfo, VkImageAspectFlagBits aspect, bool isResolveAttachment)->void {
_attachments.emplace_back(this, pAttInfo, isResolveAttachment);
});
// Add subpass
_subpasses.emplace_back(this, pRenderingInfo);
// Link attachments to subpasses
for (auto& att : _attachments) {
att.linkToSubpasses();
}
}
#pragma mark -
#pragma mark Support functions
#pragma mark MVKRenderingAttachmentIterator
// Adds the rendering attachment info to the array of attachment descriptors at the index,
// and increments the index, for both the base view and the resolve view, if it is present.
static void mvkAddAttachmentDescriptor(const VkRenderingAttachmentInfo* pAttInfo,
const VkRenderingAttachmentInfo* pStencilAttInfo,
VkAttachmentDescription2 attachmentDescriptors[],
uint32_t& attDescIdx) {
VkAttachmentDescription2 attDesc;
attDesc.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
attDesc.pNext = nullptr;
attDesc.flags = 0;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// Handle stencil-only possibility.
if ( !pAttInfo ) { pAttInfo = pStencilAttInfo; }
void MVKRenderingAttachmentIterator::iterate(MVKRenderingAttachmentInfoOperation attOperation) {
for (uint32_t caIdx = 0; caIdx < _renderingInfo.colorAttachmentCount; caIdx++) {
handleAttachment(&_renderingInfo.pColorAttachments[caIdx], VK_IMAGE_ASPECT_COLOR_BIT, attOperation);
}
handleAttachment(_renderingInfo.pDepthAttachment, VK_IMAGE_ASPECT_DEPTH_BIT, attOperation);
handleAttachment(_renderingInfo.pStencilAttachment, VK_IMAGE_ASPECT_STENCIL_BIT, attOperation);
}
void MVKRenderingAttachmentIterator::handleAttachment(const VkRenderingAttachmentInfo* pAttInfo,
VkImageAspectFlagBits aspect,
MVKRenderingAttachmentInfoOperation attOperation) {
if (pAttInfo && pAttInfo->imageView) {
MVKImageView* mvkImgView = (MVKImageView*)pAttInfo->imageView;
attDesc.format = mvkImgView->getVkFormat();
attDesc.samples = mvkImgView->getSampleCount();
attDesc.loadOp = pAttInfo->loadOp;
attDesc.storeOp = pAttInfo->storeOp;
attDesc.stencilLoadOp = pStencilAttInfo ? pStencilAttInfo->loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = pStencilAttInfo ? pStencilAttInfo->storeOp : VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = pAttInfo->imageLayout;
attDesc.finalLayout = pAttInfo->imageLayout;
attachmentDescriptors[attDescIdx++] = attDesc;
attOperation(pAttInfo, aspect, false);
if (pAttInfo->resolveImageView && pAttInfo->resolveMode != VK_RESOLVE_MODE_NONE) {
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = pStencilAttInfo ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = pAttInfo->resolveImageLayout;
attDesc.finalLayout = pAttInfo->resolveImageLayout;
attachmentDescriptors[attDescIdx++] = attDesc;
attOperation(pAttInfo, aspect, true);
}
}
}
MVKRenderPass* mvkCreateRenderPass(MVKDevice* device, const VkRenderingInfo* pRenderingInfo) {
// Renderpass attachments are sequentially indexed in this order:
// [color, color-resolve], ..., ds, ds-resolve
// skipping any attachments that do not have a VkImageView
uint32_t maxAttDescCnt = (pRenderingInfo->colorAttachmentCount + 1) * 2;
VkAttachmentDescription2 attachmentDescriptors[maxAttDescCnt];
VkAttachmentReference2 colorAttachmentRefs[pRenderingInfo->colorAttachmentCount];
VkAttachmentReference2 resolveAttachmentRefs[pRenderingInfo->colorAttachmentCount];
VkAttachmentReference2 attRef;
attRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
attRef.pNext = nullptr;
attRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
uint32_t attDescIdx = 0;
uint32_t caRefIdx = 0;
bool hasClrRslvAtt = false;
for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) {
auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx];
if (clrAtt.imageView) {
attRef.layout = clrAtt.imageLayout;
attRef.attachment = attDescIdx;
colorAttachmentRefs[caRefIdx] = attRef;
if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) {
attRef.layout = clrAtt.resolveImageLayout;
attRef.attachment = attDescIdx + 1;
resolveAttachmentRefs[caRefIdx] = attRef;
hasClrRslvAtt = true;
}
caRefIdx++;
}
mvkAddAttachmentDescriptor(&clrAtt, nullptr, attachmentDescriptors, attDescIdx);
MVKRenderingAttachmentIterator::MVKRenderingAttachmentIterator(const VkRenderingInfo* pRenderingInfo) {
_renderingInfo = *pRenderingInfo;
_renderingInfo.pDepthAttachment = getAttachmentInfo(pRenderingInfo->pDepthAttachment, pRenderingInfo->pStencilAttachment, false);
_renderingInfo.pStencilAttachment = getAttachmentInfo(pRenderingInfo->pStencilAttachment, pRenderingInfo->pDepthAttachment, true);
}
// Combine depth and stencil attachments into one depth-stencil attachment.
// If both depth and stencil are present, their views and layouts must match.
VkAttachmentReference2 dsAttRef;
VkAttachmentReference2 dsRslvAttRef;
VkResolveModeFlagBits depthResolveMode = VK_RESOLVE_MODE_NONE;
VkResolveModeFlagBits stencilResolveMode = VK_RESOLVE_MODE_NONE;
attRef.aspectMask = 0;
attRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout rslvLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (pRenderingInfo->pDepthAttachment && pRenderingInfo->pDepthAttachment->imageView) {
attRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
depthResolveMode = pRenderingInfo->pDepthAttachment->resolveMode;
attRef.layout = pRenderingInfo->pDepthAttachment->imageLayout;
rslvLayout = pRenderingInfo->pDepthAttachment->resolveImageLayout;
// If the depth/stencil attachment is not in use, but the alternate stencil/depth attachment is,
// and the MTLPixelFormat is usable by both attachments, force the use of the alternate attachment
// for both attachments, to avoid Metal validation errors when a pipeline expects both depth and
// stencil, but only one of the attachments has been provided here.
// Check the MTLPixelFormat of the MVKImage underlying the MVKImageView, to bypass possible
// substitution of MTLPixelFormat in the MVKImageView due to swizzling, or stencil-only access.
const VkRenderingAttachmentInfo* MVKRenderingAttachmentIterator::getAttachmentInfo(const VkRenderingAttachmentInfo* pAtt,
const VkRenderingAttachmentInfo* pAltAtt,
bool isStencil) {
bool useAlt = false;
if ( !(pAtt && pAtt->imageView) && (pAltAtt && pAltAtt->imageView) ) {
MVKImage* mvkImg = ((MVKImageView*)pAltAtt->imageView)->getImage();
useAlt = (isStencil
? mvkImg->getPixelFormats()->isStencilFormat(mvkImg->getMTLPixelFormat())
: mvkImg->getPixelFormats()->isDepthFormat(mvkImg->getMTLPixelFormat()));
}
if (pRenderingInfo->pStencilAttachment && pRenderingInfo->pStencilAttachment->imageView) {
attRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
stencilResolveMode = pRenderingInfo->pStencilAttachment->resolveMode;
attRef.layout = pRenderingInfo->pStencilAttachment->imageLayout;
rslvLayout = pRenderingInfo->pStencilAttachment->resolveImageLayout;
return useAlt ? pAltAtt : pAtt;
}
attRef.attachment = attRef.aspectMask ? attDescIdx : VK_ATTACHMENT_UNUSED;
dsAttRef = attRef;
attRef.layout = rslvLayout;
attRef.attachment = attDescIdx + 1;
dsRslvAttRef = attRef;
mvkAddAttachmentDescriptor(pRenderingInfo->pDepthAttachment,
pRenderingInfo->pStencilAttachment,
attachmentDescriptors, attDescIdx);
// Depth/stencil resolve handled via VkSubpassDescription2 pNext
VkSubpassDescriptionDepthStencilResolve dsRslv;
dsRslv.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
dsRslv.pNext = nullptr;
dsRslv.depthResolveMode = depthResolveMode;
dsRslv.stencilResolveMode = stencilResolveMode;
dsRslv.pDepthStencilResolveAttachment = &dsRslvAttRef;
bool hasDSRslvAtt = depthResolveMode != VK_RESOLVE_MODE_NONE || stencilResolveMode != VK_RESOLVE_MODE_NONE;
// Define the subpass
VkSubpassDescription2 spDesc;
spDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
spDesc.pNext = hasDSRslvAtt ? &dsRslv : nullptr;
spDesc.flags = 0;
spDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
spDesc.viewMask = pRenderingInfo->viewMask;
spDesc.inputAttachmentCount = 0;
spDesc.pInputAttachments = nullptr;
spDesc.colorAttachmentCount = caRefIdx;
spDesc.pColorAttachments = colorAttachmentRefs;
spDesc.pResolveAttachments = hasClrRslvAtt ? resolveAttachmentRefs : nullptr;;
spDesc.pDepthStencilAttachment = &dsAttRef;
spDesc.preserveAttachmentCount = 0;
spDesc.pPreserveAttachments = nullptr;
// Define the renderpass
VkRenderPassCreateInfo2 rpCreateInfo;
rpCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
rpCreateInfo.pNext = nullptr;
rpCreateInfo.flags = 0;
rpCreateInfo.attachmentCount = attDescIdx;
rpCreateInfo.pAttachments = attachmentDescriptors;
rpCreateInfo.subpassCount = 1;
rpCreateInfo.pSubpasses = &spDesc;
rpCreateInfo.dependencyCount = 0;
rpCreateInfo.pDependencies = nullptr;
rpCreateInfo.correlatedViewMaskCount = 0;
rpCreateInfo.pCorrelatedViewMasks = nullptr;
auto* mvkRP = device->createRenderPass(&rpCreateInfo, nullptr);
mvkRP->setRenderingFlags(pRenderingInfo->flags);
return mvkRP;
}
uint32_t mvkGetAttachments(const VkRenderingInfo* pRenderingInfo,
MVKImageView* attachments[],
VkClearValue clearValues[]) {
// Renderpass attachments are sequentially indexed in this order:
// [color, color-resolve], ..., ds, ds-resolve
// skipping any attachments that do not have a VkImageView
// For consistency, we populate the clear value of any resolve attachments, even though they are ignored.
uint32_t attIdx = 0;
for (uint32_t caIdx = 0; caIdx < pRenderingInfo->colorAttachmentCount; caIdx++) {
auto& clrAtt = pRenderingInfo->pColorAttachments[caIdx];
if (clrAtt.imageView) {
clearValues[attIdx] = clrAtt.clearValue;
attachments[attIdx++] = (MVKImageView*)clrAtt.imageView;
if (clrAtt.resolveImageView && clrAtt.resolveMode != VK_RESOLVE_MODE_NONE) {
clearValues[attIdx] = clrAtt.clearValue;
attachments[attIdx++] = (MVKImageView*)clrAtt.resolveImageView;
}
}
}
// We need to combine the DS attachments into one
auto* pDSAtt = pRenderingInfo->pDepthAttachment ? pRenderingInfo->pDepthAttachment : pRenderingInfo->pStencilAttachment;
if (pDSAtt) {
if (pDSAtt->imageView) {
clearValues[attIdx] = pDSAtt->clearValue;
attachments[attIdx++] = (MVKImageView*)pDSAtt->imageView;
}
if (pDSAtt->resolveImageView && pDSAtt->resolveMode != VK_RESOLVE_MODE_NONE) {
clearValues[attIdx] = pDSAtt->clearValue;
attachments[attIdx++] = (MVKImageView*)pDSAtt->resolveImageView;
}
}
return attIdx;
}
#pragma mark -
#pragma mark Support functions
bool mvkIsColorAttachmentUsed(const VkPipelineRenderingCreateInfo* pRendInfo, uint32_t colorAttIdx) {
return pRendInfo && pRendInfo->pColorAttachmentFormats[colorAttIdx];
@ -1085,14 +1081,6 @@ bool mvkHasColorAttachments(const VkPipelineRenderingCreateInfo* pRendInfo) {
return false;
}
VkFormat mvkGetDepthStencilFormat(const VkPipelineRenderingCreateInfo* pRendInfo) {
return (pRendInfo
? (pRendInfo->depthAttachmentFormat
? pRendInfo->depthAttachmentFormat
: pRendInfo->stencilAttachmentFormat)
: VK_FORMAT_UNDEFINED);
}
uint32_t mvkGetNextViewMaskGroup(uint32_t viewMask, uint32_t* startView, uint32_t* viewCount, uint32_t *groupMask) {
// First, find the first set bit. This is the start of the next clump of views to be rendered.
// n.b. ffs(3) returns a 1-based index. This actually bit me during development of this feature.