src/ngfx/porting/metal/MTLGraphicsPipeline.mm
Source code
/*
* Copyright 2020 GoPro Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "ngfx/porting/metal/MTLGraphicsPipeline.h"
#include "ngfx/porting/metal/MTLPipelineUtil.h"
#include "ngfx/porting/metal/MTLShaderModule.h"
#include "ngfx/porting/metal/MTLGraphicsContext.h"
#include "ngfx/porting/metal/MTLCommandBuffer.h"
#include "ngfx/porting/metal/MTLRenderCommandEncoder.h"
#include "ngfx/core/DebugUtil.h"
using namespace ngfx;
void MTLGraphicsPipeline::create(MTLGraphicsContext* ctx, const State& state, MTLVertexDescriptor* vertexDescriptor,
const Shaders& shaders, ::MTLPixelFormat colorFormat, ::MTLPixelFormat depthFormat) {
NSError* error;
auto device = ctx->mtlDevice.v;
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [MTLRenderPipelineDescriptor new];
pipelineStateDescriptor.label = @"";
pipelineStateDescriptor.vertexFunction = shaders.VS;
pipelineStateDescriptor.fragmentFunction = shaders.PS;
for (uint32_t j = 0; j<state.numColorAttachments; j++) {
auto colorAttachment = pipelineStateDescriptor.colorAttachments[j];
colorAttachment.pixelFormat = colorFormat;
colorAttachment.blendingEnabled = state.blendEnable;
colorAttachment.sourceRGBBlendFactor = ::MTLBlendFactor(state.srcColorBlendFactor);
colorAttachment.sourceAlphaBlendFactor = ::MTLBlendFactor(state.srcAlphaBlendFactor);
colorAttachment.destinationRGBBlendFactor = ::MTLBlendFactor(state.dstColorBlendFactor);
colorAttachment.destinationAlphaBlendFactor = ::MTLBlendFactor(state.dstAlphaBlendFactor);
colorAttachment.rgbBlendOperation = ::MTLBlendOperation(state.colorBlendOp);
colorAttachment.alphaBlendOperation = ::MTLBlendOperation(state.alphaBlendOp);
colorAttachment.writeMask = state.colorWriteMask;
}
pipelineStateDescriptor.rasterSampleCount = state.numSamples;
pipelineStateDescriptor.vertexDescriptor = vertexDescriptor;
pipelineStateDescriptor.depthAttachmentPixelFormat = depthFormat;
const std::vector<MTLPixelFormat> stencilFormats = {
MTLPixelFormatStencil8 ,MTLPixelFormatDepth24Unorm_Stencil8,
MTLPixelFormatDepth32Float_Stencil8,
};
if (std::find(stencilFormats.begin(), stencilFormats.end(), depthFormat) != stencilFormats.end()) {
pipelineStateDescriptor.stencilAttachmentPixelFormat = depthFormat;
}
MTLPipelineOption options = MTLPipelineOptionArgumentInfo | MTLPipelineOptionBufferTypeInfo;
mtlPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor options:options reflection:&reflection error:&error];
[pipelineStateDescriptor release];
NSCAssert(mtlPipelineState, @"Failed to create pipeline state: %@", error);
mtlPrimitiveType = ::MTLPrimitiveType(state.primitiveTopology);
mtlCullMode = ::MTLCullMode(state.cullModeFlags);
mtlFrontFaceWinding = ::MTLWinding(state.frontFace);
if (state.depthTestEnable) {
MTLDepthStencilDescriptor *depthStencilDesc = [[MTLDepthStencilDescriptor alloc] init];
depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess;
depthStencilDesc.depthWriteEnabled = state.depthWriteEnable;
mtlDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc];
}
}
GraphicsPipeline* GraphicsPipeline::create(GraphicsContext* ctx, const GraphicsPipeline::State &state,
VertexShaderModule* vs, FragmentShaderModule* fs, PixelFormat colorFormat, PixelFormat depthFormat,
std::set<std::string> instanceAttributes) {
MTLGraphicsPipeline* mtlGraphicsPipeline = new MTLGraphicsPipeline();
auto& descriptorBindings = mtlGraphicsPipeline->descriptorBindings;
MTLPipelineUtil::parseDescriptors(vs->descriptors, descriptorBindings);
MTLPipelineUtil::parseDescriptors(fs->descriptors, descriptorBindings);
uint32_t numVSDescriptors = vs->descriptors.size();
MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor new];
auto& vertexAttributeBindings = mtlGraphicsPipeline->vertexAttributeBindings;
vertexAttributeBindings.resize(vs->attributes.size());
for (uint32_t j = 0; j<vs->attributes.size(); j++) {
auto& attr = vs->attributes[j];
auto mtlAttr = vertexDescriptor.attributes[attr.location - numVSDescriptors];
mtlAttr.bufferIndex = attr.location;
auto mtlLayout = vertexDescriptor.layouts[mtlAttr.bufferIndex];
uint32_t stride = attr.elementSize;
auto mtlVertexFormat = attr.format;
mtlAttr.format = ::MTLVertexFormat(mtlVertexFormat);
mtlAttr.offset = 0;
mtlLayout.stride = stride;
if (instanceAttributes.find(attr.name) != instanceAttributes.end())
mtlLayout.stepFunction = MTLVertexStepFunctionPerInstance;
vertexAttributeBindings[j] = attr.location;
}
MTLGraphicsPipeline::Shaders shaders;
shaders.VS = mtl(vs)->mtlFunction;
shaders.PS = mtl(fs)->mtlFunction;
mtlGraphicsPipeline->create(mtl(ctx), state, vertexDescriptor, shaders, ::MTLPixelFormat(colorFormat),
::MTLPixelFormat(depthFormat));
[vertexDescriptor release];
return mtlGraphicsPipeline;
}
Updated on 3 April 2021 at 20:21:51 PDT