• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrMtlPipelineState.h"
9
10#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrPipeline.h"
13#include "GrRenderTarget.h"
14#include "GrRenderTargetPriv.h"
15#include "GrTexturePriv.h"
16#include "GrMtlBuffer.h"
17#include "GrMtlGpu.h"
18#include "GrMtlSampler.h"
19#include "GrMtlTexture.h"
20#include "glsl/GrGLSLFragmentProcessor.h"
21#include "glsl/GrGLSLGeometryProcessor.h"
22#include "glsl/GrGLSLXferProcessor.h"
23
24GrMtlPipelineState::SamplerBindings::SamplerBindings(const GrSamplerState& state,
25                                                     GrTexture* texture,
26                                                     GrMtlGpu* gpu)
27        : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) {
28    // TODO: use resource provider to get sampler.
29    std::unique_ptr<GrMtlSampler> sampler(
30            GrMtlSampler::Create(gpu, state, texture->texturePriv().maxMipMapLevel()));
31    fSampler = sampler->mtlSamplerState();
32}
33
34GrMtlPipelineState::GrMtlPipelineState(
35        GrMtlGpu* gpu,
36        id<MTLRenderPipelineState> pipelineState,
37        MTLPixelFormat pixelFormat,
38        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
39        const UniformInfoArray& uniforms,
40        sk_sp<GrMtlBuffer> geometryUniformBuffer,
41        sk_sp<GrMtlBuffer> fragmentUniformBuffer,
42        uint32_t numSamplers,
43        std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
44        std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
45        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
46        int fragmentProcessorCnt)
47        : fGpu(gpu)
48        , fPipelineState(pipelineState)
49        , fPixelFormat(pixelFormat)
50        , fBuiltinUniformHandles(builtinUniformHandles)
51        , fGeometryUniformBuffer(std::move(geometryUniformBuffer))
52        , fFragmentUniformBuffer(std::move(fragmentUniformBuffer))
53        , fNumSamplers(numSamplers)
54        , fGeometryProcessor(std::move(geometryProcessor))
55        , fXferProcessor(std::move(xferProcessor))
56        , fFragmentProcessors(std::move(fragmentProcessors))
57        , fFragmentProcessorCnt(fragmentProcessorCnt)
58        , fDataManager(uniforms, fGeometryUniformBuffer->sizeInBytes(),
59                       fFragmentUniformBuffer->sizeInBytes()) {
60    (void) fPixelFormat; // Suppress unused-var warning.
61}
62
63void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget,
64                                 GrSurfaceOrigin origin,
65                                 const GrPrimitiveProcessor& primProc,
66                                 const GrPipeline& pipeline,
67                                 const GrTextureProxy* const primProcTextures[]) {
68    SkASSERT(primProcTextures || !primProc.numTextureSamplers());
69
70    this->setRenderTargetState(renderTarget, origin);
71    fGeometryProcessor->setData(fDataManager, primProc,
72                                GrFragmentProcessor::CoordTransformIter(pipeline));
73    fSamplerBindings.reset();
74    for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
75        const auto& sampler = primProc.textureSampler(i);
76        auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture());
77        fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
78    }
79
80    GrFragmentProcessor::Iter iter(pipeline);
81    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
82    const GrFragmentProcessor* fp = iter.next();
83    GrGLSLFragmentProcessor* glslFP = glslIter.next();
84    while (fp && glslFP) {
85        glslFP->setData(fDataManager, *fp);
86        for (int i = 0; i < fp->numTextureSamplers(); ++i) {
87            const auto& sampler = fp->textureSampler(i);
88            fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
89        }
90        fp = iter.next();
91        glslFP = glslIter.next();
92    }
93    SkASSERT(!fp && !glslFP);
94
95    {
96        SkIPoint offset;
97        GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
98
99        fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
100    }
101
102    if (GrTextureProxy* dstTextureProxy = pipeline.dstTextureProxy()) {
103        fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(),
104                                      dstTextureProxy->peekTexture(),
105                                      fGpu);
106    }
107
108    SkASSERT(fNumSamplers == fSamplerBindings.count());
109    if (fGeometryUniformBuffer || fFragmentUniformBuffer) {
110        fDataManager.uploadUniformBuffers(fGpu, fGeometryUniformBuffer.get(),
111                                          fFragmentUniformBuffer.get());
112    }
113
114    if (pipeline.isStencilEnabled()) {
115        SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment());
116        fStencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
117                       renderTarget->renderTargetPriv().numStencilBits());
118    }
119}
120
121void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) {
122    if (fGeometryUniformBuffer) {
123        [renderCmdEncoder setVertexBuffer: fGeometryUniformBuffer->mtlBuffer()
124                                   offset: 0
125                                  atIndex: GrMtlUniformHandler::kGeometryBinding];
126    }
127    if (fFragmentUniformBuffer) {
128        [renderCmdEncoder setFragmentBuffer: fFragmentUniformBuffer->mtlBuffer()
129                                     offset: 0
130                                    atIndex: GrMtlUniformHandler::kFragBinding];
131    }
132    SkASSERT(fNumSamplers == fSamplerBindings.count());
133    for (int index = 0; index < fNumSamplers; ++index) {
134        [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture
135                                     atIndex: index];
136        [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler
137                                          atIndex: index];
138    }
139}
140
141void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
142    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
143    if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
144        fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
145        fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
146    }
147
148    // set RT adjustment
149    SkISize size;
150    size.set(rt->width(), rt->height());
151    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
152    if (fRenderTargetState.fRenderTargetOrigin != origin ||
153        fRenderTargetState.fRenderTargetSize != size) {
154        fRenderTargetState.fRenderTargetSize = size;
155        fRenderTargetState.fRenderTargetOrigin = origin;
156
157        float rtAdjustmentVec[4];
158        fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
159        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
160    }
161}
162
163static bool blend_coeff_refs_constant(GrBlendCoeff coeff) {
164    switch (coeff) {
165        case kConstC_GrBlendCoeff:
166        case kIConstC_GrBlendCoeff:
167        case kConstA_GrBlendCoeff:
168        case kIConstA_GrBlendCoeff:
169            return true;
170        default:
171            return false;
172    }
173}
174
175void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder,
176                                           GrPixelConfig config,
177                                           const GrXferProcessor& xferProcessor) {
178    if (!renderCmdEncoder) {
179        return;
180    }
181
182    GrXferProcessor::BlendInfo blendInfo;
183    xferProcessor.getBlendInfo(&blendInfo);
184    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
185    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
186    if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) {
187        // Swizzle the blend to match what the shader will output.
188        const GrSwizzle& swizzle = fGpu->caps()->shaderCaps()->configOutputSwizzle(config);
189        SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
190
191        [renderCmdEncoder setBlendColorRed: blendConst.fR
192                                     green: blendConst.fG
193                                      blue: blendConst.fB
194                                     alpha: blendConst.fA];
195    }
196}
197
198MTLStencilOperation skia_stencil_op_to_mtl(GrStencilOp op) {
199    switch (op) {
200        case GrStencilOp::kKeep:
201            return MTLStencilOperationKeep;
202        case GrStencilOp::kZero:
203            return MTLStencilOperationZero;
204        case GrStencilOp::kReplace:
205            return MTLStencilOperationReplace;
206        case GrStencilOp::kInvert:
207            return MTLStencilOperationInvert;
208        case GrStencilOp::kIncWrap:
209            return MTLStencilOperationIncrementWrap;
210        case GrStencilOp::kDecWrap:
211            return MTLStencilOperationDecrementWrap;
212        case GrStencilOp::kIncClamp:
213            return MTLStencilOperationIncrementClamp;
214        case GrStencilOp::kDecClamp:
215            return MTLStencilOperationDecrementClamp;
216    }
217}
218
219MTLStencilDescriptor* skia_stencil_to_mtl(GrStencilSettings::Face face) {
220    MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
221    switch (face.fTest) {
222        case GrStencilTest::kAlways:
223            result.stencilCompareFunction = MTLCompareFunctionAlways;
224            break;
225        case GrStencilTest::kNever:
226            result.stencilCompareFunction = MTLCompareFunctionNever;
227            break;
228        case GrStencilTest::kGreater:
229            result.stencilCompareFunction = MTLCompareFunctionGreater;
230            break;
231        case GrStencilTest::kGEqual:
232            result.stencilCompareFunction = MTLCompareFunctionGreaterEqual;
233            break;
234        case GrStencilTest::kLess:
235            result.stencilCompareFunction = MTLCompareFunctionLess;
236            break;
237        case GrStencilTest::kLEqual:
238            result.stencilCompareFunction = MTLCompareFunctionLessEqual;
239            break;
240        case GrStencilTest::kEqual:
241            result.stencilCompareFunction = MTLCompareFunctionEqual;
242            break;
243        case GrStencilTest::kNotEqual:
244            result.stencilCompareFunction = MTLCompareFunctionNotEqual;
245            break;
246    }
247    result.readMask = face.fTestMask;
248    result.writeMask = face.fWriteMask;
249    result.depthStencilPassOperation = skia_stencil_op_to_mtl(face.fPassOp);
250    result.stencilFailureOperation = skia_stencil_op_to_mtl(face.fFailOp);
251    return result;
252}
253
254void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) {
255    if (fStencil.isDisabled()) {
256        MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
257        id<MTLDepthStencilState> state = [fGpu->device() newDepthStencilStateWithDescriptor:desc];
258        [renderCmdEncoder setDepthStencilState:state];
259    }
260    else {
261        MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
262        desc.frontFaceStencil = skia_stencil_to_mtl(fStencil.front());
263        if (fStencil.isTwoSided()) {
264            desc.backFaceStencil = skia_stencil_to_mtl(fStencil.back());
265            [renderCmdEncoder setStencilFrontReferenceValue:fStencil.front().fRef
266                              backReferenceValue:fStencil.back().fRef];
267        }
268        else {
269            desc.backFaceStencil = desc.frontFaceStencil;
270            [renderCmdEncoder setStencilReferenceValue:fStencil.front().fRef];
271        }
272        id<MTLDepthStencilState> state = [fGpu->device() newDepthStencilStateWithDescriptor:desc];
273        [renderCmdEncoder setDepthStencilState:state];
274    }
275}
276