• 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(GrSamplerState state,
28                                                     GrTexture* texture,
29                                                     GrMtlGpu* gpu)
30        : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) {
31    fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state);
32}
33
34GrMtlPipelineState::GrMtlPipelineState(
35        GrMtlGpu* gpu,
36        id<MTLRenderPipelineState> pipelineState,
37        MTLPixelFormat pixelFormat,
38        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
39        const UniformInfoArray& uniforms,
40        uint32_t uniformBufferSize,
41        uint32_t numSamplers,
42        std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
43        std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
44        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
45        int fragmentProcessorCnt)
46        : fGpu(gpu)
47        , fPipelineState(pipelineState)
48        , fPixelFormat(pixelFormat)
49        , fBuiltinUniformHandles(builtinUniformHandles)
50        , fNumSamplers(numSamplers)
51        , fGeometryProcessor(std::move(geometryProcessor))
52        , fXferProcessor(std::move(xferProcessor))
53        , fFragmentProcessors(std::move(fragmentProcessors))
54        , fFragmentProcessorCnt(fragmentProcessorCnt)
55        , fDataManager(uniforms, uniformBufferSize) {
56    (void) fPixelFormat; // Suppress unused-var warning.
57}
58
59void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget,
60                                 const GrProgramInfo& programInfo) {
61    this->setRenderTargetState(renderTarget, programInfo.origin());
62    GrFragmentProcessor::PipelineCoordTransformRange transformRange(programInfo.pipeline());
63    fGeometryProcessor->setData(fDataManager, programInfo.primProc(), transformRange);
64
65    if (!programInfo.hasDynamicPrimProcTextures()) {
66        auto proxies = programInfo.hasFixedPrimProcTextures() ? programInfo.fixedPrimProcTextures()
67                                                              : nullptr;
68        this->setTextures(programInfo, proxies);
69    }
70    fDataManager.resetDirtyBits();
71
72#ifdef SK_DEBUG
73    if (programInfo.pipeline().isStencilEnabled()) {
74        SkASSERT(renderTarget->renderTargetPriv().getStencilAttachment());
75        SkASSERT(renderTarget->renderTargetPriv().numStencilBits() == 8);
76    }
77#endif
78
79    fStencil = programInfo.nonGLStencilSettings();
80}
81
82void GrMtlPipelineState::setTextures(const GrProgramInfo& programInfo,
83                                     const GrSurfaceProxy* const primProcTextures[]) {
84    fSamplerBindings.reset();
85    for (int i = 0; i < programInfo.primProc().numTextureSamplers(); ++i) {
86        SkASSERT(primProcTextures[i]->asTextureProxy());
87        const auto& sampler = programInfo.primProc().textureSampler(i);
88        auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture());
89        fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
90    }
91
92    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
93    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
94    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
95        glslIter->setData(fDataManager, *fpIter);
96        for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
97            const auto& sampler = fpIter->textureSampler(i);
98            fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
99        }
100    }
101    SkASSERT(!fpIter && !glslIter);
102
103    {
104        SkIPoint offset;
105        GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset);
106
107        fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(),
108                                dstTexture, offset);
109    }
110
111    if (GrTextureProxy* dstTextureProxy = programInfo.pipeline().dstProxyView().asTextureProxy()) {
112        fSamplerBindings.emplace_back(
113                GrSamplerState::Filter::kNearest, dstTextureProxy->peekTexture(), fGpu);
114    }
115
116    SkASSERT(fNumSamplers == fSamplerBindings.count());
117}
118
119void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder,
120                                      const GrSwizzle& outputSwizzle,
121                                      const GrXferProcessor& xferProcessor) {
122    [renderCmdEncoder pushDebugGroup:@"setDrawState"];
123    this->bindUniforms(renderCmdEncoder);
124    this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor);
125    this->setDepthStencilState(renderCmdEncoder);
126    [renderCmdEncoder popDebugGroup];
127}
128
129void GrMtlPipelineState::bindUniforms(id<MTLRenderCommandEncoder> renderCmdEncoder) {
130    fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder);
131}
132
133void GrMtlPipelineState::bindTextures(id<MTLRenderCommandEncoder> renderCmdEncoder) {
134    SkASSERT(fNumSamplers == fSamplerBindings.count());
135    for (int index = 0; index < fNumSamplers; ++index) {
136        [renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture
137                                     atIndex: index];
138        [renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler->mtlSampler()
139                                          atIndex: index];
140    }
141}
142
143void GrMtlPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
144    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
145    if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
146        fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
147        fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
148    }
149
150    // set RT adjustment
151    SkISize dimensions = rt->dimensions();
152    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
153    if (fRenderTargetState.fRenderTargetOrigin != origin ||
154        fRenderTargetState.fRenderTargetSize != dimensions) {
155        fRenderTargetState.fRenderTargetSize = dimensions;
156        fRenderTargetState.fRenderTargetOrigin = origin;
157
158        float rtAdjustmentVec[4];
159        fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
160        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
161    }
162}
163
164static bool blend_coeff_refs_constant(GrBlendCoeff coeff) {
165    switch (coeff) {
166        case kConstC_GrBlendCoeff:
167        case kIConstC_GrBlendCoeff:
168        case kConstA_GrBlendCoeff:
169        case kIConstA_GrBlendCoeff:
170            return true;
171        default:
172            return false;
173    }
174}
175
176void GrMtlPipelineState::setBlendConstants(id<MTLRenderCommandEncoder> renderCmdEncoder,
177                                           const GrSwizzle& swizzle,
178                                           const GrXferProcessor& xferProcessor) {
179    if (!renderCmdEncoder) {
180        return;
181    }
182
183    const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo();
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        SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
189
190        [renderCmdEncoder setBlendColorRed: blendConst.fR
191                                     green: blendConst.fG
192                                      blue: blendConst.fB
193                                     alpha: blendConst.fA];
194    }
195}
196
197void GrMtlPipelineState::setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder) {
198    const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin;
199    GrMtlDepthStencil* state =
200            fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin);
201    if (!fStencil.isDisabled()) {
202        if (fStencil.isTwoSided()) {
203            if (@available(macOS 10.11, iOS 9.0, *)) {
204                [renderCmdEncoder
205                        setStencilFrontReferenceValue:fStencil.postOriginCCWFace(origin).fRef
206                        backReferenceValue:fStencil.postOriginCWFace(origin).fRef];
207            } else {
208                // Two-sided stencil not supported on older versions of iOS
209                // TODO: Find a way to recover from this
210                SkASSERT(false);
211            }
212        } else {
213            [renderCmdEncoder setStencilReferenceValue:fStencil.singleSidedFace().fRef];
214        }
215    }
216    [renderCmdEncoder setDepthStencilState:state->mtlDepthStencil()];
217}
218
219void GrMtlPipelineState::SetDynamicScissorRectState(id<MTLRenderCommandEncoder> renderCmdEncoder,
220                                                    const GrRenderTarget* renderTarget,
221                                                    GrSurfaceOrigin rtOrigin,
222                                                    SkIRect scissorRect) {
223    if (!scissorRect.intersect(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()))) {
224        scissorRect.setEmpty();
225    }
226
227    MTLScissorRect scissor;
228    scissor.x = scissorRect.fLeft;
229    scissor.width = scissorRect.width();
230    if (kTopLeft_GrSurfaceOrigin == rtOrigin) {
231        scissor.y = scissorRect.fTop;
232    } else {
233        SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin);
234        scissor.y = renderTarget->height() - scissorRect.fBottom;
235    }
236    scissor.height = scissorRect.height();
237
238    SkASSERT(scissor.x >= 0);
239    SkASSERT(scissor.y >= 0);
240
241    [renderCmdEncoder setScissorRect: scissor];
242}
243
244bool GrMtlPipelineState::doesntSampleAttachment(
245        const MTLRenderPassAttachmentDescriptor* attachment) const {
246    for (int i = 0; i < fSamplerBindings.count(); ++i) {
247        if (attachment.texture == fSamplerBindings[i].fTexture) {
248            return false;
249        }
250    }
251    return true;
252}
253