blob: a09a6ab7383877f205a1ea2c986327e6f782d3fa [file] [log] [blame]
/*
* MVKCommandResourceFactory.mm
*
* Copyright (c) 2014-2018 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 "MVKCommandResourceFactory.h"
#include "MVKCommandPipelineStateFactoryShaderSource.h"
#include "MVKFoundation.h"
#include "mvk_datatypes.h"
#include "MVKLogging.h"
using namespace std;
#pragma mark -
#pragma mark MVKCommandResourceFactory
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt) {
bool isDepthFormat = mvkMTLPixelFormatIsDepthFormat(mtlPixFmt);
string fragFuncSfx = getFragFunctionSuffix(mtlPixFmt);
MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
plDesc.label = [NSString stringWithFormat: @"CmdBlitImage%s-%lu", fragFuncSfx.data(), (unsigned long)mtlPixFmt];
plDesc.vertexFunction = getFunctionNamed(isDepthFormat ? "vtxCmdBlitImageD" : "vtxCmdBlitImage");
plDesc.fragmentFunction = getFunctionNamed((string("fragCmdBlitImage") + fragFuncSfx).data());
if ( isDepthFormat ) {
plDesc.depthAttachmentPixelFormat = mtlPixFmt;
} else {
MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[0];
colorDesc.pixelFormat = mtlPixFmt;
}
MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor;
// Vertex attribute descriptors
MTLVertexAttributeDescriptorArray* vaDescArray = vtxDesc.attributes;
MTLVertexAttributeDescriptor* vaDesc;
NSUInteger vtxBuffIdx = _device->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
NSUInteger vtxStride = 0;
// Vertex location
vaDesc = vaDescArray[0];
vaDesc.format = MTLVertexFormatFloat2;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
vtxStride += sizeof(simd::float2);
// Vertex texture coords
vaDesc = vaDescArray[1];
vaDesc.format = MTLVertexFormatFloat2;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
vtxStride += sizeof(simd::float2);
// Vertex attribute buffer.
MTLVertexBufferLayoutDescriptorArray* vbDescArray = vtxDesc.layouts;
MTLVertexBufferLayoutDescriptor* vbDesc = vbDescArray[vtxBuffIdx];
vbDesc.stepFunction = MTLVertexStepFunctionPerVertex;
vbDesc.stepRate = 1;
vbDesc.stride = vtxStride;
return newMTLRenderPipelineState(plDesc);
}
id<MTLSamplerState> MVKCommandResourceFactory::newCmdBlitImageMTLSamplerState(MTLSamplerMinMagFilter mtlFilter) {
MTLSamplerDescriptor* sDesc = [[[MTLSamplerDescriptor alloc] init] autorelease];
sDesc.rAddressMode = MTLSamplerAddressModeClampToZero;
sDesc.sAddressMode = MTLSamplerAddressModeClampToZero;
sDesc.tAddressMode = MTLSamplerAddressModeClampToZero;
sDesc.mipFilter = MTLSamplerMipFilterNotMipmapped;
sDesc.normalizedCoordinates = YES;
sDesc.minFilter = mtlFilter;
sDesc.magFilter = mtlFilter;
return [getMTLDevice() newSamplerStateWithDescriptor: sDesc];
}
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey) {
string fragFuncSfx = getFragFunctionSuffix(attKey);
MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
plDesc.label = [NSString stringWithFormat: @"CmdClearAttachments%s", fragFuncSfx.data()];
plDesc.vertexFunction = getFunctionNamed("vtxCmdClearAttachments");
plDesc.fragmentFunction = getFunctionNamed((string("fragCmdClearAttachments") + fragFuncSfx).data());
plDesc.sampleCount = attKey.mtlSampleCount;
for (uint32_t caIdx = 0; caIdx < kMVKAttachmentFormatDepthStencilIndex; caIdx++) {
MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx];
colorDesc.pixelFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[caIdx];
colorDesc.writeMask = attKey.isEnabled(caIdx) ? MTLColorWriteMaskAll : MTLColorWriteMaskNone;
}
MTLPixelFormat mtlDSFormat = (MTLPixelFormat)attKey.attachmentMTLPixelFormats[kMVKAttachmentFormatDepthStencilIndex];
if (mvkMTLPixelFormatIsDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; }
if (mvkMTLPixelFormatIsStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; }
MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor;
// Vertex attribute descriptors
MTLVertexAttributeDescriptorArray* vaDescArray = vtxDesc.attributes;
MTLVertexAttributeDescriptor* vaDesc;
NSUInteger vtxBuffIdx = _device->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
NSUInteger vtxStride = 0;
// Vertex location
vaDesc = vaDescArray[0];
vaDesc.format = MTLVertexFormatFloat2;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
vtxStride += sizeof(simd::float2);
// Vertex attribute buffer.
MTLVertexBufferLayoutDescriptorArray* vbDescArray = vtxDesc.layouts;
MTLVertexBufferLayoutDescriptor* vbDesc = vbDescArray[vtxBuffIdx];
vbDesc.stepFunction = MTLVertexStepFunctionPerVertex;
vbDesc.stepRate = 1;
vbDesc.stride = vtxStride;
return newMTLRenderPipelineState(plDesc);
}
id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(bool useDepth, bool useStencil) {
MTLDepthStencilDescriptor* dsDesc = [[[MTLDepthStencilDescriptor alloc] init] autorelease];
dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
dsDesc.depthWriteEnabled = useDepth;
if (useStencil) {
MTLStencilDescriptor* sDesc = [[[MTLStencilDescriptor alloc] init] autorelease];
sDesc.stencilCompareFunction = MTLCompareFunctionAlways;
sDesc.stencilFailureOperation = MTLStencilOperationReplace;
sDesc.depthFailureOperation = MTLStencilOperationReplace;
sDesc.depthStencilPassOperation = MTLStencilOperationReplace;
dsDesc.frontFaceStencil = sDesc;
dsDesc.backFaceStencil = sDesc;
} else {
dsDesc.frontFaceStencil = nil;
dsDesc.backFaceStencil = nil;
}
return [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
}
id<MTLDepthStencilState> MVKCommandResourceFactory::newMTLDepthStencilState(MVKMTLDepthStencilDescriptorData& dsData) {
MTLDepthStencilDescriptor* dsDesc = [[[MTLDepthStencilDescriptor alloc] init] autorelease];
dsDesc.depthCompareFunction = (MTLCompareFunction)dsData.depthCompareFunction;
dsDesc.depthWriteEnabled = dsData.depthWriteEnabled;
dsDesc.frontFaceStencil = getMTLStencilDescriptor(dsData.frontFaceStencilData);
dsDesc.backFaceStencil = getMTLStencilDescriptor(dsData.backFaceStencilData);
return [getMTLDevice() newDepthStencilStateWithDescriptor: dsDesc];
}
MTLStencilDescriptor* MVKCommandResourceFactory::getMTLStencilDescriptor(MVKMTLStencilDescriptorData& sData) {
if ( !sData.enabled ) { return nil; }
MTLStencilDescriptor* sDesc = [[[MTLStencilDescriptor alloc] init] autorelease];
sDesc.stencilCompareFunction = (MTLCompareFunction)sData.stencilCompareFunction;
sDesc.stencilFailureOperation = (MTLStencilOperation)sData.stencilFailureOperation;
sDesc.depthFailureOperation = (MTLStencilOperation)sData.depthFailureOperation;
sDesc.depthStencilPassOperation = (MTLStencilOperation)sData.depthStencilPassOperation;
sDesc.readMask = sData.readMask;
sDesc.writeMask = sData.writeMask;
return sDesc;
}
MVKImage* MVKCommandResourceFactory::newMVKImage(MVKImageDescriptorData& imgData) {
const VkImageCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.imageType = imgData.imageType,
.format = imgData.format,
.extent = imgData.extent,
.mipLevels = imgData.mipLevels,
.arrayLayers = imgData.arrayLayers,
.samples = imgData.samples,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = imgData.usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
};
return _device->createImage(&createInfo, nullptr);
}
string MVKCommandResourceFactory::getFragFunctionSuffix(MTLPixelFormat mtlPixFmt) {
switch (mvkFormatTypeFromMTLPixelFormat(mtlPixFmt)) {
case kMVKFormatDepthStencil: return "DS";
case kMVKFormatColorUInt: return "U";
case kMVKFormatColorInt: return "I";
default: return "F";
}
}
string MVKCommandResourceFactory::getFragFunctionSuffix(MVKRPSKeyClearAtt& attKey) {
string suffix;
if (attKey.isEnabledOnly(0)) { suffix += "0"; }
suffix += getFragFunctionSuffix((MTLPixelFormat)attKey.attachmentMTLPixelFormats[0]);
return suffix;
}
id<MTLFunction> MVKCommandResourceFactory::getFunctionNamed(const char* funcName) {
uint64_t startTime = _device->getPerformanceTimestamp();
id<MTLFunction> mtlFunc = [[_mtlLibrary newFunctionWithName: @(funcName)] autorelease];
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.functionRetrieval, startTime);
return mtlFunc;
}
id<MTLRenderPipelineState> MVKCommandResourceFactory::newMTLRenderPipelineState(MTLRenderPipelineDescriptor* plDesc) {
uint64_t startTime = _device->getPerformanceTimestamp();
NSError* err = nil;
id<MTLRenderPipelineState> rps = [getMTLDevice() newRenderPipelineStateWithDescriptor: plDesc error: &err]; // retained
MVKAssert( !err, "Could not create %s pipeline state: %s (code %li) %s", plDesc.label.UTF8String, err.localizedDescription.UTF8String, (long)err.code, err.localizedFailureReason.UTF8String);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.pipelineCompile, startTime);
return rps;
}
id<MTLComputePipelineState> MVKCommandResourceFactory::newCopyBytesMTLComputePipelineState() {
MTLComputePipelineDescriptor* plDesc = [[[MTLComputePipelineDescriptor alloc] init] autorelease];
plDesc.computeFunction = getFunctionNamed("compCopyBufferBytes");
plDesc.buffers[0].mutability = MTLMutabilityMutable;
plDesc.buffers[1].mutability = MTLMutabilityMutable;
NSError* err = nil;
id<MTLComputePipelineState> computePipelineState = [getMTLDevice() newComputePipelineStateWithDescriptor:plDesc options:MTLPipelineOptionNone reflection:nil error:&err];
MVKAssert( !err, "Could not create %s pipeline state: %s (code %li) %s", plDesc.label.UTF8String, err.localizedDescription.UTF8String, (long)err.code, err.localizedFailureReason.UTF8String);
return computePipelineState;
}
#pragma mark Construction
MVKCommandResourceFactory::MVKCommandResourceFactory(MVKDevice* device) : MVKBaseDeviceObject(device) {
initMTLLibrary();
}
/** Initializes the Metal shaders used for command activity. */
void MVKCommandResourceFactory::initMTLLibrary() {
uint64_t startTime = _device->getPerformanceTimestamp();
@autoreleasepool {
MTLCompileOptions* shdrOpts = [[MTLCompileOptions new] autorelease];
NSError* err = nil;
_mtlLibrary = [getMTLDevice() newLibraryWithSource: @(_MVKStaticCmdShaderSource)
options: shdrOpts
error: &err]; // retained
MVKAssert( !err, "Could not compile command shaders %s (code %li) %s", err.localizedDescription.UTF8String, (long)err.code, err.localizedFailureReason.UTF8String);
}
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime);
}
MVKCommandResourceFactory::~MVKCommandResourceFactory() {
[_mtlLibrary release];
_mtlLibrary = nil;
}