Merge pull request #1494 from billhollings/fix-subpass-mtltex-mem-leak

Fix memory leak of dummy MTLTexture in render subpasses that use no attachments.
This commit is contained in:
Bill Hollings 2021-12-27 13:00:34 -05:00 committed by GitHub
commit 939d51da71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 118 additions and 87 deletions

View File

@ -22,6 +22,7 @@ Released TBD
- Do not use `MTLEvent` for `VkSemaphore` under *Rosetta2*. - Do not use `MTLEvent` for `VkSemaphore` under *Rosetta2*.
- Support compiling *MSL 2.4* in runtime pipelines and `MoltenVKShaderConverterTool`. - Support compiling *MSL 2.4* in runtime pipelines and `MoltenVKShaderConverterTool`.
- Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*. - Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*.
- Fix memory leak of dummy `MTLTexture` in render subpasses that use no attachments.
- Fix Metal object retain-release errors in assignment operators. - Fix Metal object retain-release errors in assignment operators.
- Update to latest SPIRV-Cross: - Update to latest SPIRV-Cross:
- MSL: Add 64 bit support for `OpSwitch`. - MSL: Add 64 bit support for `OpSwitch`.

View File

@ -64,8 +64,7 @@ void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->beginRenderpass(this, cmdEncoder->beginRenderpass(this,
_contents, _contents,
_renderPass, _renderPass,
_framebuffer->getExtent2D(), _framebuffer,
_framebuffer->getLayerCount(),
_renderArea, _renderArea,
_clearValues.contents(), _clearValues.contents(),
_attachments.contents()); _attachments.contents());

View File

@ -1234,7 +1234,7 @@ void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
simd::float4 vertices[vtxCnt]; simd::float4 vertices[vtxCnt];
simd::float4 clearColors[kMVKClearAttachmentCount]; simd::float4 clearColors[kMVKClearAttachmentCount];
VkExtent2D fbExtent = cmdEncoder->_framebufferExtent; VkExtent2D fbExtent = cmdEncoder->getFramebufferExtent();
#if MVK_MACOS_OR_IOS #if MVK_MACOS_OR_IOS
// I need to know if the 'renderTargetWidth' and 'renderTargetHeight' properties // I need to know if the 'renderTargetWidth' and 'renderTargetHeight' properties
// actually do something, but [MTLRenderPassDescriptor instancesRespondToSelector: @selector(renderTargetWidth)] // actually do something, but [MTLRenderPassDescriptor instancesRespondToSelector: @selector(renderTargetWidth)]
@ -1255,7 +1255,7 @@ void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
// Populate the render pipeline state attachment key with info from the subpass and framebuffer. // Populate the render pipeline state attachment key with info from the subpass and framebuffer.
_rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount()); _rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount());
if (cmdEncoder->_canUseLayeredRendering && if (cmdEncoder->_canUseLayeredRendering &&
(cmdEncoder->_framebufferLayerCount > 1 || cmdEncoder->getSubpass()->isMultiview())) { (cmdEncoder->getFramebufferLayerCount() > 1 || cmdEncoder->getSubpass()->isMultiview())) {
_rpsKey.enableLayeredRendering(); _rpsKey.enableLayeredRendering();
} }

View File

@ -283,8 +283,7 @@ public:
void beginRenderpass(MVKCommand* passCmd, void beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents, VkSubpassContents subpassContents,
MVKRenderPass* renderPass, MVKRenderPass* renderPass,
VkExtent2D framebufferExtent, MVKFramebuffer* framebuffer,
uint32_t framebufferLayerCount,
VkRect2D& renderArea, VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues, MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> attachments); MVKArrayRef<MVKImageView*> attachments);
@ -307,6 +306,12 @@ public:
/** Returns the render subpass that is currently active. */ /** Returns the render subpass that is currently active. */
MVKRenderSubpass* getSubpass(); MVKRenderSubpass* getSubpass();
/** The extent of current framebuffer.*/
VkExtent2D getFramebufferExtent();
/** The layer count of current framebuffer.*/
uint32_t getFramebufferLayerCount();
/** Returns the index of the currently active multiview subpass, or zero if the current render pass is not multiview. */ /** Returns the index of the currently active multiview subpass, or zero if the current render pass is not multiview. */
uint32_t getMultiviewPassIndex(); uint32_t getMultiviewPassIndex();
@ -483,12 +488,6 @@ public:
/** Indicates whether the current draw is an indexed draw. */ /** Indicates whether the current draw is an indexed draw. */
bool _isIndexedDraw; bool _isIndexedDraw;
/** The extent of current framebuffer.*/
VkExtent2D _framebufferExtent;
/** The layer count of current framebuffer.*/
uint32_t _framebufferLayerCount;
#pragma mark Construction #pragma mark Construction
MVKCommandEncoder(MVKCommandBuffer* cmdBuffer); MVKCommandEncoder(MVKCommandBuffer* cmdBuffer);
@ -513,6 +512,7 @@ protected:
VkSubpassContents _subpassContents; VkSubpassContents _subpassContents;
MVKRenderPass* _renderPass; MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer;
MVKCommand* _lastMultiviewPassCmd; MVKCommand* _lastMultiviewPassCmd;
uint32_t _renderSubpassIndex; uint32_t _renderSubpassIndex;
uint32_t _multiviewPassIndex; uint32_t _multiviewPassIndex;

View File

@ -17,6 +17,7 @@
*/ */
#include "MVKCommandBuffer.h" #include "MVKCommandBuffer.h"
#include "MVKFramebuffer.h"
#include "MVKCommandPool.h" #include "MVKCommandPool.h"
#include "MVKQueue.h" #include "MVKQueue.h"
#include "MVKPipeline.h" #include "MVKPipeline.h"
@ -250,6 +251,7 @@ MVKRenderSubpass* MVKCommandBuffer::getLastMultiviewSubpass() {
void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff, void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff,
MVKCommandEncodingContext* pEncodingContext) { MVKCommandEncodingContext* pEncodingContext) {
_framebuffer = nullptr;
_renderPass = nullptr; _renderPass = nullptr;
_subpassContents = VK_SUBPASS_CONTENTS_INLINE; _subpassContents = VK_SUBPASS_CONTENTS_INLINE;
_renderSubpassIndex = 0; _renderSubpassIndex = 0;
@ -289,17 +291,15 @@ void MVKCommandEncoder::encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer) {
void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd, void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents, VkSubpassContents subpassContents,
MVKRenderPass* renderPass, MVKRenderPass* renderPass,
VkExtent2D framebufferExtent, MVKFramebuffer* framebuffer,
uint32_t framebufferLayerCount,
VkRect2D& renderArea, VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues, MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> attachments) { MVKArrayRef<MVKImageView*> attachments) {
_renderPass = renderPass; _renderPass = renderPass;
_framebufferExtent = framebufferExtent; _framebuffer = framebuffer;
_framebufferLayerCount = framebufferLayerCount;
_renderArea = renderArea; _renderArea = renderArea;
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) && _isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
mvkVkExtent2DsAreEqual(_renderArea.extent, _framebufferExtent)); mvkVkExtent2DsAreEqual(_renderArea.extent, getFramebufferExtent()));
_clearValues.assign(clearValues.begin(), clearValues.end()); _clearValues.assign(clearValues.begin(), clearValues.end());
_attachments.assign(attachments.begin(), attachments.end()); _attachments.assign(attachments.begin(), attachments.end());
setSubpass(passCmd, subpassContents, 0); setSubpass(passCmd, subpassContents, 0);
@ -346,8 +346,7 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc,
_multiviewPassIndex, _multiviewPassIndex,
_framebufferExtent, _framebuffer,
_framebufferLayerCount,
_attachments.contents(), _attachments.contents(),
_clearValues.contents(), _clearValues.contents(),
_isRenderingEntireAttachment, _isRenderingEntireAttachment,
@ -359,7 +358,7 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
mtlRPDesc.visibilityResultBuffer = _pEncodingContext->visibilityResultBuffer->_mtlBuffer; mtlRPDesc.visibilityResultBuffer = _pEncodingContext->visibilityResultBuffer->_mtlBuffer;
} }
VkExtent2D fbExtent = _framebufferExtent; VkExtent2D fbExtent = getFramebufferExtent();
mtlRPDesc.renderTargetWidthMVK = max(min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width), 1u); 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); mtlRPDesc.renderTargetHeightMVK = max(min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height), 1u);
if (_canUseLayeredRendering) { if (_canUseLayeredRendering) {
@ -381,7 +380,7 @@ void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) {
// We need to use the view count for this multiview pass. // We need to use the view count for this multiview pass.
renderTargetArrayLength = getSubpass()->getViewCountInMetalPass(_multiviewPassIndex); renderTargetArrayLength = getSubpass()->getViewCountInMetalPass(_multiviewPassIndex);
} else { } else {
renderTargetArrayLength = _framebufferLayerCount; renderTargetArrayLength = getFramebufferLayerCount();
} }
// Metal does not allow layered render passes where some RTs are 3D and others are 2D. // Metal does not allow layered render passes where some RTs are 3D and others are 2D.
if (!(found3D && found2D) || renderTargetArrayLength > 1) { if (!(found3D && found2D) || renderTargetArrayLength > 1) {
@ -434,6 +433,10 @@ NSString* MVKCommandEncoder::getMTLRenderCommandEncoderName(MVKCommandUse cmdUse
return mvkMTLRenderCommandEncoderLabel(cmdUse); return mvkMTLRenderCommandEncoderLabel(cmdUse);
} }
VkExtent2D MVKCommandEncoder::getFramebufferExtent() { return _framebuffer ? _framebuffer->getExtent2D() : VkExtent2D{0,0}; }
uint32_t MVKCommandEncoder::getFramebufferLayerCount() { return _framebuffer ? _framebuffer->getLayerCount() : 0; }
void MVKCommandEncoder::bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKPipeline* pipeline) { void MVKCommandEncoder::bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKPipeline* pipeline) {
switch (pipelineBindPoint) { switch (pipelineBindPoint) {
case VK_PIPELINE_BIND_POINT_GRAPHICS: case VK_PIPELINE_BIND_POINT_GRAPHICS:
@ -530,7 +533,7 @@ void MVKCommandEncoder::clearRenderArea() {
VkClearRect clearRect; VkClearRect clearRect;
clearRect.rect = _renderArea; clearRect.rect = _renderArea;
clearRect.baseArrayLayer = 0; clearRect.baseArrayLayer = 0;
clearRect.layerCount = _framebufferLayerCount; clearRect.layerCount = getFramebufferLayerCount();
// Create and execute a temporary clear attachments command. // Create and execute a temporary clear attachments command.
// To be threadsafe...do NOT acquire and return the command from the pool. // To be threadsafe...do NOT acquire and return the command from the pool.
@ -577,8 +580,7 @@ void MVKCommandEncoder::endRenderpass() {
endMetalRenderEncoding(); endMetalRenderEncoding();
_renderPass = nullptr; _renderPass = nullptr;
_framebufferExtent = {}; _framebuffer = nullptr;
_framebufferLayerCount = 0;
_attachments.clear(); _attachments.clear();
_renderSubpassIndex = 0; _renderSubpassIndex = 0;
} }

View File

@ -21,6 +21,9 @@
#include "MVKDevice.h" #include "MVKDevice.h"
#include "MVKImage.h" #include "MVKImage.h"
#include "MVKSmallVector.h" #include "MVKSmallVector.h"
#include <mutex>
class MVKRenderSubpass;
#pragma mark MVKFramebuffer #pragma mark MVKFramebuffer
@ -45,16 +48,25 @@ public:
/** Returns the attachments. */ /** Returns the attachments. */
MVKArrayRef<MVKImageView*> getAttachments() { return _attachments.contents(); } MVKArrayRef<MVKImageView*> getAttachments() { return _attachments.contents(); }
/**
* Returns a MTLTexture for use as a dummy texture when a render subpass,
* that is compatible with the specified subpass, has no attachments.
*/
id<MTLTexture> getDummyAttachmentMTLTexture(MVKRenderSubpass* subpass, uint32_t passIdx);
#pragma mark Construction #pragma mark Construction
/** Constructs an instance for the specified device. */
MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo); MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo);
~MVKFramebuffer() override;
protected: protected:
void propagateDebugName() override {} void propagateDebugName() override {}
MVKSmallVector<MVKImageView*, 4> _attachments;
id<MTLTexture> _mtlDummyTex = nil;
std::mutex _lock;
VkExtent2D _extent; VkExtent2D _extent;
uint32_t _layerCount; uint32_t _layerCount;
MVKSmallVector<MVKImageView*, 4> _attachments;
}; };

View File

@ -17,11 +17,68 @@
*/ */
#include "MVKFramebuffer.h" #include "MVKFramebuffer.h"
#include "MVKRenderPass.h"
using namespace std;
#pragma mark MVKFramebuffer #pragma mark MVKFramebuffer
#pragma mark Construction id<MTLTexture> MVKFramebuffer::getDummyAttachmentMTLTexture(MVKRenderSubpass* subpass, uint32_t passIdx) {
if (_mtlDummyTex) { return _mtlDummyTex; }
// Lock and check again in case another thread has created the texture.
lock_guard<mutex> lock(_lock);
if (_mtlDummyTex) { return _mtlDummyTex; }
VkExtent2D fbExtent = getExtent2D();
uint32_t fbLayerCount = getLayerCount();
uint32_t sampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getDefaultSampleCount());
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO];
if (subpass->isMultiview()) {
#if MVK_MACOS_OR_IOS
if (sampleCount > 1 && getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
mtlTexDesc.sampleCount = sampleCount;
} else {
mtlTexDesc.textureType = MTLTextureType2DArray;
}
#else
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
mtlTexDesc.arrayLength = subpass->getViewCountInMetalPass(passIdx);
} else if (fbLayerCount > 1) {
#if MVK_MACOS
if (sampleCount > 1 && getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
mtlTexDesc.sampleCount = sampleCount;
} else {
mtlTexDesc.textureType = MTLTextureType2DArray;
}
#else
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
mtlTexDesc.arrayLength = fbLayerCount;
} else if (sampleCount > 1) {
mtlTexDesc.textureType = MTLTextureType2DMultisample;
mtlTexDesc.sampleCount = sampleCount;
}
#if MVK_IOS
if ([getMTLDevice() supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v3]) {
mtlTexDesc.storageMode = MTLStorageModeMemoryless;
} else {
mtlTexDesc.storageMode = MTLStorageModePrivate;
}
#else
mtlTexDesc.storageMode = MTLStorageModePrivate;
#endif
mtlTexDesc.usage = MTLTextureUsageRenderTarget;
_mtlDummyTex = [getMTLDevice() newTextureWithDescriptor: mtlTexDesc]; // retained
[_mtlDummyTex setPurgeableState: MTLPurgeableStateVolatile];
return _mtlDummyTex;
}
MVKFramebuffer::MVKFramebuffer(MVKDevice* device, MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
const VkFramebufferCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { const VkFramebufferCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
@ -36,3 +93,8 @@ MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
} }
} }
} }
MVKFramebuffer::~MVKFramebuffer() {
[_mtlDummyTex release];
}

View File

@ -76,6 +76,9 @@ public:
/** Returns the Vulkan sample count of the attachments used in this subpass. */ /** Returns the Vulkan sample count of the attachments used in this subpass. */
VkSampleCountFlagBits getSampleCount(); VkSampleCountFlagBits getSampleCount();
/** Returns the default sample count for when there are no attachments used in this subpass. */
VkSampleCountFlagBits getDefaultSampleCount() { return _defaultSampleCount; }
/** Sets the default sample count for when there are no attachments used in this subpass. */ /** Sets the default sample count for when there are no attachments used in this subpass. */
void setDefaultSampleCount(VkSampleCountFlagBits count) { _defaultSampleCount = count; } void setDefaultSampleCount(VkSampleCountFlagBits count) { _defaultSampleCount = count; }
@ -104,8 +107,7 @@ public:
*/ */
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc, void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx, uint32_t passIdx,
VkExtent2D framebufferExtent, MVKFramebuffer* framebuffer,
uint32_t framebufferLayerCount,
const MVKArrayRef<MVKImageView*> attachments, const MVKArrayRef<MVKImageView*> attachments,
const MVKArrayRef<VkClearValue> clearValues, const MVKArrayRef<VkClearValue> clearValues,
bool isRenderingEntireAttachment, bool isRenderingEntireAttachment,
@ -161,7 +163,6 @@ private:
VkAttachmentReference2 _depthStencilResolveAttachment; VkAttachmentReference2 _depthStencilResolveAttachment;
VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE; VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE;
VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE; VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE;
id<MTLTexture> _mtlDummyTex = nil;
VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT; VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT;
}; };

View File

@ -196,8 +196,7 @@ uint32_t MVKRenderSubpass::getViewCountUpToMetalPass(uint32_t passIdx) const {
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc, void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx, uint32_t passIdx,
VkExtent2D framebufferExtent, MVKFramebuffer* framebuffer,
uint32_t framebufferLayerCount,
const MVKArrayRef<MVKImageView*> attachments, const MVKArrayRef<MVKImageView*> attachments,
const MVKArrayRef<VkClearValue> clearValues, const MVKArrayRef<VkClearValue> clearValues,
bool isRenderingEntireAttachment, bool isRenderingEntireAttachment,
@ -326,68 +325,23 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
} }
} }
_mtlDummyTex = nil; // 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 && dsRPAttIdx == VK_ATTACHMENT_UNUSED) {
uint32_t sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount);
if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) { if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) {
// We support having no attachments.
#if MVK_MACOS_OR_IOS #if MVK_MACOS_OR_IOS
mtlRPDesc.defaultRasterSampleCount = sampleCount; mtlRPDesc.defaultRasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount);
#endif #endif
return;
}
// Add a dummy attachment so this passes validation.
VkExtent2D fbExtent = framebufferExtent;
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO];
if (isMultiview()) {
#if MVK_MACOS_OR_IOS
if (sampleCount > 1 && _renderPass->getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
mtlTexDesc.sampleCount = sampleCount;
} else { } else {
mtlTexDesc.textureType = MTLTextureType2DArray;
}
#else
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
mtlTexDesc.arrayLength = getViewCountInMetalPass(passIdx);
} else if (framebufferLayerCount > 1) {
#if MVK_MACOS
if (sampleCount > 1 && _renderPass->getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
mtlTexDesc.sampleCount = sampleCount;
} else {
mtlTexDesc.textureType = MTLTextureType2DArray;
}
#else
mtlTexDesc.textureType = MTLTextureType2DArray;
#endif
mtlTexDesc.arrayLength = framebufferLayerCount;
} else if (sampleCount > 1) {
mtlTexDesc.textureType = MTLTextureType2DMultisample;
mtlTexDesc.sampleCount = sampleCount;
}
#if MVK_IOS
if ([_renderPass->getMTLDevice() supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v3]) {
mtlTexDesc.storageMode = MTLStorageModeMemoryless;
} else {
mtlTexDesc.storageMode = MTLStorageModePrivate;
}
#else
mtlTexDesc.storageMode = MTLStorageModePrivate;
#endif
mtlTexDesc.usage = MTLTextureUsageRenderTarget;
_mtlDummyTex = [_renderPass->getMTLDevice() newTextureWithDescriptor: mtlTexDesc]; // not retained
[_mtlDummyTex setPurgeableState: MTLPurgeableStateVolatile];
MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPDesc.colorAttachments[0]; MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPDesc.colorAttachments[0];
mtlColorAttDesc.texture = _mtlDummyTex; mtlColorAttDesc.texture = framebuffer->getDummyAttachmentMTLTexture(this, passIdx);
mtlColorAttDesc.level = 0; mtlColorAttDesc.level = 0;
mtlColorAttDesc.slice = 0; mtlColorAttDesc.slice = 0;
mtlColorAttDesc.depthPlane = 0; mtlColorAttDesc.depthPlane = 0;
mtlColorAttDesc.loadAction = MTLLoadActionDontCare; mtlColorAttDesc.loadAction = MTLLoadActionDontCare;
mtlColorAttDesc.storeAction = MTLStoreActionDontCare; mtlColorAttDesc.storeAction = MTLStoreActionDontCare;
} }
}
} }
void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder, void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,