123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- /*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
- #include "include/gpu/GrContext.h"
- #include "src/gpu/GrContextPriv.h"
- #include "src/gpu/mtl/GrMtlGpu.h"
- #include "src/gpu/mtl/GrMtlPipelineState.h"
- #include "src/gpu/mtl/GrMtlUtil.h"
- #include "src/gpu/GrRenderTargetPriv.h"
- #import <simd/simd.h>
- #if !__has_feature(objc_arc)
- #error This file must be compiled with Arc. Use -fobjc-arc flag
- #endif
- GrMtlPipelineState* GrMtlPipelineStateBuilder::CreatePipelineState(
- GrMtlGpu* gpu,
- GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
- const GrPrimitiveProcessor& primProc,
- const GrTextureProxy* const primProcProxies[],
- const GrPipeline& pipeline,
- Desc* desc) {
- GrMtlPipelineStateBuilder builder(gpu, renderTarget, origin, pipeline, primProc,
- primProcProxies, desc);
- if (!builder.emitAndInstallProcs()) {
- return nullptr;
- }
- return builder.finalize(renderTarget, primProc, pipeline, desc);
- }
- GrMtlPipelineStateBuilder::GrMtlPipelineStateBuilder(GrMtlGpu* gpu,
- GrRenderTarget* renderTarget,
- GrSurfaceOrigin origin,
- const GrPipeline& pipeline,
- const GrPrimitiveProcessor& primProc,
- const GrTextureProxy* const primProcProxies[],
- GrProgramDesc* desc)
- : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
- , fGpu(gpu)
- , fUniformHandler(this)
- , fVaryingHandler(this) {
- }
- const GrCaps* GrMtlPipelineStateBuilder::caps() const {
- return fGpu->caps();
- }
- void GrMtlPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) {
- outputColor.addLayoutQualifier("location = 0, index = 0");
- }
- void GrMtlPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
- outputColor.addLayoutQualifier("location = 0, index = 1");
- }
- id<MTLLibrary> GrMtlPipelineStateBuilder::createMtlShaderLibrary(
- const GrGLSLShaderBuilder& builder,
- SkSL::Program::Kind kind,
- const SkSL::Program::Settings& settings,
- GrProgramDesc* desc) {
- SkSL::Program::Inputs inputs;
- id<MTLLibrary> shaderLibrary = GrCompileMtlShaderLibrary(fGpu, builder.fCompilerString.c_str(),
- kind, settings, &inputs);
- if (shaderLibrary == nil) {
- return nil;
- }
- if (inputs.fRTHeight) {
- this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
- }
- return shaderLibrary;
- }
- static inline MTLVertexFormat attribute_type_to_mtlformat(GrVertexAttribType type) {
- // All half types will actually be float types. We are currently not using half types with
- // metal to avoid an issue with narrow type coercions (float->half) http://skbug.com/8221
- switch (type) {
- case kFloat_GrVertexAttribType:
- return MTLVertexFormatFloat;
- case kFloat2_GrVertexAttribType:
- return MTLVertexFormatFloat2;
- case kFloat3_GrVertexAttribType:
- return MTLVertexFormatFloat3;
- case kFloat4_GrVertexAttribType:
- return MTLVertexFormatFloat4;
- case kHalf_GrVertexAttribType:
- return MTLVertexFormatHalf;
- case kHalf2_GrVertexAttribType:
- return MTLVertexFormatHalf2;
- case kHalf3_GrVertexAttribType:
- return MTLVertexFormatHalf3;
- case kHalf4_GrVertexAttribType:
- return MTLVertexFormatHalf4;
- case kInt2_GrVertexAttribType:
- return MTLVertexFormatInt2;
- case kInt3_GrVertexAttribType:
- return MTLVertexFormatInt3;
- case kInt4_GrVertexAttribType:
- return MTLVertexFormatInt4;
- case kByte_GrVertexAttribType:
- return MTLVertexFormatChar;
- case kByte2_GrVertexAttribType:
- return MTLVertexFormatChar2;
- case kByte3_GrVertexAttribType:
- return MTLVertexFormatChar3;
- case kByte4_GrVertexAttribType:
- return MTLVertexFormatChar4;
- case kUByte_GrVertexAttribType:
- return MTLVertexFormatUChar;
- case kUByte2_GrVertexAttribType:
- return MTLVertexFormatUChar2;
- case kUByte3_GrVertexAttribType:
- return MTLVertexFormatUChar3;
- case kUByte4_GrVertexAttribType:
- return MTLVertexFormatUChar4;
- case kUByte_norm_GrVertexAttribType:
- return MTLVertexFormatUCharNormalized;
- case kUByte4_norm_GrVertexAttribType:
- return MTLVertexFormatUChar4Normalized;
- case kShort2_GrVertexAttribType:
- return MTLVertexFormatShort2;
- case kShort4_GrVertexAttribType:
- return MTLVertexFormatShort4;
- case kUShort2_GrVertexAttribType:
- return MTLVertexFormatUShort2;
- case kUShort2_norm_GrVertexAttribType:
- return MTLVertexFormatUShort2Normalized;
- case kInt_GrVertexAttribType:
- return MTLVertexFormatInt;
- case kUint_GrVertexAttribType:
- return MTLVertexFormatUInt;
- case kUShort_norm_GrVertexAttribType:
- return MTLVertexFormatUShortNormalized;
- // Experimental (for Y416)
- case kUShort4_norm_GrVertexAttribType:
- return MTLVertexFormatUShort4Normalized;
- }
- SK_ABORT("Unknown vertex attribute type");
- return MTLVertexFormatInvalid;
- }
- static MTLVertexDescriptor* create_vertex_descriptor(const GrPrimitiveProcessor& primProc) {
- uint32_t vertexBinding = 0, instanceBinding = 0;
- int nextBinding = GrMtlUniformHandler::kLastUniformBinding + 1;
- if (primProc.hasVertexAttributes()) {
- vertexBinding = nextBinding++;
- }
- if (primProc.hasInstanceAttributes()) {
- instanceBinding = nextBinding;
- }
- auto vertexDescriptor = [[MTLVertexDescriptor alloc] init];
- int attributeIndex = 0;
- int vertexAttributeCount = primProc.numVertexAttributes();
- size_t vertexAttributeOffset = 0;
- for (const auto& attribute : primProc.vertexAttributes()) {
- MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
- mtlAttribute.format = attribute_type_to_mtlformat(attribute.cpuType());
- mtlAttribute.offset = vertexAttributeOffset;
- mtlAttribute.bufferIndex = vertexBinding;
- vertexAttributeOffset += attribute.sizeAlign4();
- attributeIndex++;
- }
- SkASSERT(vertexAttributeOffset == primProc.vertexStride());
- if (vertexAttributeCount) {
- MTLVertexBufferLayoutDescriptor* vertexBufferLayout =
- vertexDescriptor.layouts[vertexBinding];
- vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex;
- vertexBufferLayout.stepRate = 1;
- vertexBufferLayout.stride = vertexAttributeOffset;
- }
- int instanceAttributeCount = primProc.numInstanceAttributes();
- size_t instanceAttributeOffset = 0;
- for (const auto& attribute : primProc.instanceAttributes()) {
- MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
- mtlAttribute.format = attribute_type_to_mtlformat(attribute.cpuType());
- mtlAttribute.offset = instanceAttributeOffset;
- mtlAttribute.bufferIndex = instanceBinding;
- instanceAttributeOffset += attribute.sizeAlign4();
- attributeIndex++;
- }
- SkASSERT(instanceAttributeOffset == primProc.instanceStride());
- if (instanceAttributeCount) {
- MTLVertexBufferLayoutDescriptor* instanceBufferLayout =
- vertexDescriptor.layouts[instanceBinding];
- instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance;
- instanceBufferLayout.stepRate = 1;
- instanceBufferLayout.stride = instanceAttributeOffset;
- }
- return vertexDescriptor;
- }
- static MTLBlendFactor blend_coeff_to_mtl_blend(GrBlendCoeff coeff) {
- static const MTLBlendFactor gTable[] = {
- MTLBlendFactorZero, // kZero_GrBlendCoeff
- MTLBlendFactorOne, // kOne_GrBlendCoeff
- MTLBlendFactorSourceColor, // kSC_GrBlendCoeff
- MTLBlendFactorOneMinusSourceColor, // kISC_GrBlendCoeff
- MTLBlendFactorDestinationColor, // kDC_GrBlendCoeff
- MTLBlendFactorOneMinusDestinationColor, // kIDC_GrBlendCoeff
- MTLBlendFactorSourceAlpha, // kSA_GrBlendCoeff
- MTLBlendFactorOneMinusSourceAlpha, // kISA_GrBlendCoeff
- MTLBlendFactorDestinationAlpha, // kDA_GrBlendCoeff
- MTLBlendFactorOneMinusDestinationAlpha, // kIDA_GrBlendCoeff
- MTLBlendFactorBlendColor, // kConstC_GrBlendCoeff
- MTLBlendFactorOneMinusBlendColor, // kIConstC_GrBlendCoeff
- MTLBlendFactorBlendAlpha, // kConstA_GrBlendCoeff
- MTLBlendFactorOneMinusBlendAlpha, // kIConstA_GrBlendCoeff
- MTLBlendFactorSource1Color, // kS2C_GrBlendCoeff
- MTLBlendFactorOneMinusSource1Color, // kIS2C_GrBlendCoeff
- MTLBlendFactorSource1Alpha, // kS2A_GrBlendCoeff
- MTLBlendFactorOneMinusSource1Alpha, // kIS2A_GrBlendCoeff
- MTLBlendFactorZero, // kIllegal_GrBlendCoeff
- };
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrBlendCoeffCnt);
- GR_STATIC_ASSERT(0 == kZero_GrBlendCoeff);
- GR_STATIC_ASSERT(1 == kOne_GrBlendCoeff);
- GR_STATIC_ASSERT(2 == kSC_GrBlendCoeff);
- GR_STATIC_ASSERT(3 == kISC_GrBlendCoeff);
- GR_STATIC_ASSERT(4 == kDC_GrBlendCoeff);
- GR_STATIC_ASSERT(5 == kIDC_GrBlendCoeff);
- GR_STATIC_ASSERT(6 == kSA_GrBlendCoeff);
- GR_STATIC_ASSERT(7 == kISA_GrBlendCoeff);
- GR_STATIC_ASSERT(8 == kDA_GrBlendCoeff);
- GR_STATIC_ASSERT(9 == kIDA_GrBlendCoeff);
- GR_STATIC_ASSERT(10 == kConstC_GrBlendCoeff);
- GR_STATIC_ASSERT(11 == kIConstC_GrBlendCoeff);
- GR_STATIC_ASSERT(12 == kConstA_GrBlendCoeff);
- GR_STATIC_ASSERT(13 == kIConstA_GrBlendCoeff);
- GR_STATIC_ASSERT(14 == kS2C_GrBlendCoeff);
- GR_STATIC_ASSERT(15 == kIS2C_GrBlendCoeff);
- GR_STATIC_ASSERT(16 == kS2A_GrBlendCoeff);
- GR_STATIC_ASSERT(17 == kIS2A_GrBlendCoeff);
- SkASSERT((unsigned)coeff < kGrBlendCoeffCnt);
- return gTable[coeff];
- }
- static MTLBlendOperation blend_equation_to_mtl_blend_op(GrBlendEquation equation) {
- static const MTLBlendOperation gTable[] = {
- MTLBlendOperationAdd, // kAdd_GrBlendEquation
- MTLBlendOperationSubtract, // kSubtract_GrBlendEquation
- MTLBlendOperationReverseSubtract, // kReverseSubtract_GrBlendEquation
- };
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kFirstAdvancedGrBlendEquation);
- GR_STATIC_ASSERT(0 == kAdd_GrBlendEquation);
- GR_STATIC_ASSERT(1 == kSubtract_GrBlendEquation);
- GR_STATIC_ASSERT(2 == kReverseSubtract_GrBlendEquation);
- SkASSERT((unsigned)equation < kGrBlendEquationCnt);
- return gTable[equation];
- }
- static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
- GrPixelConfig config, const GrPipeline& pipeline) {
- auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
- // pixel format
- MTLPixelFormat format;
- SkAssertResult(GrPixelConfigToMTLFormat(config, &format));
- mtlColorAttachment.pixelFormat = format;
- // blending
- const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo();
- GrBlendEquation equation = blendInfo.fEquation;
- GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
- GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
- bool blendOff = (kAdd_GrBlendEquation == equation || kSubtract_GrBlendEquation == equation) &&
- kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
- mtlColorAttachment.blendingEnabled = !blendOff;
- if (!blendOff) {
- mtlColorAttachment.sourceRGBBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
- mtlColorAttachment.destinationRGBBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
- mtlColorAttachment.rgbBlendOperation = blend_equation_to_mtl_blend_op(equation);
- mtlColorAttachment.sourceAlphaBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
- mtlColorAttachment.destinationAlphaBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
- mtlColorAttachment.alphaBlendOperation = blend_equation_to_mtl_blend_op(equation);
- }
- if (!blendInfo.fWriteColor) {
- mtlColorAttachment.writeMask = MTLColorWriteMaskNone;
- } else {
- mtlColorAttachment.writeMask = MTLColorWriteMaskAll;
- }
- return mtlColorAttachment;
- }
- uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment) {
- // Metal expects the buffer to be padded at the end according to the alignment
- // of the largest element in the buffer.
- uint32_t offsetDiff = offset & maxAlignment;
- if (offsetDiff != 0) {
- offsetDiff = maxAlignment - offsetDiff + 1;
- }
- return offset + offsetDiff;
- }
- GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTarget,
- const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- Desc* desc) {
- auto pipelineDescriptor = [MTLRenderPipelineDescriptor new];
- fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
- fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
- fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
- fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
- this->finalizeShaders();
- SkSL::Program::Settings settings;
- settings.fCaps = this->caps()->shaderCaps();
- settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
- settings.fSharpenTextures = fGpu->getContext()->priv().options().fSharpenMipmappedTextures;
- SkASSERT(!this->fragColorIsInOut());
- // TODO: Store shaders in cache
- id<MTLLibrary> vertexLibrary = nil;
- id<MTLLibrary> fragmentLibrary = nil;
- vertexLibrary = this->createMtlShaderLibrary(fVS,
- SkSL::Program::kVertex_Kind,
- settings,
- desc);
- fragmentLibrary = this->createMtlShaderLibrary(fFS,
- SkSL::Program::kFragment_Kind,
- settings,
- desc);
- SkASSERT(!this->primitiveProcessor().willUseGeoShader());
- if (!vertexLibrary || !fragmentLibrary) {
- return nullptr;
- }
- id<MTLFunction> vertexFunction = [vertexLibrary newFunctionWithName: @"vertexMain"];
- id<MTLFunction> fragmentFunction = [fragmentLibrary newFunctionWithName: @"fragmentMain"];
- if (vertexFunction == nil) {
- SkDebugf("Couldn't find vertexMain() in library\n");
- return nullptr;
- }
- if (fragmentFunction == nil) {
- SkDebugf("Couldn't find fragmentMain() in library\n");
- return nullptr;
- }
- pipelineDescriptor.vertexFunction = vertexFunction;
- pipelineDescriptor.fragmentFunction = fragmentFunction;
- pipelineDescriptor.vertexDescriptor = create_vertex_descriptor(primProc);
- pipelineDescriptor.colorAttachments[0] = create_color_attachment(this->config(), pipeline);
- pipelineDescriptor.sampleCount = renderTarget->numSamples();
- bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
- GrMtlCaps* mtlCaps = (GrMtlCaps*)this->caps();
- pipelineDescriptor.stencilAttachmentPixelFormat =
- hasStencilAttachment ? mtlCaps->preferredStencilFormat().fInternalFormat
- : MTLPixelFormatInvalid;
- SkASSERT(pipelineDescriptor.vertexFunction);
- SkASSERT(pipelineDescriptor.fragmentFunction);
- SkASSERT(pipelineDescriptor.vertexDescriptor);
- SkASSERT(pipelineDescriptor.colorAttachments[0]);
- #if defined(SK_BUILD_FOR_MAC) && defined(GR_USE_COMPLETION_HANDLER)
- bool timedout;
- id<MTLRenderPipelineState> pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
- fGpu->device(), pipelineDescriptor, &timedout);
- if (timedout) {
- // try a second time
- pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
- fGpu->device(), pipelineDescriptor, &timedout);
- }
- if (!pipelineState) {
- return nullptr;
- }
- #else
- NSError* error = nil;
- id<MTLRenderPipelineState> pipelineState =
- [fGpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor
- error: &error];
- if (error) {
- SkDebugf("Error creating pipeline: %s\n",
- [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
- return nullptr;
- }
- #endif
- uint32_t geomBufferSize = buffer_size(fUniformHandler.fCurrentGeometryUBOOffset,
- fUniformHandler.fCurrentGeometryUBOMaxAlignment);
- uint32_t fragBufferSize = buffer_size(fUniformHandler.fCurrentFragmentUBOOffset,
- fUniformHandler.fCurrentFragmentUBOMaxAlignment);
- return new GrMtlPipelineState(fGpu,
- pipelineState,
- pipelineDescriptor.colorAttachments[0].pixelFormat,
- fUniformHandles,
- fUniformHandler.fUniforms,
- geomBufferSize,
- fragBufferSize,
- (uint32_t)fUniformHandler.numSamplers(),
- std::move(fGeometryProcessor),
- std::move(fXferProcessor),
- std::move(fFragmentProcessors),
- fFragmentProcessorCnt);
- }
- //////////////////////////////////////////////////////////////////////////////
- bool GrMtlPipelineStateBuilder::Desc::Build(Desc* desc,
- GrRenderTarget* renderTarget,
- const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- GrPrimitiveType primitiveType,
- GrMtlGpu* gpu) {
- if (!INHERITED::Build(desc, renderTarget, primProc,
- GrPrimitiveType::kLines == primitiveType, pipeline, gpu)) {
- return false;
- }
- GrProcessorKeyBuilder b(&desc->key());
- int keyLength = desc->key().count();
- SkASSERT(0 == (keyLength % 4));
- desc->fShaderKeyLength = SkToU32(keyLength);
- b.add32(renderTarget->config());
- b.add32(renderTarget->numSamples());
- bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
- b.add32(hasStencilAttachment ? gpu->mtlCaps().preferredStencilFormat().fInternalFormat
- : MTLPixelFormatInvalid);
- b.add32((uint32_t)pipeline.isStencilEnabled());
- // Stencil samples don't seem to be tracked in the MTLRenderPipeline
- b.add32(pipeline.getBlendInfoKey());
- b.add32((uint32_t)primitiveType);
- return true;
- }
|