• 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 "src/gpu/mtl/GrMtlPipelineState.h"
9
10#include "include/gpu/GrContext.h"
11#include "src/gpu/GrContextPriv.h"
12#include "src/gpu/GrPipeline.h"
13#include "src/gpu/GrRenderTarget.h"
14#include "src/gpu/GrRenderTargetPriv.h"
15#include "src/gpu/GrTexturePriv.h"
16#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
17#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
18#include "src/gpu/glsl/GrGLSLXferProcessor.h"
19#include "src/gpu/mtl/GrMtlBuffer.h"
20#include "src/gpu/mtl/GrMtlGpu.h"
21#include "src/gpu/mtl/GrMtlTexture.h"
22
23#if !__has_feature(objc_arc)
24#error This file must be compiled with Arc. Use -fobjc-arc flag
25#endif
26
27GrMtlPipelineState::SamplerBindings::SamplerBindings(const GrSamplerState& state,
28                                                     GrTexture* texture,
29                                                     GrMtlGpu* gpu)
30        : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) {
31    uint32_t maxMipMapLevel = texture->texturePriv().maxMipMapLevel();
32    fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state, maxMipMapLevel);
33}
34
35GrMtlPipelineState::GrMtlPipelineState(
36        GrMtlGpu* gpu,
37        id<MTLRenderPipelineState> pipelineState,
38        MTLPixelFormat pixelFormat,
39        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
40        const UniformInfoArray& uniforms,
41        uint32_t uniformBufferSize,
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        , fNumSamplers(numSamplers)
52        , fGeometryProcessor(std::move(geometryProcessor))
53        , fXferProcessor(std::move(xferProcessor))
54        , fFragmentProcessors(std::move(fragmentProcessors))
55        , fFragmentProcessorCnt(fragmentProcessorCnt)
56        , fDataManager(uniforms, uniformBufferSize) {
57    (void) fPixelFormat; // Suppress unused-var warning.
58}
59
60void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget,
61                                 GrSurfaceOrigin origin,
62                                 const GrPrimitiveProcessor& primProc,
63                                 const GrPipeline& pipeline,
64                                 const GrTextureProxy* const primProcTextures[]) {
65    SkASSERT(primProcTextures || !primProc.numTextureSamplers());
66
67    this->setRenderTargetState(renderTarget, origin);
68    fGeometryProcessor->setData(fDataManager, primProc,
69                                GrFragmentProcessor::CoordTransformIter(pipeline));
70    fSamplerBindings.reset();
71    for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
72        const auto& sampler = primProc.textureSampler(i);
73        auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture());
74        fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
75    }
76
77    GrFragmentProcessor::Iter iter(pipeline);
78    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
79    const GrFragmentProcessor* fp = iter.next();
80    GrGLSLFragmentProcessor* glslFP = glslIter.next();
81    while (fp && glslFP) {
82        glslFP->setData(fDataManager, *fp);
83        for (int i = 0; i < fp->numTextureSamplers(); ++i) {
84            const auto& sampler = fp->textureSampler(i);
85            fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
86        }
87        fp = iter.next();
88        glslFP = glslIter.next();
89    }
90    SkASSERT(!fp && !glslFP);
91
92    {
93        SkIPoint offset;
94        GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
95
96        fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
97    }
98
99    if (GrTextureProxy* dstTextureProxy = pipeline.dstTextureProxy()) {
100        fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(),
101                                      dstTextureProxy->peekTexture(),
102                                      fGpu);
103    }
104
105    SkASSERT(fNumSamplers == fSamplerBindings.count());
106    fDataManager.resetDirtyBits();
107
108    if (pipeline.isStencilEnabled()) {
109        SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment());
110        fStencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
111                       renderTarget->renderTargetPriv().numStencilBits());
112    }
113}
114
115void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder,
116                                      const GrSwizzle& outputSwizzle,
117                                      const GrXferProcessor& xferProcessor) {
118    [renderCmdEncoder pushDebugGroup:@"setDrawState"];
119    this->bind(renderCmdEncoder);
120    this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor);
121    this->setDepthStencilState(renderCmdEncoder);
122    [renderCmdEncoder popDebugGroup];
123}
124
125void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) {
126    fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder);
127
128    SkASSERT(fNumSamplers == fSamplerBindings.count());
129    for (int index = 0; index < fNumSamplers; ++index) {
130        [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture
131                                     atIndex: index];
132        [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler->mtlSampler()
133                                          atIndex: index];
134    }
135}
136
137void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
138    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
139    if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
140        fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
141        fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
142    }
143
144    // set RT adjustment
145    SkISize size;
146    size.set(rt->width(), rt->height());
147    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
148    if (fRenderTargetState.fRenderTargetOrigin != origin ||
149        fRenderTargetState.fRenderTargetSize != size) {
150        fRenderTargetState.fRenderTargetSize = size;
151        fRenderTargetState.fRenderTargetOrigin = origin;
152
153        float rtAdjustmentVec[4];
154        fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
155        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
156    }
157}
158
159static bool blend_coeff_refs_constant(GrBlendCoeff coeff) {
160    switch (coeff) {
161        case kConstC_GrBlendCoeff:
162        case kIConstC_GrBlendCoeff:
163        case kConstA_GrBlendCoeff:
164        case kIConstA_GrBlendCoeff:
165            return true;
166        default:
167            return false;
168    }
169}
170
171void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder,
172                                           const GrSwizzle& swizzle,
173                                           const GrXferProcessor& xferProcessor) {
174    if (!renderCmdEncoder) {
175        return;
176    }
177
178    const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo();
179    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
180    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
181    if (blend_coeff_refs_constant(srcCoeff) || blend_coeff_refs_constant(dstCoeff)) {
182        // Swizzle the blend to match what the shader will output.
183        SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
184
185        [renderCmdEncoder setBlendColorRed: blendConst.fR
186                                     green: blendConst.fG
187                                      blue: blendConst.fB
188                                     alpha: blendConst.fA];
189    }
190}
191
192void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) {
193    const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin;
194    GrMtlDepthStencil* state =
195            fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin);
196    if (!fStencil.isDisabled()) {
197        if (fStencil.isTwoSided()) {
198            [renderCmdEncoder setStencilFrontReferenceValue:fStencil.front(origin).fRef
199                              backReferenceValue:fStencil.back(origin).fRef];
200        }
201        else {
202            [renderCmdEncoder setStencilReferenceValue:fStencil.frontAndBack().fRef];
203        }
204    }
205    [renderCmdEncoder setDepthStencilState:state->mtlDepthStencil()];
206}
207
208void GrMtlPipelineState::SetDynamicScissorRectState(id<MTLRenderCommandEncoder> renderCmdEncoder,
209                                                    const GrRenderTarget* renderTarget,
210                                                    GrSurfaceOrigin rtOrigin,
211                                                    SkIRect scissorRect) {
212    if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) {
213        scissorRect.setEmpty();
214    }
215
216    MTLScissorRect scissor;
217    scissor.x = scissorRect.fLeft;
218    scissor.width = scissorRect.width();
219    if (kTopLeft_GrSurfaceOrigin == rtOrigin) {
220        scissor.y = scissorRect.fTop;
221    } else {
222        SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin);
223        scissor.y = renderTarget->height() - scissorRect.fBottom;
224    }
225    scissor.height = scissorRect.height();
226
227    SkASSERT(scissor.x >= 0);
228    SkASSERT(scissor.y >= 0);
229
230    [renderCmdEncoder setScissorRect: scissor];
231}
232
233bool GrMtlPipelineState::doesntSampleAttachment(
234        const MTLRenderPassAttachmentDescriptor* attachment) const {
235    for (int i = 0; i < fSamplerBindings.count(); ++i) {
236        if (attachment.texture == fSamplerBindings[i].fTexture) {
237            return false;
238        }
239    }
240    return true;
241}
242