Update: support the VK_KHR_imageless_framebuffer extension.
Remove framebuffer reference in MVKCommandEncoder. Instead,
1) non-imageless: copy the attachment vector from
VkFramebufferCreateInfo if it does not contain the
VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR flag.
or
2) imageless: copy the attachment vector from
VkRenderPassAttachmentBeginInfo when calling
vkBeginRenderPass/vkBeginRenderPass2.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index c5b76f8..858473b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -50,7 +50,6 @@
MVKFramebuffer* _framebuffer;
VkRect2D _renderArea;
VkSubpassContents _contents;
- MVKSmallVector<MVKImageView*, 8> _imagelessAttachments;
};
@@ -61,7 +60,7 @@
* Vulkan command to begin a render pass.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
-template <size_t N>
+template <size_t N_CV, size_t N_A>
class MVKCmdBeginRenderPass : public MVKCmdBeginRenderPassBase {
public:
@@ -77,13 +76,22 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKSmallVector<VkClearValue, N> _clearValues;
+ MVKSmallVector<VkClearValue, N_CV> _clearValues;
+ MVKSmallVector<MVKImageView*, N_A> _attachments;
};
// Concrete template class implementations.
-typedef MVKCmdBeginRenderPass<1> MVKCmdBeginRenderPass1;
-typedef MVKCmdBeginRenderPass<2> MVKCmdBeginRenderPass2;
-typedef MVKCmdBeginRenderPass<9> MVKCmdBeginRenderPassMulti;
+typedef MVKCmdBeginRenderPass<1, 0> MVKCmdBeginRenderPass10;
+typedef MVKCmdBeginRenderPass<2, 0> MVKCmdBeginRenderPass20;
+typedef MVKCmdBeginRenderPass<9, 0> MVKCmdBeginRenderPassMulti0;
+
+typedef MVKCmdBeginRenderPass<1, 1> MVKCmdBeginRenderPass11;
+typedef MVKCmdBeginRenderPass<2, 1> MVKCmdBeginRenderPass21;
+typedef MVKCmdBeginRenderPass<9, 1> MVKCmdBeginRenderPassMulti1;
+
+typedef MVKCmdBeginRenderPass<1, 8> MVKCmdBeginRenderPass1Multi;
+typedef MVKCmdBeginRenderPass<2, 8> MVKCmdBeginRenderPass2Multi;
+typedef MVKCmdBeginRenderPass<9, 8> MVKCmdBeginRenderPassMultiMulti;
#pragma mark -
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
index a987c52..0811310 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
@@ -19,6 +19,7 @@
#include "MVKCmdRenderPass.h"
#include "MVKCommandBuffer.h"
#include "MVKCommandPool.h"
+#include "MVKFramebuffer.h"
#include "MVKRenderPass.h"
#include "MVKPipeline.h"
#include "MVKFoundation.h"
@@ -36,20 +37,6 @@
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
_renderArea = pRenderPassBegin->renderArea;
- for (auto* next = (const VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
- switch (next->sType) {
- case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: {
- const auto* pAttachmentBegin = (VkRenderPassAttachmentBeginInfo*)next;
- for(uint32_t i = 0; i < pAttachmentBegin->attachmentCount; i++) {
- _imagelessAttachments.push_back((MVKImageView*)pAttachmentBegin->pAttachments[i]);
- }
- break;
- }
- default:
- break;
- }
- }
-
return VK_SUCCESS;
}
@@ -57,8 +44,8 @@
#pragma mark -
#pragma mark MVKCmdBeginRenderPass
-template <size_t N>
-VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
+template <size_t N_CV, size_t N_A>
+VkResult MVKCmdBeginRenderPass<N_CV, N_A>::setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents) {
MVKCmdBeginRenderPassBase::setContent(cmdBuff, pRenderPassBegin, contents);
@@ -71,25 +58,62 @@
_clearValues.push_back(pRenderPassBegin->pClearValues[i]);
}
+ bool imageless = false;
+ for (auto* next = (const VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: {
+ const auto* pAttachmentBegin = (VkRenderPassAttachmentBeginInfo*)next;
+ for(uint32_t i = 0; i < pAttachmentBegin->attachmentCount; i++) {
+ _attachments.push_back((MVKImageView*)pAttachmentBegin->pAttachments[i]);
+ }
+ imageless = true;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (!imageless) {
+ for(uint32_t i = 0; i < _framebuffer->getAttachmentCount(); i++) {
+ _attachments.push_back((MVKImageView*)_framebuffer->getAttachment(i));
+ }
+ }
+
return VK_SUCCESS;
}
-template <size_t N>
-VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
+template <size_t N_CV, size_t N_A>
+VkResult MVKCmdBeginRenderPass<N_CV, N_A>::setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin,
const VkSubpassBeginInfo* pSubpassBeginInfo) {
return setContent(cmdBuff, pRenderPassBegin, pSubpassBeginInfo->contents);
}
-template <size_t N>
-void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N_CV, size_t N_A>
+void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
- cmdEncoder->beginRenderpass(this, _contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents(), _imagelessAttachments.contents());
+ cmdEncoder->beginRenderpass(this,
+ _contents,
+ _renderPass,
+ _framebuffer->getExtent2D(),
+ _framebuffer->getLayerCount(),
+ _renderArea,
+ _clearValues.contents(),
+ _attachments.contents());
}
-template class MVKCmdBeginRenderPass<1>;
-template class MVKCmdBeginRenderPass<2>;
-template class MVKCmdBeginRenderPass<9>;
+template class MVKCmdBeginRenderPass<1, 0>;
+template class MVKCmdBeginRenderPass<2, 0>;
+template class MVKCmdBeginRenderPass<9, 0>;
+
+template class MVKCmdBeginRenderPass<1, 1>;
+template class MVKCmdBeginRenderPass<2, 1>;
+template class MVKCmdBeginRenderPass<9, 1>;
+
+template class MVKCmdBeginRenderPass<1, 8>;
+template class MVKCmdBeginRenderPass<2, 8>;
+template class MVKCmdBeginRenderPass<9, 8>;
#pragma mark -
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index df50a7d..7d1d379 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -1236,7 +1236,7 @@
simd::float4 vertices[vtxCnt];
simd::float4 clearColors[kMVKClearAttachmentCount];
- VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D();
+ VkExtent2D fbExtent = cmdEncoder->_framebufferExtent;
#if MVK_MACOS_OR_IOS
// I need to know if the 'renderTargetWidth' and 'renderTargetHeight' properties
// actually do something, but [MTLRenderPassDescriptor instancesRespondToSelector: @selector(renderTargetWidth)]
@@ -1257,7 +1257,7 @@
// Populate the render pipeline state attachment key with info from the subpass and framebuffer.
_rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount());
if (cmdEncoder->_canUseLayeredRendering &&
- (cmdEncoder->_framebuffer->getLayerCount() > 1 || cmdEncoder->getSubpass()->isMultiview())) {
+ (cmdEncoder->_framebufferLayerCount > 1 || cmdEncoder->getSubpass()->isMultiview())) {
_rpsKey.enableLayeredRendering();
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index f6f93ee..88d7813 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -273,10 +273,11 @@
void beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents,
MVKRenderPass* renderPass,
- MVKFramebuffer* framebuffer,
+ VkExtent2D framebufferExtent,
+ uint32_t framebufferLayerCount,
VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues,
- MVKArrayRef<MVKImageView*> imagelessAttachments);
+ MVKArrayRef<MVKImageView*> attachments);
/** Begins the next render subpass. */
void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents);
@@ -421,9 +422,6 @@
/** The command buffer whose commands are being encoded. */
MVKCommandBuffer* _cmdBuffer;
- /** The framebuffer to which rendering is currently directed. */
- MVKFramebuffer* _framebuffer;
-
/** The current Metal command buffer. */
id<MTLCommandBuffer> _mtlCmdBuffer;
@@ -475,6 +473,11 @@
/** Indicates whether the current draw is an indexed draw. */
bool _isIndexedDraw;
+ /** The extent of current framebuffer.*/
+ VkExtent2D _framebufferExtent;
+
+ /** The layer count of current framebuffer.*/
+ uint32_t _framebufferLayerCount;
#pragma mark Construction
@@ -495,7 +498,7 @@
VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries;
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
- MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _imagelessAttachments;
+ MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _attachments;
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
MVKCommandUse _mtlComputeEncoderUse;
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index c52bb98..15f8daa 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -20,7 +20,6 @@
#include "MVKCommandPool.h"
#include "MVKQueue.h"
#include "MVKPipeline.h"
-#include "MVKFramebuffer.h"
#include "MVKQueryPool.h"
#include "MVKFoundation.h"
#include "MTLRenderPassDescriptor+MoltenVK.h"
@@ -286,17 +285,21 @@
void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents,
MVKRenderPass* renderPass,
- MVKFramebuffer* framebuffer,
+ VkExtent2D framebufferExtent,
+ uint32_t framebufferLayerCount,
VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues,
- MVKArrayRef<MVKImageView*> imagelessAttachments) {
+ MVKArrayRef<MVKImageView*> attachments) {
_renderPass = renderPass;
- _framebuffer = framebuffer;
+ _framebufferExtent = framebufferExtent;
+ _framebufferLayerCount = framebufferLayerCount;
_renderArea = renderArea;
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
- mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
+ mvkVkExtent2DsAreEqual(_renderArea.extent, _framebufferExtent));
_clearValues.assign(clearValues.begin(), clearValues.end());
- _imagelessAttachments.assign(imagelessAttachments.begin(), imagelessAttachments.end());
+ for(auto* v : attachments) {
+ _attachments.push_back(v);
+ }
setSubpass(passCmd, subpassContents, 0);
}
@@ -336,7 +339,14 @@
endCurrentMetalEncoding();
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
- getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _multiviewPassIndex, _framebuffer, _imagelessAttachments.contents(), _clearValues.contents(), _isRenderingEntireAttachment, loadOverride);
+ getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc,
+ _multiviewPassIndex,
+ _framebufferExtent,
+ _framebufferLayerCount,
+ _attachments.contents(),
+ _clearValues.contents(),
+ _isRenderingEntireAttachment,
+ loadOverride);
if (_cmdBuffer->_needsVisibilityResultMTLBuffer) {
if (!_visibilityResultMTLBuffer) {
_visibilityResultMTLBuffer = getTempMTLBuffer(_pDeviceMetalFeatures->maxQueryBufferSize, true, true);
@@ -344,7 +354,7 @@
mtlRPDesc.visibilityResultBuffer = _visibilityResultMTLBuffer->_mtlBuffer;
}
- VkExtent2D fbExtent = _framebuffer->getExtent2D();
+ VkExtent2D fbExtent = _framebufferExtent;
mtlRPDesc.renderTargetWidthMVK = max(min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width), 1u);
mtlRPDesc.renderTargetHeightMVK = max(min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height), 1u);
if (_canUseLayeredRendering) {
@@ -364,9 +374,9 @@
if (getSubpass()->isMultiview()) {
// In the case of a multiview pass, the framebuffer layer count will be one.
// We need to use the view count for this multiview pass.
- renderTargetArrayLength = getSubpass()->getViewCountInMetalPass(_multiviewPassIndex);
+ renderTargetArrayLength = getSubpass()->getViewCountInMetalPass(_multiviewPassIndex);
} else {
- renderTargetArrayLength = _framebuffer->getLayerCount();
+ renderTargetArrayLength = _framebufferLayerCount;
}
// Metal does not allow layered render passes where some RTs are 3D and others are 2D.
if (!(found3D && found2D) || renderTargetArrayLength > 1) {
@@ -397,7 +407,7 @@
void MVKCommandEncoder::encodeStoreActions(bool storeOverride) {
getSubpass()->encodeStoreActions(this,
_isRenderingEntireAttachment,
- _imagelessAttachments.contents(),
+ _attachments.contents(),
storeOverride);
}
@@ -513,7 +523,7 @@
VkClearRect clearRect;
clearRect.rect = _renderArea;
clearRect.baseArrayLayer = 0;
- clearRect.layerCount = _framebuffer->getLayerCount();
+ clearRect.layerCount = _framebufferLayerCount;
// Create and execute a temporary clear attachments command.
// To be threadsafe...do NOT acquire and return the command from the pool.
@@ -560,7 +570,7 @@
endMetalRenderEncoding();
_renderPass = nullptr;
- _framebuffer = nullptr;
+ _attachments.clear();
_renderSubpassIndex = 0;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
index 26009aa..6f74ed4 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
@@ -56,11 +56,21 @@
MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold3) \
MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi)
+#define MVK_CMD_TYPE_POOLS_FROM_4_THRESHOLDS(cmdType, arg1Threshold1, arg1Threshold2, arg2Threshold1, arg2Threshold2) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold1 ##arg2Threshold1) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold1 ##arg2Threshold2) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold1 ##Multi) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold2 ##arg2Threshold1) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold2 ##arg2Threshold2) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##arg1Threshold2 ##Multi) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi ##arg2Threshold1) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi ##arg2Threshold2) \
+ MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi ##Multi)
MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(PipelineBarrier, 1, 4)
MVK_CMD_TYPE_POOL(BindGraphicsPipeline)
MVK_CMD_TYPE_POOL(BindComputePipeline)
-MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BeginRenderPass, 1, 2)
+MVK_CMD_TYPE_POOLS_FROM_4_THRESHOLDS(BeginRenderPass, 1, 2, 0, 1)
MVK_CMD_TYPE_POOL(NextSubpass)
MVK_CMD_TYPE_POOL(EndRenderPass)
MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1)
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
index 0fc06b4..32cd5dd 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
@@ -44,8 +44,8 @@
/** Returns the attachment at the specified index. */
inline MVKImageView* getAttachment(uint32_t index) { return _attachments[index]; }
-
- inline bool getImageless() { return _imageless; }
+
+ inline size_t getAttachmentCount() {return _attachments.size(); }
#pragma mark Construction
@@ -58,7 +58,5 @@
VkExtent2D _extent;
uint32_t _layerCount;
MVKSmallVector<MVKImageView*, 4> _attachments;
- bool _imageless;
- MVKSmallVector<MVKImageView*, 4> _imagelessAttachments;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm
index 18d442a..91d3bde 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.mm
@@ -28,11 +28,7 @@
_extent = { .width = pCreateInfo->width, .height = pCreateInfo->height };
_layerCount = pCreateInfo->layers;
- if (pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) {
- _imageless = true;
- }
- else {
- _imageless = false;
+ if (!(pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR)) {
// Add attachments
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index 8c0a89f..c813fa6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -95,8 +95,9 @@
*/
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
- MVKFramebuffer* framebuffer,
- const MVKArrayRef<MVKImageView*>& imagelessAttachments,
+ VkExtent2D framebufferExtent,
+ uint32_t framebufferLayerCount,
+ const MVKArrayRef<MVKImageView*>& attachments,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride = false);
@@ -120,7 +121,7 @@
/** If a render encoder is active, sets the store actions for all attachments to it. */
void encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool isRenderingEntireAttachment,
- const MVKArrayRef<MVKImageView*>& imagelessAttachments,
+ const MVKArrayRef<MVKImageView*>& attachments,
bool storeOverride = false);
/** Constructs an instance for the specified parent renderpass. */
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 0b8f2a9..0443597 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -175,13 +175,13 @@
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
- MVKFramebuffer* framebuffer,
- const MVKArrayRef<MVKImageView*>& imagelessAttachments,
+ VkExtent2D framebufferExtent,
+ uint32_t framebufferLayerCount,
+ const MVKArrayRef<MVKImageView*>& attachments,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride) {
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
- bool imageless = framebuffer->getImageless();
// Populate the Metal color attachments
uint32_t caCnt = getColorAttachmentCount();
@@ -197,12 +197,7 @@
uint32_t rslvRPAttIdx = _resolveAttachments.empty() ? VK_ATTACHMENT_UNUSED : _resolveAttachments[caIdx].attachment;
bool hasResolveAttachment = (rslvRPAttIdx != VK_ATTACHMENT_UNUSED);
if (hasResolveAttachment) {
- if (imageless) {
- imagelessAttachments[rslvRPAttIdx]->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
- }
- else {
- framebuffer->getAttachment(rslvRPAttIdx)->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
- }
+ attachments[rslvRPAttIdx]->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
// In a multiview render pass, we need to override the starting layer to ensure
// only the enabled views are loaded.
@@ -217,17 +212,10 @@
// Configure the color attachment
MVKRenderPassAttachment* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx];
- if (imageless) {
- imagelessAttachments[clrRPAttIdx]->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
- }
- else {
- framebuffer->getAttachment(clrRPAttIdx)->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
- }
+ attachments[clrRPAttIdx]->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
- isMemorylessAttachment = imageless
- ? imagelessAttachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
- : framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
+ isMemorylessAttachment = attachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this,
isRenderingEntireAttachment,
@@ -251,16 +239,12 @@
uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx];
- MVKImageView* dsImage = imageless
- ? imagelessAttachments[dsRPAttIdx]
- : framebuffer->getAttachment(dsRPAttIdx);
+ MVKImageView* dsImage = attachments[dsRPAttIdx];
MVKImageView* dsRslvImage = nullptr;
MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0);
if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
- dsRslvImage = imageless
- ? imagelessAttachments[dsRslvRPAttIdx]
- : framebuffer->getAttachment(dsRslvRPAttIdx);
+ dsRslvImage = attachments[dsRslvRPAttIdx];
}
if (pixFmts->isDepthFormat(mtlDSFormat)) {
@@ -331,7 +315,7 @@
}
// Add a dummy attachment so this passes validation.
- VkExtent2D fbExtent = framebuffer->getExtent2D();
+ VkExtent2D fbExtent = framebufferExtent;
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO];
if (isMultiview()) {
#if MVK_MACOS_OR_IOS
@@ -345,7 +329,7 @@
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
mtlTexDesc.arrayLength = getViewCountInMetalPass(passIdx);
- } else if (framebuffer->getLayerCount() > 1) {
+ } else if (framebufferLayerCount > 1) {
#if MVK_MACOS
if (sampleCount > 1 && _renderPass->getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
@@ -356,7 +340,7 @@
#else
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
- mtlTexDesc.arrayLength = framebuffer->getLayerCount();
+ mtlTexDesc.arrayLength = framebufferLayerCount;
} else if (sampleCount > 1) {
mtlTexDesc.textureType = MTLTextureType2DMultisample;
mtlTexDesc.sampleCount = sampleCount;
@@ -385,7 +369,7 @@
void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool isRenderingEntireAttachment,
- const MVKArrayRef<MVKImageView*>& imagelessAttachments,
+ const MVKArrayRef<MVKImageView*>& attachments,
bool storeOverride) {
if (!cmdEncoder->_mtlRenderEncoder) { return; }
if (!_renderPass->getDevice()->_pMetalFeatures->deferredStoreActions) { return; }
@@ -397,9 +381,7 @@
bool hasResolveAttachment = _resolveAttachments.empty() ? false : _resolveAttachments[caIdx].attachment != VK_ATTACHMENT_UNUSED;
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
- isMemorylessAttachment = cmdEncoder->_framebuffer->getImageless()
- ? imagelessAttachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
- : cmdEncoder->_framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
+ isMemorylessAttachment = attachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
_renderPass->_attachments[clrRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasResolveAttachment, caIdx, false, storeOverride);
}
@@ -411,9 +393,7 @@
bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE;
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
- isMemorylessAttachment = cmdEncoder->_framebuffer->getImageless()
- ? imagelessAttachments[dsRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
- : cmdEncoder->_framebuffer->getAttachment(dsRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
+ isMemorylessAttachment = attachments[dsRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasDepthResolveAttachment, 0, false, storeOverride);
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasStencilResolveAttachment, 0, true, storeOverride);
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 2546e84..d9070f7 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -131,6 +131,29 @@
MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__); \
}
+// Add one of nine commands, based on comparing a command parameter against four threshold values
+#define MVKAddCmdFrom4Thresholds(baseCmdType, value1, arg1Threshold1, arg1Threshold2, \
+ value2, arg2Threshold1, arg2Threshold2, vkCmdBuff, ...) \
+ if (value1 <= arg1Threshold1 && value2 <= arg2Threshold1) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold1 ##arg2Threshold1, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 <= arg1Threshold2 && value2 <= arg2Threshold1) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold1 ##arg2Threshold1, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 > arg1Threshold2 && value2 <= arg2Threshold1) { \
+ MVKAddCmd(baseCmdType ##Multi ##arg2Threshold1, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 <= arg1Threshold1 && value2 <= arg2Threshold2) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold1 ##arg2Threshold2, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 <= arg1Threshold2 && value2 <= arg2Threshold2) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold2 ##arg2Threshold2, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 > arg1Threshold2 && value2 <= arg2Threshold2) { \
+ MVKAddCmd(baseCmdType ##Multi ##arg2Threshold2, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 <= arg1Threshold1 && value2 > arg2Threshold2) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold1 ##Multi, vkCmdBuff, ##__VA_ARGS__); \
+ } else if (value1 <= arg1Threshold2 && value2 > arg2Threshold2) { \
+ MVKAddCmd(baseCmdType ##arg1Threshold2 ##Multi, vkCmdBuff, ##__VA_ARGS__); \
+ } else { \
+ MVKAddCmd(baseCmdType ##Multi ##Multi, vkCmdBuff, ##__VA_ARGS__); \
+ }
+
// Define an extension call as an alias of a core call
#define MVK_PUBLIC_CORE_ALIAS(vkf) MVK_PUBLIC_ALIAS(vkf##KHR, vkf)
@@ -1869,7 +1892,24 @@
VkSubpassContents contents) {
MVKTraceVulkanCallStart();
- MVKAddCmdFrom2Thresholds(BeginRenderPass, pRenderPassBegin->clearValueCount, 1, 2, commandBuffer,pRenderPassBegin, contents);
+ uint32_t attachmentCount = 0;
+ for (const auto* next = (VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
+ switch(next->sType) {
+ case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: {
+ auto* pAttachmentBegin = (VkRenderPassAttachmentBeginInfo*)next;
+ attachmentCount = pAttachmentBegin->attachmentCount;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ MVKAddCmdFrom4Thresholds(BeginRenderPass,
+ pRenderPassBegin->clearValueCount, 1, 2,
+ attachmentCount, 0, 1,
+ commandBuffer,
+ pRenderPassBegin,
+ contents);
MVKTraceVulkanCallEnd();
}
@@ -2283,7 +2323,24 @@
const VkSubpassBeginInfo* pSubpassBeginInfo) {
MVKTraceVulkanCallStart();
- MVKAddCmdFrom2Thresholds(BeginRenderPass, pRenderPassBegin->clearValueCount, 1, 2, commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+ uint32_t attachmentCount = 0;
+ for (const auto* next = (VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
+ switch(next->sType) {
+ case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: {
+ auto* pAttachmentBegin = (VkRenderPassAttachmentBeginInfo*)next;
+ attachmentCount = pAttachmentBegin->attachmentCount;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ MVKAddCmdFrom4Thresholds(BeginRenderPass,
+ pRenderPassBegin->clearValueCount, 1, 2,
+ attachmentCount, 0, 1,
+ commandBuffer,
+ pRenderPassBegin,
+ pSubpassBeginInfo);
MVKTraceVulkanCallEnd();
}