Reduce memory leaks when autorelease pools are not available.
Remove use of autorelease. Rename getXXX() functions that returned autoreleased objects to newXXX() that don't. Calling functions now responsible for releasing returned objects from these functions. Move creation and tracking of texture->texture views for copying to MVKImage. MVKCmdCopyImage retrieve texture view from MVKImage. MVKMTLFunction responsible for releasing its MTLFunction. Add dev notes to README.md.
This commit is contained in:
parent
27a1c44f0a
commit
65eed2fe33
@ -67,8 +67,7 @@ protected:
|
||||
bool _isSrcCompressed;
|
||||
bool _isDstCompressed;
|
||||
bool _canCopyFormats;
|
||||
bool _shouldUseTextureView;
|
||||
bool _shouldUseTempBuffer;
|
||||
bool _useTempBuffer;
|
||||
std::vector<VkImageCopy> _imageCopyRegions;
|
||||
std::vector<VkBufferImageCopy> _srcTmpBuffImgCopies;
|
||||
std::vector<VkBufferImageCopy> _dstTmpBuffImgCopies;
|
||||
|
@ -77,8 +77,7 @@ void MVKCmdCopyImage::setContent(VkImage srcImage,
|
||||
uint32_t dstBytesPerBlock = mvkMTLPixelFormatBytesPerBlock(_dstMTLPixFmt);
|
||||
|
||||
_canCopyFormats = (srcBytesPerBlock == dstBytesPerBlock) && (_srcSampleCount == _dstSampleCount);
|
||||
_shouldUseTextureView = (_srcMTLPixFmt != _dstMTLPixFmt) && !(_isSrcCompressed || _isDstCompressed); // Different formats and neither is compressed
|
||||
_shouldUseTempBuffer = (_srcMTLPixFmt != _dstMTLPixFmt) && (_isSrcCompressed || _isDstCompressed); // Different formats and at least one is compressed
|
||||
_useTempBuffer = (_srcMTLPixFmt != _dstMTLPixFmt) && (_isSrcCompressed || _isDstCompressed); // Different formats and at least one is compressed
|
||||
|
||||
_commandUse = commandUse;
|
||||
_tmpBuffSize = 0;
|
||||
@ -89,7 +88,7 @@ void MVKCmdCopyImage::setContent(VkImage srcImage,
|
||||
}
|
||||
|
||||
void MVKCmdCopyImage::addImageCopyRegion(const VkImageCopy& region) {
|
||||
if (_shouldUseTempBuffer) {
|
||||
if (_useTempBuffer) {
|
||||
addTempBufferImageCopyRegion(region); // Convert to image->buffer->image copies
|
||||
} else {
|
||||
_imageCopyRegions.push_back(region);
|
||||
@ -133,15 +132,14 @@ void MVKCmdCopyImage::addTempBufferImageCopyRegion(const VkImageCopy& region) {
|
||||
}
|
||||
|
||||
void MVKCmdCopyImage::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture();
|
||||
// Unless we need to use an intermediary buffer copy, map the source pixel format to the
|
||||
// dest pixel format through a texture view on the source texture. If the source and dest
|
||||
// pixel formats are the same, this will simply degenerate to the source texture itself.
|
||||
MTLPixelFormat mapSrcMTLPixFmt = _useTempBuffer ? _srcMTLPixFmt : _dstMTLPixFmt;
|
||||
id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(mapSrcMTLPixFmt);
|
||||
id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
|
||||
if ( !srcMTLTex || !dstMTLTex ) { return; }
|
||||
|
||||
// If the pixel formats are different but mappable, use a texture view on the source texture
|
||||
if (_shouldUseTextureView) {
|
||||
srcMTLTex = [[srcMTLTex newTextureViewWithPixelFormat: _dstMTLPixFmt] autorelease];
|
||||
}
|
||||
|
||||
id<MTLBlitCommandEncoder> mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(_commandUse);
|
||||
|
||||
// If copies can be performed using direct texture-texture copying, do so
|
||||
|
@ -357,8 +357,8 @@ public:
|
||||
*/
|
||||
id<MTLDepthStencilState> newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData);
|
||||
|
||||
/** Returns an autoreleased MTLStencilDescriptor constructed from the stencil data. */
|
||||
MTLStencilDescriptor* getMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData);
|
||||
/** Returns an retained MTLStencilDescriptor constructed from the stencil data. */
|
||||
MTLStencilDescriptor* newMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData);
|
||||
|
||||
/**
|
||||
* Returns a new MVKImage configured with content held in Private storage.
|
||||
@ -405,15 +405,15 @@ public:
|
||||
protected:
|
||||
void initMTLLibrary();
|
||||
void initImageDeviceMemory();
|
||||
id<MTLFunction> getBlitFragFunction(MVKRPSKeyBlitImg& blitKey);
|
||||
id<MTLFunction> getClearVertFunction(MVKRPSKeyClearAtt& attKey);
|
||||
id<MTLFunction> getClearFragFunction(MVKRPSKeyClearAtt& attKey);
|
||||
id<MTLFunction> newBlitFragFunction(MVKRPSKeyBlitImg& blitKey);
|
||||
id<MTLFunction> newClearVertFunction(MVKRPSKeyClearAtt& attKey);
|
||||
id<MTLFunction> newClearFragFunction(MVKRPSKeyClearAtt& attKey);
|
||||
NSString* getMTLFormatTypeString(MTLPixelFormat mtlPixFmt);
|
||||
id<MTLFunction> getFunctionNamed(const char* funcName);
|
||||
id<MTLFunction> newFunctionNamed(const char* funcName);
|
||||
id<MTLFunction> newMTLFunction(NSString* mslSrcCode, NSString* funcName);
|
||||
id<MTLRenderPipelineState> newMTLRenderPipelineState(MTLRenderPipelineDescriptor* plDesc,
|
||||
MVKVulkanAPIDeviceObject* owner);
|
||||
id<MTLComputePipelineState> newMTLComputePipelineState(id<MTLFunction> mtlFunction,
|
||||
id<MTLComputePipelineState> newMTLComputePipelineState(const char* funcName,
|
||||
MVKVulkanAPIDeviceObject* owner);
|
||||
|
||||
id<MTLLibrary> _mtlLibrary;
|
||||
|
@ -33,11 +33,13 @@ using namespace std;
|
||||
|
||||
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
|
||||
id<MTLFunction> vtxFunc = newFunctionNamed("vtxCmdBlitImage"); // temp retain
|
||||
id<MTLFunction> fragFunc = newBlitFragFunction(blitKey); // temp retain
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retain
|
||||
plDesc.label = @"CmdBlitImage";
|
||||
|
||||
plDesc.vertexFunction = getFunctionNamed("vtxCmdBlitImage");
|
||||
plDesc.fragmentFunction = getBlitFragFunction(blitKey);
|
||||
plDesc.vertexFunction = vtxFunc;
|
||||
plDesc.fragmentFunction = fragFunc;
|
||||
plDesc.sampleCount = blitKey.dstSampleCount;
|
||||
|
||||
plDesc.colorAttachments[0].pixelFormat = blitKey.getDstMTLPixelFormat();
|
||||
@ -71,12 +73,18 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdBlitImageMTLRenderPi
|
||||
vbDesc.stepRate = 1;
|
||||
vbDesc.stride = vtxStride;
|
||||
|
||||
return newMTLRenderPipelineState(plDesc, owner);
|
||||
id<MTLRenderPipelineState> rps = newMTLRenderPipelineState(plDesc, owner);
|
||||
|
||||
[vtxFunc release]; // temp release
|
||||
[fragFunc release]; // temp release
|
||||
[plDesc release]; // temp release
|
||||
|
||||
return rps;
|
||||
}
|
||||
|
||||
id<MTLSamplerState> MVKCommandResourceFactory::newCmdBlitImageMTLSamplerState(MTLSamplerMinMagFilter mtlFilter) {
|
||||
|
||||
MTLSamplerDescriptor* sDesc = [[[MTLSamplerDescriptor alloc] init] autorelease];
|
||||
MTLSamplerDescriptor* sDesc = [MTLSamplerDescriptor new]; // temp retain
|
||||
sDesc.rAddressMode = MTLSamplerAddressModeClampToZero;
|
||||
sDesc.sAddressMode = MTLSamplerAddressModeClampToZero;
|
||||
sDesc.tAddressMode = MTLSamplerAddressModeClampToZero;
|
||||
@ -84,15 +92,22 @@ id<MTLSamplerState> MVKCommandResourceFactory::newCmdBlitImageMTLSamplerState(MT
|
||||
sDesc.normalizedCoordinates = YES;
|
||||
sDesc.minFilter = mtlFilter;
|
||||
sDesc.magFilter = mtlFilter;
|
||||
return [getMTLDevice() newSamplerStateWithDescriptor: sDesc];
|
||||
|
||||
id<MTLSamplerState> ss = [getMTLDevice() newSamplerStateWithDescriptor: sDesc];
|
||||
|
||||
[sDesc release]; // temp release
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
|
||||
id<MTLFunction> vtxFunc = newClearVertFunction(attKey); // temp retain
|
||||
id<MTLFunction> fragFunc = newClearFragFunction(attKey); // temp retain
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retain
|
||||
plDesc.label = @"CmdClearAttachments";
|
||||
plDesc.vertexFunction = getClearVertFunction(attKey);
|
||||
plDesc.fragmentFunction = getClearFragFunction(attKey);
|
||||
plDesc.vertexFunction = vtxFunc;
|
||||
plDesc.fragmentFunction = fragFunc;
|
||||
plDesc.sampleCount = attKey.mtlSampleCount;
|
||||
plDesc.inputPrimitiveTopologyMVK = MTLPrimitiveTopologyClassTriangle;
|
||||
|
||||
@ -127,19 +142,23 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipeli
|
||||
vbDesc.stepRate = 1;
|
||||
vbDesc.stride = vtxStride;
|
||||
|
||||
return newMTLRenderPipelineState(plDesc, owner);
|
||||
id<MTLRenderPipelineState> rps = newMTLRenderPipelineState(plDesc, owner);
|
||||
|
||||
[vtxFunc release]; // temp release
|
||||
[fragFunc release]; // temp release
|
||||
[plDesc release]; // temp release
|
||||
|
||||
return rps;
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg& blitKey) {
|
||||
id<MTLFunction> mtlFunc = nil;
|
||||
|
||||
NSString* typeStr = getMTLFormatTypeString(blitKey.getSrcMTLPixelFormat());
|
||||
|
||||
bool isArrayType = blitKey.isSrcArrayType();
|
||||
NSString* arraySuffix = isArrayType ? @"_array" : @"";
|
||||
NSString* sliceArg = isArrayType ? @", srcSlice" : @"";
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg& blitKey) {
|
||||
@autoreleasepool {
|
||||
NSString* typeStr = getMTLFormatTypeString(blitKey.getSrcMTLPixelFormat());
|
||||
|
||||
bool isArrayType = blitKey.isSrcArrayType();
|
||||
NSString* arraySuffix = isArrayType ? @"_array" : @"";
|
||||
NSString* sliceArg = isArrayType ? @", srcSlice" : @"";
|
||||
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
[msl appendLineMVK: @"#include <metal_stdlib>"];
|
||||
[msl appendLineMVK: @"using namespace metal;"];
|
||||
@ -161,14 +180,13 @@ id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"}"];
|
||||
|
||||
mtlFunc = newMTLFunction(msl, funcName);
|
||||
// MVKLogDebug("\n%s", msl.UTF8String);
|
||||
|
||||
return newMTLFunction(msl, funcName);
|
||||
}
|
||||
return [mtlFunc autorelease];
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::getClearVertFunction(MVKRPSKeyClearAtt& attKey) {
|
||||
id<MTLFunction> mtlFunc = nil;
|
||||
id<MTLFunction> MVKCommandResourceFactory::newClearVertFunction(MVKRPSKeyClearAtt& attKey) {
|
||||
@autoreleasepool {
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
[msl appendLineMVK: @"#include <metal_stdlib>"];
|
||||
@ -197,14 +215,13 @@ id<MTLFunction> MVKCommandResourceFactory::getClearVertFunction(MVKRPSKeyClearAt
|
||||
[msl appendLineMVK: @" return varyings;"];
|
||||
[msl appendLineMVK: @"}"];
|
||||
|
||||
mtlFunc = newMTLFunction(msl, funcName);
|
||||
// MVKLogDebug("\n%s", msl.UTF8String);
|
||||
|
||||
return newMTLFunction(msl, funcName);
|
||||
}
|
||||
return [mtlFunc autorelease];
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAtt& attKey) {
|
||||
id<MTLFunction> mtlFunc = nil;
|
||||
id<MTLFunction> MVKCommandResourceFactory::newClearFragFunction(MVKRPSKeyClearAtt& attKey) {
|
||||
@autoreleasepool {
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
[msl appendLineMVK: @"#include <metal_stdlib>"];
|
||||
@ -243,10 +260,10 @@ id<MTLFunction> MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAt
|
||||
[msl appendLineMVK: @" return ccOut;"];
|
||||
[msl appendLineMVK: @"}"];
|
||||
|
||||
mtlFunc = newMTLFunction(msl, funcName);
|
||||
// MVKLogDebug("\n%s", msl.UTF8String);
|
||||
|
||||
return newMTLFunction(msl, funcName);
|
||||
}
|
||||
return [mtlFunc autorelease];
|
||||
}
|
||||
|
||||
NSString* MVKCommandResourceFactory::getMTLFormatTypeString(MTLPixelFormat mtlPixFmt) {
|
||||
@ -265,12 +282,12 @@ NSString* MVKCommandResourceFactory::getMTLFormatTypeString(MTLPixelFormat mtlPi
|
||||
|
||||
id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(bool useDepth, bool useStencil) {
|
||||
|
||||
MTLDepthStencilDescriptor* dsDesc = [[[MTLDepthStencilDescriptor alloc] init] autorelease];
|
||||
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain
|
||||
dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
|
||||
dsDesc.depthWriteEnabled = useDepth;
|
||||
|
||||
if (useStencil) {
|
||||
MTLStencilDescriptor* sDesc = [[[MTLStencilDescriptor alloc] init] autorelease];
|
||||
MTLStencilDescriptor* sDesc = [MTLStencilDescriptor new]; // temp retain
|
||||
sDesc.stencilCompareFunction = MTLCompareFunctionAlways;
|
||||
sDesc.stencilFailureOperation = MTLStencilOperationReplace;
|
||||
sDesc.depthFailureOperation = MTLStencilOperationReplace;
|
||||
@ -278,28 +295,42 @@ id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(bool
|
||||
|
||||
dsDesc.frontFaceStencil = sDesc;
|
||||
dsDesc.backFaceStencil = sDesc;
|
||||
|
||||
[sDesc release]; // temp release
|
||||
} else {
|
||||
dsDesc.frontFaceStencil = nil;
|
||||
dsDesc.backFaceStencil = nil;
|
||||
}
|
||||
|
||||
return [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
|
||||
id<MTLDepthStencilState> dss = [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
|
||||
|
||||
[dsDesc release]; // temp release
|
||||
|
||||
return dss;
|
||||
}
|
||||
|
||||
id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) {
|
||||
MTLDepthStencilDescriptor* dsDesc = [[[MTLDepthStencilDescriptor alloc] init] autorelease];
|
||||
MTLStencilDescriptor* fsDesc = newMTLStencilDescriptor(dsData.frontFaceStencilData); // temp retain
|
||||
MTLStencilDescriptor* bsDesc = newMTLStencilDescriptor(dsData.backFaceStencilData); // temp retain
|
||||
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; // temp retain
|
||||
dsDesc.depthCompareFunction = (MTLCompareFunction)dsData.depthCompareFunction;
|
||||
dsDesc.depthWriteEnabled = dsData.depthWriteEnabled;
|
||||
dsDesc.frontFaceStencil = getMTLStencilDescriptor(dsData.frontFaceStencilData);
|
||||
dsDesc.backFaceStencil = getMTLStencilDescriptor(dsData.backFaceStencilData);
|
||||
dsDesc.frontFaceStencil = fsDesc;
|
||||
dsDesc.backFaceStencil = bsDesc;
|
||||
|
||||
return [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
|
||||
id<MTLDepthStencilState> dss = [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
|
||||
|
||||
[fsDesc release]; // temp release
|
||||
[bsDesc release]; // temp release
|
||||
[dsDesc release]; // temp release
|
||||
|
||||
return dss;
|
||||
}
|
||||
|
||||
MTLStencilDescriptor* MVKCommandResourceFactory::getMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) {
|
||||
MTLStencilDescriptor* MVKCommandResourceFactory::newMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) {
|
||||
if ( !sData.enabled ) { return nil; }
|
||||
|
||||
MTLStencilDescriptor* sDesc = [[[MTLStencilDescriptor alloc] init] autorelease];
|
||||
MTLStencilDescriptor* sDesc = [MTLStencilDescriptor new]; // retained
|
||||
sDesc.stencilCompareFunction = (MTLCompareFunction)sData.stencilCompareFunction;
|
||||
sDesc.stencilFailureOperation = (MTLStencilOperation)sData.stencilFailureOperation;
|
||||
sDesc.depthFailureOperation = (MTLStencilOperation)sData.depthFailureOperation;
|
||||
@ -362,68 +393,75 @@ MVKBuffer* MVKCommandResourceFactory::newMVKBuffer(MVKBufferDescriptorData& buff
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdCopyBufferBytesMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed("cmdCopyBufferBytes"), owner);
|
||||
return newMTLComputePipelineState("cmdCopyBufferBytes", owner);
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdFillBufferMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed("cmdFillBuffer"), owner);
|
||||
return newMTLComputePipelineState("cmdFillBuffer", owner);
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed(needTempBuf
|
||||
? "cmdCopyBufferToImage3DDecompressTempBufferDXTn"
|
||||
: "cmdCopyBufferToImage3DDecompressDXTn"), owner);
|
||||
return newMTLComputePipelineState(needTempBuf
|
||||
? "cmdCopyBufferToImage3DDecompressTempBufferDXTn"
|
||||
: "cmdCopyBufferToImage3DDecompressDXTn", owner);
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed(indexed
|
||||
? "cmdDrawIndexedIndirectConvertBuffers"
|
||||
: "cmdDrawIndirectConvertBuffers"), owner);
|
||||
return newMTLComputePipelineState(indexed
|
||||
? "cmdDrawIndexedIndirectConvertBuffers"
|
||||
: "cmdDrawIndirectConvertBuffers", owner);
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed(type == MTLIndexTypeUInt16
|
||||
? "cmdDrawIndexedCopyIndex16Buffer"
|
||||
: "cmdDrawIndexedCopyIndex32Buffer"), owner);
|
||||
return newMTLComputePipelineState(type == MTLIndexTypeUInt16
|
||||
? "cmdDrawIndexedCopyIndex16Buffer"
|
||||
: "cmdDrawIndexedCopyIndex32Buffer", owner);
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdCopyQueryPoolResultsMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner) {
|
||||
return newMTLComputePipelineState(getFunctionNamed("cmdCopyQueryPoolResultsToBuffer"), owner);
|
||||
return newMTLComputePipelineState("cmdCopyQueryPoolResultsToBuffer", owner);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Support methods
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::getFunctionNamed(const char* funcName) {
|
||||
// Returns the retained MTLFunction with the name.
|
||||
// The caller is responsible for releasing the returned function object.
|
||||
id<MTLFunction> MVKCommandResourceFactory::newFunctionNamed(const char* funcName) {
|
||||
uint64_t startTime = _device->getPerformanceTimestamp();
|
||||
NSString* nsFuncName = [[NSString alloc] initWithUTF8String: funcName]; // temp retained
|
||||
id<MTLFunction> mtlFunc = [[_mtlLibrary newFunctionWithName: nsFuncName] autorelease];
|
||||
[nsFuncName release]; // release temp NSStr
|
||||
id<MTLFunction> mtlFunc = [_mtlLibrary newFunctionWithName: nsFuncName]; // retained
|
||||
[nsFuncName release]; // temp release
|
||||
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
|
||||
return mtlFunc;
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::newMTLFunction(NSString* mslSrcCode, NSString* funcName) {
|
||||
@autoreleasepool {
|
||||
id<MTLFunction> mtlFunc = nil;
|
||||
NSError* err = nil;
|
||||
|
||||
uint64_t startTime = _device->getPerformanceTimestamp();
|
||||
id<MTLLibrary> mtlLib = [[getMTLDevice() newLibraryWithSource: mslSrcCode
|
||||
options: getDevice()->getMTLCompileOptions()
|
||||
error: &err] autorelease];
|
||||
id<MTLLibrary> mtlLib = [getMTLDevice() newLibraryWithSource: mslSrcCode
|
||||
options: getDevice()->getMTLCompileOptions()
|
||||
error: &err]; // temp retain
|
||||
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.mslCompile, startTime);
|
||||
|
||||
if (err) {
|
||||
reportError(VK_ERROR_INITIALIZATION_FAILED,
|
||||
"Could not compile support shader from MSL source (Error code %li):\n%s\n%s",
|
||||
(long)err.code, mslSrcCode.UTF8String, err.localizedDescription.UTF8String);
|
||||
return nil;
|
||||
} else {
|
||||
startTime = _device->getPerformanceTimestamp();
|
||||
mtlFunc = [mtlLib newFunctionWithName: funcName];
|
||||
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
|
||||
}
|
||||
|
||||
startTime = _device->getPerformanceTimestamp();
|
||||
id<MTLFunction> mtlFunc = [mtlLib newFunctionWithName: funcName];
|
||||
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
|
||||
[mtlLib release]; // temp release
|
||||
|
||||
return mtlFunc;
|
||||
}
|
||||
}
|
||||
@ -436,11 +474,13 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newMTLRenderPipelineState(
|
||||
return rps;
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newMTLComputePipelineState(id<MTLFunction> mtlFunction,
|
||||
id<MTLComputePipelineState> MVKCommandResourceFactory::newMTLComputePipelineState(const char* funcName,
|
||||
MVKVulkanAPIDeviceObject* owner) {
|
||||
id<MTLFunction> mtlFunc = newFunctionNamed(funcName); // temp retain
|
||||
MVKComputePipelineCompiler* plc = new MVKComputePipelineCompiler(owner);
|
||||
id<MTLComputePipelineState> cps = plc->newMTLComputePipelineState(mtlFunction); // retained
|
||||
id<MTLComputePipelineState> cps = plc->newMTLComputePipelineState(mtlFunc); // retained
|
||||
plc->destroy();
|
||||
[mtlFunc release]; // temp release
|
||||
return cps;
|
||||
}
|
||||
|
||||
|
@ -282,13 +282,18 @@ public:
|
||||
#pragma mark Metal
|
||||
|
||||
/** Populates the specified structure with the Metal-specific features of this device. */
|
||||
const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; }
|
||||
inline const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; }
|
||||
|
||||
/** Returns the underlying Metal device. */
|
||||
inline id<MTLDevice> getMTLDevice() { return _mtlDevice; }
|
||||
|
||||
/*** Replaces the underlying Metal device .*/
|
||||
inline void replaceMTLDevice(id<MTLDevice> mtlDevice) { [_mtlDevice autorelease]; _mtlDevice = [mtlDevice retain]; }
|
||||
inline void replaceMTLDevice(id<MTLDevice> mtlDevice) {
|
||||
if (mtlDevice != _mtlDevice) {
|
||||
[_mtlDevice release];
|
||||
_mtlDevice = [mtlDevice retain];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Construction
|
||||
|
||||
@ -554,7 +559,7 @@ public:
|
||||
inline id<MTLDevice> getMTLDevice() { return _physicalDevice->getMTLDevice(); }
|
||||
|
||||
/** Returns standard compilation options to be used when compiling MSL shaders. */
|
||||
MTLCompileOptions* getMTLCompileOptions();
|
||||
inline MTLCompileOptions* getMTLCompileOptions() { return _mtlCompileOptions; }
|
||||
|
||||
/** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number. */
|
||||
uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding);
|
||||
@ -657,6 +662,7 @@ protected:
|
||||
void initPerformanceTracking();
|
||||
void initPhysicalDevice(MVKPhysicalDevice* physicalDevice);
|
||||
void initQueues(const VkDeviceCreateInfo* pCreateInfo);
|
||||
void initMTLCompileOptions();
|
||||
void enableFeatures(const VkDeviceCreateInfo* pCreateInfo);
|
||||
void enableFeatures(const VkBool32* pEnable, const VkBool32* pRequested, const VkBool32* pAvailable, uint32_t count);
|
||||
void enableExtensions(const VkDeviceCreateInfo* pCreateInfo);
|
||||
@ -667,6 +673,7 @@ protected:
|
||||
|
||||
MVKPhysicalDevice* _physicalDevice;
|
||||
MVKCommandResourceFactory* _commandResourceFactory;
|
||||
MTLCompileOptions* _mtlCompileOptions;
|
||||
std::vector<std::vector<MVKQueue*>> _queuesByQueueFamilyIndex;
|
||||
std::vector<MVKResource*> _resources;
|
||||
std::mutex _rezLock;
|
||||
|
@ -1711,9 +1711,11 @@ void MVKPhysicalDevice::logGPUInfo() {
|
||||
|
||||
#endif
|
||||
|
||||
MVKLogInfo(logMsg.c_str(), _properties.deviceName, devTypeStr.c_str(), _properties.vendorID, _properties.deviceID,
|
||||
[[[NSUUID alloc] initWithUUIDBytes: _properties.pipelineCacheUUID] autorelease].UUIDString.UTF8String,
|
||||
NSUUID* nsUUID = [[NSUUID alloc] initWithUUIDBytes: _properties.pipelineCacheUUID]; // temp retain
|
||||
MVKLogInfo(logMsg.c_str(), _properties.deviceName, devTypeStr.c_str(),
|
||||
_properties.vendorID, _properties.deviceID, nsUUID.UUIDString.UTF8String,
|
||||
SPIRVToMSLConversionOptions::printMSLVersion(_metalFeatures.mslVersion).c_str());
|
||||
[nsUUID release]; // temp release
|
||||
}
|
||||
|
||||
MVKPhysicalDevice::~MVKPhysicalDevice() {
|
||||
@ -2164,12 +2166,6 @@ void MVKDevice::getPerformanceStatistics(MVKPerformanceStatistics* pPerf) {
|
||||
|
||||
#pragma mark Metal
|
||||
|
||||
MTLCompileOptions* MVKDevice::getMTLCompileOptions() {
|
||||
MTLCompileOptions* opts = [[MTLCompileOptions new] autorelease];
|
||||
opts.languageVersion = _pMetalFeatures->mslVersionEnum;
|
||||
return opts;
|
||||
}
|
||||
|
||||
uint32_t MVKDevice::getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) {
|
||||
return ((_pMetalFeatures->maxPerStageBufferCount - 1) - binding);
|
||||
}
|
||||
@ -2240,6 +2236,8 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo
|
||||
_globalVisibilityResultMTLBuffer = nil;
|
||||
_globalVisibilityQueryCount = 0;
|
||||
|
||||
initMTLCompileOptions(); // Before command resource factory
|
||||
|
||||
_commandResourceFactory = new MVKCommandResourceFactory(this);
|
||||
|
||||
initQueues(pCreateInfo);
|
||||
@ -2451,12 +2449,19 @@ void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
void MVKDevice::initMTLCompileOptions() {
|
||||
_mtlCompileOptions = [MTLCompileOptions new]; // retained
|
||||
_mtlCompileOptions.languageVersion = _pMetalFeatures->mslVersionEnum;
|
||||
}
|
||||
|
||||
MVKDevice::~MVKDevice() {
|
||||
for (auto& queues : _queuesByQueueFamilyIndex) {
|
||||
mvkDestroyContainerContents(queues);
|
||||
}
|
||||
[_globalVisibilityResultMTLBuffer release];
|
||||
_commandResourceFactory->destroy();
|
||||
|
||||
[_mtlCompileOptions release];
|
||||
[_globalVisibilityResultMTLBuffer release];
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "MVKSync.h"
|
||||
#include "MVKVector.h"
|
||||
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
#import <IOSurface/IOSurfaceRef.h>
|
||||
@ -154,6 +155,9 @@ public:
|
||||
/** Returns the Metal texture underlying this image. */
|
||||
id<MTLTexture> getMTLTexture();
|
||||
|
||||
/** Returns a Metal texture that interprets the pixels in the specified format. */
|
||||
id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
|
||||
|
||||
/**
|
||||
* Sets this image to use the specified MTLTexture.
|
||||
*
|
||||
@ -243,7 +247,7 @@ protected:
|
||||
virtual id<MTLTexture> newMTLTexture();
|
||||
void resetMTLTexture();
|
||||
void resetIOSurface();
|
||||
MTLTextureDescriptor* getMTLTextureDescriptor();
|
||||
MTLTextureDescriptor* newMTLTextureDescriptor();
|
||||
void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
||||
void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
|
||||
bool shouldFlushHostMemory();
|
||||
@ -254,6 +258,7 @@ protected:
|
||||
VkImageMemoryBarrier* pImageMemoryBarrier);
|
||||
|
||||
std::vector<MVKImageSubresource> _subresources;
|
||||
std::unordered_map<NSUInteger, id<MTLTexture>> _mtlTextureViews;
|
||||
VkExtent3D _extent;
|
||||
uint32_t _mipLevels;
|
||||
uint32_t _arrayLayers;
|
||||
@ -376,7 +381,7 @@ public:
|
||||
|
||||
protected:
|
||||
void propogateDebugName() override {}
|
||||
MTLSamplerDescriptor* getMTLSamplerDescriptor(const VkSamplerCreateInfo* pCreateInfo);
|
||||
MTLSamplerDescriptor* newMTLSamplerDescriptor(const VkSamplerCreateInfo* pCreateInfo);
|
||||
void initConstExprSampler(const VkSamplerCreateInfo* pCreateInfo);
|
||||
|
||||
id<MTLSamplerState> _mtlSamplerState;
|
||||
|
@ -296,6 +296,22 @@ id<MTLTexture> MVKImage::getMTLTexture() {
|
||||
return _mtlTexture;
|
||||
}
|
||||
|
||||
id<MTLTexture> MVKImage::getMTLTexture(MTLPixelFormat mtlPixFmt) {
|
||||
if (mtlPixFmt == _mtlPixelFormat) { return getMTLTexture(); }
|
||||
|
||||
id<MTLTexture> mtlTex = _mtlTextureViews[mtlPixFmt];
|
||||
if ( !mtlTex ) {
|
||||
// Lock and check again in case another thread has created the texture.
|
||||
lock_guard<mutex> lock(_lock);
|
||||
mtlTex = _mtlTextureViews[mtlPixFmt];
|
||||
if ( !mtlTex ) {
|
||||
mtlTex = [getMTLTexture() newTextureViewWithPixelFormat: mtlPixFmt]; // retained
|
||||
_mtlTextureViews[mtlPixFmt] = mtlTex;
|
||||
}
|
||||
}
|
||||
return mtlTex;
|
||||
}
|
||||
|
||||
VkResult MVKImage::setMTLTexture(id<MTLTexture> mtlTexture) {
|
||||
lock_guard<mutex> lock(_lock);
|
||||
resetMTLTexture();
|
||||
@ -325,15 +341,21 @@ VkResult MVKImage::setMTLTexture(id<MTLTexture> mtlTexture) {
|
||||
// This implementation creates a new MTLTexture from a MTLTextureDescriptor and possible IOSurface.
|
||||
// Subclasses may override this function to create the MTLTexture in a different manner.
|
||||
id<MTLTexture> MVKImage::newMTLTexture() {
|
||||
if (_ioSurface) {
|
||||
return [getMTLDevice() newTextureWithDescriptor: getMTLTextureDescriptor() iosurface: _ioSurface plane: 0];
|
||||
id<MTLTexture> mtlTex = nil;
|
||||
MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor(); // temp retain
|
||||
|
||||
if (_ioSurface) {
|
||||
mtlTex = [getMTLDevice() newTextureWithDescriptor: mtlTexDesc iosurface: _ioSurface plane: 0];
|
||||
} else if (_usesTexelBuffer) {
|
||||
return [_deviceMemory->_mtlBuffer newTextureWithDescriptor: getMTLTextureDescriptor()
|
||||
offset: getDeviceMemoryOffset()
|
||||
bytesPerRow: _subresources[0].layout.rowPitch];
|
||||
} else {
|
||||
return [getMTLDevice() newTextureWithDescriptor: getMTLTextureDescriptor()];
|
||||
}
|
||||
mtlTex = [_deviceMemory->_mtlBuffer newTextureWithDescriptor: mtlTexDesc
|
||||
offset: getDeviceMemoryOffset()
|
||||
bytesPerRow: _subresources[0].layout.rowPitch];
|
||||
} else {
|
||||
mtlTex = [getMTLDevice() newTextureWithDescriptor: mtlTexDesc];
|
||||
}
|
||||
|
||||
[mtlTexDesc release]; // temp release
|
||||
return mtlTex;
|
||||
}
|
||||
|
||||
// Removes and releases the MTLTexture object, so that it can be lazily created by getMTLTexture().
|
||||
@ -420,9 +442,10 @@ MTLTextureUsage MVKImage::getMTLTextureUsage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
// Returns an autoreleased Metal texture descriptor constructed from the properties of this image.
|
||||
MTLTextureDescriptor* MVKImage::getMTLTextureDescriptor() {
|
||||
MTLTextureDescriptor* mtlTexDesc = [[MTLTextureDescriptor alloc] init];
|
||||
// Returns a Metal texture descriptor constructed from the properties of this image.
|
||||
// It is the caller's responsibility to release the returned descriptor object.
|
||||
MTLTextureDescriptor* MVKImage::newMTLTextureDescriptor() {
|
||||
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor new]; // retained
|
||||
#if MVK_MACOS
|
||||
if (_is3DCompressed) {
|
||||
// Metal doesn't yet support 3D compressed textures, so we'll decompress
|
||||
@ -445,7 +468,7 @@ MTLTextureDescriptor* MVKImage::getMTLTextureDescriptor() {
|
||||
mtlTexDesc.storageModeMVK = getMTLStorageMode();
|
||||
mtlTexDesc.cpuCacheMode = getMTLCPUCacheMode();
|
||||
|
||||
return [mtlTexDesc autorelease];
|
||||
return mtlTexDesc;
|
||||
}
|
||||
|
||||
MTLStorageMode MVKImage::getMTLStorageMode() {
|
||||
@ -772,6 +795,7 @@ MVKImage::~MVKImage() {
|
||||
if (_deviceMemory) { _deviceMemory->removeImage(this); }
|
||||
resetMTLTexture();
|
||||
resetIOSurface();
|
||||
for (auto elem : _mtlTextureViews) { [elem.second release]; }
|
||||
}
|
||||
|
||||
|
||||
@ -1058,10 +1082,11 @@ bool MVKSampler::getConstexprSampler(mvk::MSLResourceBinding& resourceBinding) {
|
||||
return _requiresConstExprSampler;
|
||||
}
|
||||
|
||||
// Returns an autoreleased Metal sampler descriptor constructed from the properties of this image.
|
||||
MTLSamplerDescriptor* MVKSampler::getMTLSamplerDescriptor(const VkSamplerCreateInfo* pCreateInfo) {
|
||||
// Returns an Metal sampler descriptor constructed from the properties of this image.
|
||||
// It is the caller's responsibility to release the returned descriptor object.
|
||||
MTLSamplerDescriptor* MVKSampler::newMTLSamplerDescriptor(const VkSamplerCreateInfo* pCreateInfo) {
|
||||
|
||||
MTLSamplerDescriptor* mtlSampDesc = [[MTLSamplerDescriptor alloc] init];
|
||||
MTLSamplerDescriptor* mtlSampDesc = [MTLSamplerDescriptor new]; // retained
|
||||
mtlSampDesc.sAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeU);
|
||||
mtlSampDesc.tAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeV);
|
||||
mtlSampDesc.rAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeW);
|
||||
@ -1099,12 +1124,16 @@ MTLSamplerDescriptor* MVKSampler::getMTLSamplerDescriptor(const VkSamplerCreateI
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return [mtlSampDesc autorelease];
|
||||
return mtlSampDesc;
|
||||
}
|
||||
|
||||
MVKSampler::MVKSampler(MVKDevice* device, const VkSamplerCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
|
||||
_requiresConstExprSampler = pCreateInfo->compareEnable && !_device->_pMetalFeatures->depthSampleCompare;
|
||||
_mtlSamplerState = [getMTLDevice() newSamplerStateWithDescriptor: getMTLSamplerDescriptor(pCreateInfo)];
|
||||
|
||||
MTLSamplerDescriptor* mtlSampDesc = newMTLSamplerDescriptor(pCreateInfo); // temp retain
|
||||
_mtlSamplerState = [getMTLDevice() newSamplerStateWithDescriptor: mtlSampDesc];
|
||||
[mtlSampDesc release]; // temp release
|
||||
|
||||
initConstExprSampler(pCreateInfo);
|
||||
}
|
||||
|
||||
|
@ -240,10 +240,10 @@ protected:
|
||||
void initMVKShaderConverterContext(SPIRVToMSLConversionConfiguration& _shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
void addVertexInputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo);
|
||||
void addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& outputs);
|
||||
MTLRenderPipelineDescriptor* getMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
MTLRenderPipelineDescriptor* getMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
MTLComputePipelineDescriptor* getMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
MTLRenderPipelineDescriptor* getMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
|
||||
MTLRenderPipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext);
|
||||
bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
|
||||
bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
|
||||
|
@ -206,7 +206,7 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
|
||||
id<MTLComputePipelineState> plState;
|
||||
const char* compilerType = "Tessellation control stage pipeline";
|
||||
const MVKIndexMTLBufferBinding& indexBuff = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
|
||||
MTLComputePipelineDescriptor* plDesc = [[_mtlTessControlStageDesc copy] autorelease]; // Use a copy to be thread-safe.
|
||||
MTLComputePipelineDescriptor* plDesc = [_mtlTessControlStageDesc copy]; // temp retain a copy to be thread-safe.
|
||||
if (!indexBuff.mtlBuffer && getInputControlPointCount() >= getOutputControlPointCount()) {
|
||||
plState = getOrCompilePipeline(plDesc, _mtlTessControlStageState, compilerType);
|
||||
} else if (indexBuff.mtlIndexType == MTLIndexTypeUInt16) {
|
||||
@ -218,6 +218,8 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
|
||||
plDesc.stageInputDescriptor.layouts[kMVKTessCtlInputBufferIndex].stepFunction = MTLStepFunctionThreadPositionInGridXIndexed;
|
||||
plState = getOrCompilePipeline(plDesc, _mtlTessControlStageIndex32State, compilerType);
|
||||
}
|
||||
[plDesc release]; // temp release
|
||||
|
||||
if ( !_hasValidMTLPipelineStates ) { return; }
|
||||
|
||||
id<MTLComputeCommandEncoder> tessCtlEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationControl);
|
||||
@ -426,10 +428,11 @@ void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCre
|
||||
_mtlPipelineState = nil;
|
||||
_mtlTessControlStageDesc = nil;
|
||||
if (!isTessellationPipeline()) {
|
||||
MTLRenderPipelineDescriptor* plDesc = getMTLRenderPipelineDescriptor(pCreateInfo, reflectData);
|
||||
MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData); // temp retain
|
||||
if (plDesc) {
|
||||
getOrCompilePipeline(plDesc, _mtlPipelineState);
|
||||
}
|
||||
[plDesc release]; // temp release
|
||||
} else {
|
||||
// In this case, we need to create three render pipelines. But, the way Metal handles
|
||||
// index buffers for compute stage-in means we have to defer creation of stage 2 until
|
||||
@ -437,24 +440,27 @@ void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCre
|
||||
SPIRVToMSLConversionConfiguration shaderContext;
|
||||
initMVKShaderConverterContext(shaderContext, pCreateInfo, reflectData);
|
||||
|
||||
MTLRenderPipelineDescriptor* vtxPLDesc = getMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderContext);
|
||||
_mtlTessControlStageDesc = getMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderContext); // retained
|
||||
MTLRenderPipelineDescriptor* rastPLDesc = getMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderContext);
|
||||
MTLRenderPipelineDescriptor* vtxPLDesc = newMTLTessVertexStageDescriptor(pCreateInfo, reflectData, shaderContext); // temp retain
|
||||
_mtlTessControlStageDesc = newMTLTessControlStageDescriptor(pCreateInfo, reflectData, shaderContext); // retained
|
||||
MTLRenderPipelineDescriptor* rastPLDesc = newMTLTessRasterStageDescriptor(pCreateInfo, reflectData, shaderContext); // temp retained
|
||||
if (vtxPLDesc && _mtlTessControlStageDesc && rastPLDesc) {
|
||||
if (getOrCompilePipeline(vtxPLDesc, _mtlTessVertexStageState)) {
|
||||
getOrCompilePipeline(rastPLDesc, _mtlPipelineState);
|
||||
}
|
||||
}
|
||||
[vtxPLDesc release]; // temp release
|
||||
[rastPLDesc release]; // temp release
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a MTLRenderPipelineDescriptor constructed from this instance, or nil if an error occurs.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
// Returns a retained MTLRenderPipelineDescriptor constructed from this instance, or nil if an error occurs.
|
||||
// It is the responsibility of the caller to release the returned descriptor.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
const SPIRVTessReflectionData& reflectData) {
|
||||
SPIRVToMSLConversionConfiguration shaderContext;
|
||||
initMVKShaderConverterContext(shaderContext, pCreateInfo, reflectData);
|
||||
|
||||
MTLRenderPipelineDescriptor* plDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained
|
||||
|
||||
// Add shader stages. Compile vertex shader before others just in case conversion changes anything...like rasterizaion disable.
|
||||
if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderContext)) { return nil; }
|
||||
@ -476,11 +482,12 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
return plDesc;
|
||||
}
|
||||
|
||||
// Returns a MTLRenderPipelineDescriptor for the vertex stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
// Returns a retained MTLRenderPipelineDescriptor for the vertex stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
// It is the responsibility of the caller to release the returned descriptor.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
const SPIRVTessReflectionData& reflectData,
|
||||
SPIRVToMSLConversionConfiguration& shaderContext) {
|
||||
MTLRenderPipelineDescriptor* plDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained
|
||||
|
||||
// Add shader stages.
|
||||
if (!addVertexShaderToPipeline(plDesc, pCreateInfo, shaderContext)) { return nil; }
|
||||
@ -587,11 +594,12 @@ static VkFormat mvkFormatFromOutput(const SPIRVShaderOutput& output) {
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
// Returns a MTLComputePipelineDescriptor for the tess. control stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
MTLComputePipelineDescriptor* MVKGraphicsPipeline::getMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
// Returns a retained MTLComputePipelineDescriptor for the tess. control stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
// It is the responsibility of the caller to release the returned descriptor.
|
||||
MTLComputePipelineDescriptor* MVKGraphicsPipeline::newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
const SPIRVTessReflectionData& reflectData,
|
||||
SPIRVToMSLConversionConfiguration& shaderContext) {
|
||||
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new];
|
||||
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained
|
||||
|
||||
std::vector<SPIRVShaderOutput> vtxOutputs;
|
||||
std::string errorLog;
|
||||
@ -634,11 +642,12 @@ MTLComputePipelineDescriptor* MVKGraphicsPipeline::getMTLTessControlStageDescrip
|
||||
return plDesc;
|
||||
}
|
||||
|
||||
// Returns a MTLRenderPipelineDescriptor for the last stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
// Returns a retained MTLRenderPipelineDescriptor for the last stage of a tessellated draw constructed from this instance, or nil if an error occurs.
|
||||
// It is the responsibility of the caller to release the returned descriptor.
|
||||
MTLRenderPipelineDescriptor* MVKGraphicsPipeline::newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo,
|
||||
const SPIRVTessReflectionData& reflectData,
|
||||
SPIRVToMSLConversionConfiguration& shaderContext) {
|
||||
MTLRenderPipelineDescriptor* plDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained
|
||||
|
||||
std::vector<SPIRVShaderOutput> tcOutputs;
|
||||
std::string errorLog;
|
||||
@ -775,11 +784,12 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
|
||||
addVertexInputToShaderConverterContext(shaderContext, pCreateInfo);
|
||||
|
||||
MVKMTLFunction func = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderContext, _pVertexSS->pSpecializationInfo, _pipelineCache);
|
||||
if ( !func.mtlFunction ) {
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
if ( !mtlFunc ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader function could not be compiled into pipeline. See previous logged error."));
|
||||
return false;
|
||||
}
|
||||
plDesc.vertexFunction = func.mtlFunction;
|
||||
plDesc.vertexFunction = mtlFunc;
|
||||
|
||||
auto& funcRslts = func.shaderConversionResults;
|
||||
plDesc.rasterizationEnabled = !funcRslts.isRasterizationDisabled;
|
||||
@ -821,11 +831,12 @@ bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescripto
|
||||
addPrevStageOutputToShaderConverterContext(shaderContext, vtxOutputs);
|
||||
|
||||
MVKMTLFunction func = ((MVKShaderModule*)_pTessCtlSS->module)->getMTLFunction(&shaderContext, _pTessCtlSS->pSpecializationInfo, _pipelineCache);
|
||||
if ( !func.mtlFunction ) {
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
if ( !mtlFunc ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader function could not be compiled into pipeline. See previous logged error."));
|
||||
return false;
|
||||
}
|
||||
plDesc.computeFunction = func.mtlFunction;
|
||||
plDesc.computeFunction = mtlFunc;
|
||||
|
||||
auto& funcRslts = func.shaderConversionResults;
|
||||
_needsTessCtlSwizzleBuffer = funcRslts.needsSwizzleBuffer;
|
||||
@ -870,12 +881,13 @@ bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescripto
|
||||
addPrevStageOutputToShaderConverterContext(shaderContext, tcOutputs);
|
||||
|
||||
MVKMTLFunction func = ((MVKShaderModule*)_pTessEvalSS->module)->getMTLFunction(&shaderContext, _pTessEvalSS->pSpecializationInfo, _pipelineCache);
|
||||
if ( !func.mtlFunction ) {
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
if ( !mtlFunc ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation evaluation shader function could not be compiled into pipeline. See previous logged error."));
|
||||
return false;
|
||||
}
|
||||
// Yeah, you read that right. Tess. eval functions are a kind of vertex function in Metal.
|
||||
plDesc.vertexFunction = func.mtlFunction;
|
||||
plDesc.vertexFunction = mtlFunc;
|
||||
|
||||
auto& funcRslts = func.shaderConversionResults;
|
||||
plDesc.rasterizationEnabled = !funcRslts.isRasterizationDisabled;
|
||||
@ -902,11 +914,12 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto
|
||||
shaderContext.options.mslOptions.capture_output_to_buffer = false;
|
||||
|
||||
MVKMTLFunction func = ((MVKShaderModule*)_pFragmentSS->module)->getMTLFunction(&shaderContext, _pFragmentSS->pSpecializationInfo, _pipelineCache);
|
||||
if ( !func.mtlFunction ) {
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
if ( !mtlFunc ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Fragment shader function could not be compiled into pipeline. See previous logged error."));
|
||||
return false;
|
||||
}
|
||||
plDesc.fragmentFunction = func.mtlFunction;
|
||||
plDesc.fragmentFunction = mtlFunc;
|
||||
|
||||
auto& funcRslts = func.shaderConversionResults;
|
||||
_needsFragmentSwizzleBuffer = funcRslts.needsSwizzleBuffer;
|
||||
@ -1281,13 +1294,14 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
|
||||
const VkComputePipelineCreateInfo* pCreateInfo) :
|
||||
MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, parent) {
|
||||
|
||||
MVKMTLFunction shaderFunc = getMTLFunction(pCreateInfo);
|
||||
_mtlThreadgroupSize = shaderFunc.threadGroupSize;
|
||||
MVKMTLFunction func = getMTLFunction(pCreateInfo);
|
||||
_mtlThreadgroupSize = func.threadGroupSize;
|
||||
_mtlPipelineState = nil;
|
||||
|
||||
if (shaderFunc.mtlFunction) {
|
||||
MTLComputePipelineDescriptor* plDesc = [[MTLComputePipelineDescriptor new] autorelease];
|
||||
plDesc.computeFunction = shaderFunc.mtlFunction;
|
||||
id<MTLFunction> mtlFunc = func.getMTLFunction();
|
||||
if (mtlFunc) {
|
||||
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // temp retain
|
||||
plDesc.computeFunction = mtlFunc;
|
||||
|
||||
// Metal does not allow the name of the pipeline to be changed after it has been created,
|
||||
// and we need to create the Metal pipeline immediately to provide error feedback to app.
|
||||
@ -1297,6 +1311,8 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
|
||||
MVKComputePipelineCompiler* plc = new MVKComputePipelineCompiler(this);
|
||||
_mtlPipelineState = plc->newMTLComputePipelineState(plDesc); // retained
|
||||
plc->destroy();
|
||||
[plDesc release]; // temp release
|
||||
|
||||
if ( !_mtlPipelineState ) { _hasValidMTLPipelineStates = false; }
|
||||
} else {
|
||||
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader function could not be compiled into pipeline. See previous logged error."));
|
||||
|
@ -65,13 +65,13 @@ void MVKQueue::propogateDebugName() { setLabelIfNotNil(_mtlQueue, _debugName); }
|
||||
|
||||
#pragma mark Queue submissions
|
||||
|
||||
// Execute the queue submission under an autorelease pool to ensure transient Metal objects are autoreleased.
|
||||
// Execute the queue submission under an autoreleasepool to ensure transient Metal objects are autoreleased.
|
||||
// This is critical for apps that don't use standard OS autoreleasing runloop threading.
|
||||
static inline void execute(MVKQueueSubmission* qSubmit) { @autoreleasepool { qSubmit->execute(); } }
|
||||
|
||||
// Executes the submmission, either immediately, or by dispatching to an execution queue.
|
||||
// Submissions to the execution queue are wrapped in a dedicated autorelease pool.
|
||||
// Relying on the dispatch queue to find time to drain the autorelease pool can
|
||||
// Submissions to the execution queue are wrapped in a dedicated autoreleasepool.
|
||||
// Relying on the dispatch queue to find time to drain the autoreleasepool can
|
||||
// result in significant memory creep under heavy workloads.
|
||||
VkResult MVKQueue::submit(MVKQueueSubmission* qSubmit) {
|
||||
if ( !qSubmit ) { return VK_SUCCESS; } // Ignore nils
|
||||
|
@ -39,14 +39,22 @@ using namespace mvk;
|
||||
#pragma mark MVKShaderLibrary
|
||||
|
||||
/** A MTLFunction and corresponding result information resulting from a shader conversion. */
|
||||
typedef struct {
|
||||
id<MTLFunction> mtlFunction;
|
||||
const SPIRVToMSLConversionResults shaderConversionResults;
|
||||
typedef struct MVKMTLFunction {
|
||||
SPIRVToMSLConversionResults shaderConversionResults;
|
||||
MTLSize threadGroupSize;
|
||||
inline id<MTLFunction> getMTLFunction() { return _mtlFunction; }
|
||||
|
||||
MVKMTLFunction(id<MTLFunction> mtlFunc, const SPIRVToMSLConversionResults scRslts, MTLSize tgSize);
|
||||
MVKMTLFunction(const MVKMTLFunction& other);
|
||||
~MVKMTLFunction();
|
||||
|
||||
private:
|
||||
id<MTLFunction> _mtlFunction;
|
||||
|
||||
} MVKMTLFunction;
|
||||
|
||||
/** A MVKMTLFunction indicating an invalid MTLFunction. The mtlFunction member is nil. */
|
||||
extern const MVKMTLFunction MVKMTLFunctionNull;
|
||||
const MVKMTLFunction MVKMTLFunctionNull(nil, SPIRVToMSLConversionResults(), MTLSizeMake(1, 1, 1));
|
||||
|
||||
/** Wraps a single MTLLibrary. */
|
||||
class MVKShaderLibrary : public MVKBaseObject {
|
||||
@ -85,7 +93,7 @@ public:
|
||||
size_t mslCompiledCodeLength);
|
||||
|
||||
/** Copy constructor. */
|
||||
MVKShaderLibrary(MVKShaderLibrary& other);
|
||||
MVKShaderLibrary(const MVKShaderLibrary& other);
|
||||
|
||||
~MVKShaderLibrary() override;
|
||||
|
||||
|
@ -26,7 +26,22 @@
|
||||
using namespace std;
|
||||
|
||||
|
||||
const MVKMTLFunction MVKMTLFunctionNull = { nil, SPIRVToMSLConversionResults(), MTLSizeMake(1, 1, 1) };
|
||||
MVKMTLFunction::MVKMTLFunction(id<MTLFunction> mtlFunc, const SPIRVToMSLConversionResults scRslts, MTLSize tgSize) {
|
||||
_mtlFunction = [mtlFunc retain]; // retained
|
||||
shaderConversionResults = scRslts;
|
||||
threadGroupSize = tgSize;
|
||||
}
|
||||
|
||||
MVKMTLFunction::MVKMTLFunction(const MVKMTLFunction& other) {
|
||||
_mtlFunction = [other._mtlFunction retain]; // retained
|
||||
shaderConversionResults = other.shaderConversionResults;
|
||||
threadGroupSize = other.threadGroupSize;
|
||||
}
|
||||
|
||||
MVKMTLFunction::~MVKMTLFunction() {
|
||||
[_mtlFunction release];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKShaderLibrary
|
||||
@ -54,7 +69,7 @@ MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpe
|
||||
NSString* mtlFuncName = @(_shaderConversionResults.entryPoint.mtlFunctionName.c_str());
|
||||
MVKDevice* mvkDev = _owner->getDevice();
|
||||
uint64_t startTime = mvkDev->getPerformanceTimestamp();
|
||||
mtlFunc = [_mtlLibrary newFunctionWithName: mtlFuncName]; // retained
|
||||
mtlFunc = [_mtlLibrary newFunctionWithName: mtlFuncName]; // temp retain
|
||||
mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.functionRetrieval, startTime);
|
||||
|
||||
if (mtlFunc) {
|
||||
@ -84,9 +99,10 @@ MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpe
|
||||
|
||||
// Compile the specialized Metal function, and use it instead of the unspecialized Metal function.
|
||||
MVKFunctionSpecializer* fs = new MVKFunctionSpecializer(_owner);
|
||||
mtlFunc = fs->newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals); // retained
|
||||
[mtlFunc release]; // temp release
|
||||
mtlFunc = fs->newMTLFunction(_mtlLibrary, mtlFuncName, mtlFCVals); // temp retain
|
||||
fs->destroy();
|
||||
[mtlFCVals release]; // release temp
|
||||
[mtlFCVals release]; // temp release
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -100,9 +116,13 @@ MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpe
|
||||
}
|
||||
|
||||
auto& wgSize = _shaderConversionResults.entryPoint.workgroupSize;
|
||||
return { [mtlFunc autorelease], _shaderConversionResults, MTLSizeMake(getWorkgroupDimensionSize(wgSize.width, pSpecializationInfo),
|
||||
getWorkgroupDimensionSize(wgSize.height, pSpecializationInfo),
|
||||
getWorkgroupDimensionSize(wgSize.depth, pSpecializationInfo))};
|
||||
|
||||
MVKMTLFunction mvkMTLFunc(mtlFunc, _shaderConversionResults, MTLSizeMake(getWorkgroupDimensionSize(wgSize.width, pSpecializationInfo),
|
||||
getWorkgroupDimensionSize(wgSize.height, pSpecializationInfo),
|
||||
getWorkgroupDimensionSize(wgSize.depth, pSpecializationInfo)));
|
||||
[mtlFunc release]; // temp release
|
||||
|
||||
return mvkMTLFunc;
|
||||
}
|
||||
|
||||
// Returns the MTLFunctionConstant with the specified ID from the specified array of function constants.
|
||||
@ -156,7 +176,7 @@ MVKShaderLibrary::MVKShaderLibrary(MVKVulkanAPIDeviceObject* owner,
|
||||
mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.mslLoad, startTime);
|
||||
}
|
||||
|
||||
MVKShaderLibrary::MVKShaderLibrary(MVKShaderLibrary& other) : _owner(other._owner) {
|
||||
MVKShaderLibrary::MVKShaderLibrary(const MVKShaderLibrary& other) : _owner(other._owner) {
|
||||
_mtlLibrary = [other._mtlLibrary retain];
|
||||
_shaderConversionResults = other._shaderConversionResults;
|
||||
_msl = other._msl;
|
||||
|
@ -75,7 +75,7 @@ id<MTLRenderPipelineState> MVKWatermark::mtlRenderPipelineState() {
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> MVKWatermark::newRenderPipelineState() {
|
||||
MTLRenderPipelineDescriptor* plDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // temp retained
|
||||
plDesc.label = _mtlName;
|
||||
|
||||
plDesc.vertexFunction = _mtlFunctionVertex;
|
||||
@ -128,7 +128,8 @@ id<MTLRenderPipelineState> MVKWatermark::newRenderPipelineState() {
|
||||
NSError* err = nil;
|
||||
id<MTLRenderPipelineState> rps = [_mtlDevice newRenderPipelineStateWithDescriptor: plDesc error: &err]; // retained
|
||||
MVKAssert( !err, "Could not create watermark pipeline state (Error code %li)\n%s", (long)err.code, err.localizedDescription.UTF8String);
|
||||
return rps;
|
||||
[plDesc release]; // temp released
|
||||
return rps;
|
||||
}
|
||||
|
||||
|
||||
@ -296,23 +297,26 @@ void MVKWatermark::initTexture(unsigned char* textureContent,
|
||||
bytesPerRow: textureBytesPerRow
|
||||
bytesPerImage: 0];
|
||||
|
||||
MTLSamplerDescriptor* sampDesc = [[MTLSamplerDescriptor new] autorelease];
|
||||
MTLSamplerDescriptor* sampDesc = [MTLSamplerDescriptor new]; // temp retained
|
||||
sampDesc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
_mtlSamplerState = [_mtlDevice newSamplerStateWithDescriptor: sampDesc]; // retained
|
||||
_mtlSamplerState = [_mtlDevice newSamplerStateWithDescriptor: sampDesc]; // retained
|
||||
[sampDesc release]; // temp released
|
||||
}
|
||||
|
||||
// Initialize the shader functions for rendering the watermark
|
||||
void MVKWatermark::initShaders(const char* mslSourceCode) {
|
||||
NSError* err = nil;
|
||||
NSString* nsSrc = [[NSString alloc] initWithUTF8String: mslSourceCode]; // temp retained
|
||||
id<MTLLibrary> mtlLib = [[_mtlDevice newLibraryWithSource: nsSrc
|
||||
options: nil
|
||||
error: &err] autorelease];
|
||||
[nsSrc release]; // release temp string
|
||||
id<MTLLibrary> mtlLib = [_mtlDevice newLibraryWithSource: nsSrc
|
||||
options: nil
|
||||
error: &err]; // temp retained
|
||||
MVKAssert( !err, "Could not compile watermark shaders (Error code %li):\n%s", (long)err.code, err.localizedDescription.UTF8String);
|
||||
|
||||
_mtlFunctionVertex = [mtlLib newFunctionWithName: @"watermarkVertex"]; // retained
|
||||
_mtlFunctionFragment = [mtlLib newFunctionWithName: @"watermarkFragment"]; // retained
|
||||
|
||||
[nsSrc release]; // temp released
|
||||
[mtlLib release]; // temp released
|
||||
}
|
||||
|
||||
// Initialize the vertex buffers to use for rendering the watermark
|
||||
|
13
README.md
13
README.md
@ -317,6 +317,19 @@ encumbrances. In submitting code to this repository, you are agreeing that the c
|
||||
Property claims.
|
||||
|
||||
|
||||
### Memory Management
|
||||
|
||||
*Metal*, and other *Objective-C* objects in *Apple's SDK* frameworks, use reference counting for memory management.
|
||||
When instantiating *Objective-C* objects, it is important that you do not rely on implied *autorelease pools* to do
|
||||
memory management for you. Because many *Vulkan* games and apps may be ported from other platforms, they will
|
||||
typically not include autorelease pools in their threading models.
|
||||
|
||||
Avoid the use of the `autorelease` method, or any object creation methods that imply use of `autorelease`,
|
||||
(eg- `[NSString stringWithFormat: ]`, etc). Instead, favour object creation methods that return a retained object
|
||||
(eg- `[[NSString alloc] initWithFormat: ]`, etc), and manually track and release those objects. If you need to use
|
||||
autoreleased objects, wrap code blocks in an `@autoreleasepool {...}` block.
|
||||
|
||||
|
||||
### Code Formatting
|
||||
|
||||
When contributing code, please honour the code formatting style found in existing **MoltenVK** source code.
|
||||
|
Loading…
x
Reference in New Issue
Block a user