blob: 346c0b26a78925904e5792e51d85420f2904609d [file] [log] [blame]
/*
* MVKCommandEncodingPool.mm
*
* Copyright (c) 2015-2022 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MVKCommandEncodingPool.h"
#include "MVKCommandPool.h"
#include "MVKImage.h"
using namespace std;
#pragma mark -
#pragma mark MVKCommandEncodingPool
MVKVulkanAPIObject* MVKCommandEncodingPool::getVulkanAPIObject() { return _commandPool->getVulkanAPIObject(); };
// In order to provide thread-safety with minimal performance impact, each of these access
// functions follows a 3-step pattern:
//
// 1) Retrieve resource without locking, and if it exists, return it.
// 2) If it doesn't exist, lock, then test again if it exists, and if it does, return it.
// 3) If it still does not exist, create and cache the resource, and return it.
//
// Step 1 handles the common case where the resource exists, without the expense of a lock.
// Step 2 guards against a potential race condition where two threads get past Step 1 at
// the same time, and then both barrel ahead onto Step 3.
#define MVK_ENC_REZ_ACCESS(rezAccess, rezFactoryFunc) \
auto rez = rezAccess; \
if (rez) { return rez; } \
\
lock_guard<mutex> lock(_lock); \
rez = rezAccess; \
if (rez) { return rez; } \
\
rez = _commandPool->getDevice()->getCommandResourceFactory()->rezFactoryFunc; \
rezAccess = rez; \
return rez
id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey) {
MVK_ENC_REZ_ACCESS(_cmdClearMTLRenderPipelineStates[attKey], newCmdClearMTLRenderPipelineState(attKey, _commandPool));
}
id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey) {
MVK_ENC_REZ_ACCESS(_cmdBlitImageMTLRenderPipelineStates[blitKey], newCmdBlitImageMTLRenderPipelineState(blitKey, _commandPool));
}
id<MTLDepthStencilState> MVKCommandEncodingPool::getMTLDepthStencilState(bool useDepth, bool useStencil) {
if (useDepth && useStencil) {
MVK_ENC_REZ_ACCESS(_cmdClearDepthAndStencilDepthStencilState, newMTLDepthStencilState(useDepth, useStencil));
}
if (useDepth) {
MVK_ENC_REZ_ACCESS(_cmdClearDepthOnlyDepthStencilState, newMTLDepthStencilState(useDepth, useStencil));
}
if (useStencil) {
MVK_ENC_REZ_ACCESS(_cmdClearStencilOnlyDepthStencilState, newMTLDepthStencilState(useDepth, useStencil));
}
MVK_ENC_REZ_ACCESS(_cmdClearDefaultDepthStencilState, newMTLDepthStencilState(useDepth, useStencil));
}
MVKMTLBufferAllocation* MVKCommandEncodingPool::acquireMTLBufferAllocation(NSUInteger length, bool isPrivate, bool isDedicated) {
MVKAssert(isPrivate || !isDedicated, "Dedicated, host-shared temporary buffers are not supported.");
if (isDedicated) {
return _dedicatedMtlBufferAllocator.acquireMTLBufferRegion(length);
}
if (isPrivate) {
return _privateMtlBufferAllocator.acquireMTLBufferRegion(length);
}
return _mtlBufferAllocator.acquireMTLBufferRegion(length);
}
id<MTLDepthStencilState> MVKCommandEncodingPool::getMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) {
MVK_ENC_REZ_ACCESS(_mtlDepthStencilStates[dsData], newMTLDepthStencilState(dsData));
}
MVKImage* MVKCommandEncodingPool::getTransferMVKImage(MVKImageDescriptorData& imgData) {
MVK_ENC_REZ_ACCESS(_transferImages[imgData], newMVKImage(imgData));
}
MVKBuffer* MVKCommandEncodingPool::getTransferMVKBuffer(MVKBufferDescriptorData& buffData) {
MVK_ENC_REZ_ACCESS(_transferBuffers[buffData], newMVKBuffer(buffData, _transferBufferMemory[buffData]));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdCopyBufferBytesMTLComputePipelineState() {
MVK_ENC_REZ_ACCESS(_mtlCopyBufferBytesComputePipelineState, newCmdCopyBufferBytesMTLComputePipelineState(_commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdFillBufferMTLComputePipelineState() {
MVK_ENC_REZ_ACCESS(_mtlFillBufferComputePipelineState, newCmdFillBufferMTLComputePipelineState(_commandPool));
}
static inline uint32_t getRenderpassLoadStoreStateIndex(MVKFormatType type) {
switch (type) {
case kMVKFormatColorHalf:
case kMVKFormatColorFloat:
return 0;
case kMVKFormatColorInt8:
case kMVKFormatColorInt16:
case kMVKFormatColorInt32:
return 1;
case kMVKFormatColorUInt8:
case kMVKFormatColorUInt16:
case kMVKFormatColorUInt32:
return 2;
default:
return 0;
}
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdClearColorImageMTLComputePipelineState(MVKFormatType type) {
MVK_ENC_REZ_ACCESS(_mtlClearColorImageComputePipelineState[getRenderpassLoadStoreStateIndex(type)], newCmdClearColorImageMTLComputePipelineState(type, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdResolveColorImageMTLComputePipelineState(MVKFormatType type) {
MVK_ENC_REZ_ACCESS(_mtlResolveColorImageComputePipelineState[getRenderpassLoadStoreStateIndex(type)], newCmdResolveColorImageMTLComputePipelineState(type, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff) {
MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed) {
MVK_ENC_REZ_ACCESS(_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(indexed, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed) {
MVK_ENC_REZ_ACCESS(_mtlDrawIndirectTessConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(indexed, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type) {
MVK_ENC_REZ_ACCESS(_mtlDrawIndexedCopyIndexBufferComputePipelineState[type == MTLIndexTypeUInt16 ? 1 : 0], newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(type, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdCopyQueryPoolResultsMTLComputePipelineState() {
MVK_ENC_REZ_ACCESS(_mtlCopyQueryPoolResultsComputePipelineState, newCmdCopyQueryPoolResultsMTLComputePipelineState(_commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getAccumulateOcclusionQueryResultsMTLComputePipelineState() {
MVK_ENC_REZ_ACCESS(_mtlAccumOcclusionQueryResultsComputePipelineState, newAccumulateOcclusionQueryResultsMTLComputePipelineState(_commandPool));
}
void MVKCommandEncodingPool::clear() {
lock_guard<mutex> lock(_lock);
destroyMetalResources();
}
#pragma mark Construction
MVKCommandEncodingPool::MVKCommandEncodingPool(MVKCommandPool* commandPool) : _commandPool(commandPool),
_mtlBufferAllocator(commandPool->getDevice(), commandPool->getDevice()->_pMetalFeatures->maxMTLBufferSize, true),
_privateMtlBufferAllocator(commandPool->getDevice(), commandPool->getDevice()->_pMetalFeatures->maxMTLBufferSize, true, false, MTLStorageModePrivate),
_dedicatedMtlBufferAllocator(commandPool->getDevice(), commandPool->getDevice()->_pMetalFeatures->maxQueryBufferSize, true, true, MTLStorageModePrivate) {
}
MVKCommandEncodingPool::~MVKCommandEncodingPool() {
destroyMetalResources();
}
/** Ensure all cached Metal components are released. */
void MVKCommandEncodingPool::destroyMetalResources() {
MVKDevice* mvkDev = _commandPool->getDevice();
for (auto& pair : _cmdBlitImageMTLRenderPipelineStates) { [pair.second release]; }
_cmdBlitImageMTLRenderPipelineStates.clear();
for (auto& pair : _cmdClearMTLRenderPipelineStates) { [pair.second release]; }
_cmdClearMTLRenderPipelineStates.clear();
for (auto& pair : _mtlDepthStencilStates) { [pair.second release]; }
_mtlDepthStencilStates.clear();
for (auto& pair : _transferImages) { mvkDev->destroyImage(pair.second, nullptr); }
_transferImages.clear();
for (auto& pair : _transferBuffers) { mvkDev->destroyBuffer(pair.second, nullptr); }
_transferBuffers.clear();
for (auto& pair : _transferBufferMemory) { mvkDev->freeMemory(pair.second, nullptr); }
_transferBufferMemory.clear();
[_cmdClearDepthAndStencilDepthStencilState release];
_cmdClearDepthAndStencilDepthStencilState = nil;
[_cmdClearDepthOnlyDepthStencilState release];
_cmdClearDepthOnlyDepthStencilState = nil;
[_cmdClearStencilOnlyDepthStencilState release];
_cmdClearStencilOnlyDepthStencilState = nil;
[_cmdClearDefaultDepthStencilState release];
_cmdClearDefaultDepthStencilState = nil;
[_mtlCopyBufferBytesComputePipelineState release];
_mtlCopyBufferBytesComputePipelineState = nil;
[_mtlFillBufferComputePipelineState release];
_mtlFillBufferComputePipelineState = nil;
[_mtlClearColorImageComputePipelineState[0] release];
[_mtlClearColorImageComputePipelineState[1] release];
[_mtlClearColorImageComputePipelineState[2] release];
_mtlClearColorImageComputePipelineState[0] = nil;
_mtlClearColorImageComputePipelineState[1] = nil;
_mtlClearColorImageComputePipelineState[2] = nil;
[_mtlResolveColorImageComputePipelineState[0] release];
[_mtlResolveColorImageComputePipelineState[1] release];
[_mtlResolveColorImageComputePipelineState[2] release];
_mtlResolveColorImageComputePipelineState[0] = nil;
_mtlResolveColorImageComputePipelineState[1] = nil;
_mtlResolveColorImageComputePipelineState[2] = nil;
[_mtlCopyBufferToImage3DDecompressComputePipelineState[0] release];
[_mtlCopyBufferToImage3DDecompressComputePipelineState[1] release];
_mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil;
_mtlCopyBufferToImage3DDecompressComputePipelineState[1] = nil;
[_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] release];
[_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] release];
_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] = nil;
_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] = nil;
[_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] release];
[_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] release];
_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] = nil;
_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] = nil;
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[0] release];
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[1] release];
_mtlDrawIndexedCopyIndexBufferComputePipelineState[0] = nil;
_mtlDrawIndexedCopyIndexBufferComputePipelineState[1] = nil;
[_mtlCopyQueryPoolResultsComputePipelineState release];
_mtlCopyQueryPoolResultsComputePipelineState = nil;
[_mtlAccumOcclusionQueryResultsComputePipelineState release];
_mtlAccumOcclusionQueryResultsComputePipelineState = nil;
}