• 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 "src/gpu/GrBackendUtils.h"
11#include "src/gpu/GrFragmentProcessor.h"
12#include "src/gpu/GrGeometryProcessor.h"
13#include "src/gpu/GrRenderTarget.h"
14#include "src/gpu/GrTexture.h"
15#include "src/gpu/GrXferProcessor.h"
16#include "src/gpu/effects/GrTextureEffect.h"
17#include "src/gpu/mtl/GrMtlBuffer.h"
18#include "src/gpu/mtl/GrMtlFramebuffer.h"
19#include "src/gpu/mtl/GrMtlGpu.h"
20#include "src/gpu/mtl/GrMtlRenderCommandEncoder.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
27GR_NORETAIN_BEGIN
28
29GrMtlPipelineState::SamplerBindings::SamplerBindings(GrSamplerState state,
30                                                     GrTexture* texture,
31                                                     GrMtlGpu* gpu)
32        : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) {
33    fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state);
34    gpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(fSampler));
35    gpu->commandBuffer()->addGrSurface(
36            sk_ref_sp<GrSurface>(static_cast<GrMtlTexture*>(texture)->attachment()));
37}
38
39GrMtlPipelineState::GrMtlPipelineState(
40        GrMtlGpu* gpu,
41        sk_sp<GrMtlRenderPipeline> pipeline,
42        MTLPixelFormat pixelFormat,
43        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
44        const UniformInfoArray& uniforms,
45        uint32_t uniformBufferSize,
46        uint32_t numSamplers,
47        std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl,
48        std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl,
49        std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls)
50        : fGpu(gpu)
51        , fPipeline(std::move(pipeline))
52        , fPixelFormat(pixelFormat)
53        , fBuiltinUniformHandles(builtinUniformHandles)
54        , fNumSamplers(numSamplers)
55        , fGPImpl(std::move(gpImpl))
56        , fXPImpl(std::move(xpImpl))
57        , fFPImpls(std::move(fpImpls))
58        , fDataManager(uniforms, uniformBufferSize) {
59    (void) fPixelFormat; // Suppress unused-var warning.
60}
61
62void GrMtlPipelineState::setData(GrMtlFramebuffer* framebuffer,
63                                 const GrProgramInfo& programInfo) {
64    SkISize colorAttachmentDimensions = framebuffer->colorAttachment()->dimensions();
65
66    this->setRenderTargetState(colorAttachmentDimensions, programInfo.origin());
67    fGPImpl->setData(fDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc());
68
69    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
70        const auto& fp = programInfo.pipeline().getFragmentProcessor(i);
71        fp.visitWithImpls([&](const GrFragmentProcessor& fp,
72                              GrFragmentProcessor::ProgramImpl& impl) {
73            impl.setData(fDataManager, fp);
74        }, *fFPImpls[i]);
75    }
76
77    programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles);
78    fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor());
79
80    fDataManager.resetDirtyBits();
81
82#ifdef SK_DEBUG
83    if (programInfo.isStencilEnabled()) {
84        SkDEBUGCODE(const GrAttachment* stencil = framebuffer->stencilAttachment());
85        SkASSERT(stencil);
86        SkASSERT(GrBackendFormatStencilBits(stencil->backendFormat()) == 8);
87    }
88#endif
89
90    fStencil = programInfo.nonGLStencilSettings();
91    fGpu->commandBuffer()->addResource(fPipeline);
92}
93
94void GrMtlPipelineState::setTextures(const GrGeometryProcessor& geomProc,
95                                     const GrPipeline& pipeline,
96                                     const GrSurfaceProxy* const geomProcTextures[]) {
97    fSamplerBindings.reset();
98    for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
99        SkASSERT(geomProcTextures[i]->asTextureProxy());
100        const auto& sampler = geomProc.textureSampler(i);
101        auto texture = static_cast<GrMtlTexture*>(geomProcTextures[i]->peekTexture());
102        fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
103    }
104
105    if (GrTextureProxy* dstTextureProxy = pipeline.dstProxyView().asTextureProxy()) {
106        fSamplerBindings.emplace_back(
107                GrSamplerState::Filter::kNearest, dstTextureProxy->peekTexture(), fGpu);
108    }
109
110    pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
111        fSamplerBindings.emplace_back(te.samplerState(), te.texture(), fGpu);
112    });
113
114    SkASSERT(fNumSamplers == fSamplerBindings.count());
115}
116
117void GrMtlPipelineState::setDrawState(GrMtlRenderCommandEncoder* renderCmdEncoder,
118                                      const GrSwizzle& writeSwizzle,
119                                      const GrXferProcessor& xferProcessor) {
120    this->bindUniforms(renderCmdEncoder);
121    this->setBlendConstants(renderCmdEncoder, writeSwizzle, xferProcessor);
122    this->setDepthStencilState(renderCmdEncoder);
123}
124
125void GrMtlPipelineState::bindUniforms(GrMtlRenderCommandEncoder* renderCmdEncoder) {
126    fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder);
127}
128
129void GrMtlPipelineState::bindTextures(GrMtlRenderCommandEncoder* renderCmdEncoder) {
130    SkASSERT(fNumSamplers == fSamplerBindings.count());
131    for (int index = 0; index < fNumSamplers; ++index) {
132        renderCmdEncoder->setFragmentTexture(fSamplerBindings[index].fTexture, index);
133        renderCmdEncoder->setFragmentSamplerState(fSamplerBindings[index].fSampler, index);
134    }
135}
136
137void GrMtlPipelineState::setRenderTargetState(SkISize colorAttachmentDimensions,
138                                              GrSurfaceOrigin origin) {
139    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
140    if (fRenderTargetState.fRenderTargetOrigin != origin ||
141        fRenderTargetState.fRenderTargetSize != colorAttachmentDimensions) {
142        fRenderTargetState.fRenderTargetSize = colorAttachmentDimensions;
143        fRenderTargetState.fRenderTargetOrigin = origin;
144
145        // The client will mark a swap buffer as kTopLeft when making a SkSurface because
146        // Metal's framebuffer space has (0, 0) at the top left. This agrees with Skia's device
147        // coords. However, in NDC (-1, -1) is the bottom left. So we flip when origin is kTopLeft.
148        bool flip = (origin == kTopLeft_GrSurfaceOrigin);
149        std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(colorAttachmentDimensions, flip);
150        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data());
151        if (fBuiltinUniformHandles.fRTFlipUni.isValid()) {
152            // Note above that framebuffer space has origin top left. So we need !flip here.
153            std::array<float, 2> d =
154                    SkSL::Compiler::GetRTFlipVector(colorAttachmentDimensions.height(), !flip);
155            fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data());
156        }
157    }
158}
159
160void GrMtlPipelineState::setBlendConstants(GrMtlRenderCommandEncoder* renderCmdEncoder,
161                                           const GrSwizzle& swizzle,
162                                           const GrXferProcessor& xferProcessor) {
163    if (!renderCmdEncoder) {
164        return;
165    }
166
167    const GrXferProcessor::BlendInfo& blendInfo = xferProcessor.getBlendInfo();
168    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
169    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
170    if (GrBlendCoeffRefsConstant(srcCoeff) || GrBlendCoeffRefsConstant(dstCoeff)) {
171        // Swizzle the blend to match what the shader will output.
172        SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
173
174        renderCmdEncoder->setBlendColor(blendConst);
175    }
176}
177
178void GrMtlPipelineState::setDepthStencilState(GrMtlRenderCommandEncoder* renderCmdEncoder) {
179    const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin;
180    GrMtlDepthStencil* state =
181            fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin);
182    if (!fStencil.isDisabled()) {
183        if (fStencil.isTwoSided()) {
184            if (@available(macOS 10.11, iOS 9.0, *)) {
185                renderCmdEncoder->setStencilFrontBackReferenceValues(
186                        fStencil.postOriginCCWFace(origin).fRef,
187                        fStencil.postOriginCWFace(origin).fRef);
188            } else {
189                // Two-sided stencil not supported on older versions of iOS
190                // TODO: Find a way to recover from this
191                SkASSERT(false);
192            }
193        } else {
194            renderCmdEncoder->setStencilReferenceValue(fStencil.singleSidedFace().fRef);
195        }
196    }
197    renderCmdEncoder->setDepthStencilState(state->mtlDepthStencil());
198    fGpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(state));
199}
200
201void GrMtlPipelineState::SetDynamicScissorRectState(GrMtlRenderCommandEncoder* renderCmdEncoder,
202                                                    SkISize colorAttachmentDimensions,
203                                                    GrSurfaceOrigin rtOrigin,
204                                                    SkIRect scissorRect) {
205    if (!scissorRect.intersect(SkIRect::MakeWH(colorAttachmentDimensions.width(),
206                                               colorAttachmentDimensions.height()))) {
207        scissorRect.setEmpty();
208    }
209
210    MTLScissorRect scissor;
211    scissor.x = scissorRect.fLeft;
212    scissor.width = scissorRect.width();
213    if (kTopLeft_GrSurfaceOrigin == rtOrigin) {
214        scissor.y = scissorRect.fTop;
215    } else {
216        SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin);
217        scissor.y = colorAttachmentDimensions.height() - scissorRect.fBottom;
218    }
219    scissor.height = scissorRect.height();
220
221    SkASSERT(scissor.x >= 0);
222    SkASSERT(scissor.y >= 0);
223
224    renderCmdEncoder->setScissorRect(scissor);
225}
226
227bool GrMtlPipelineState::doesntSampleAttachment(
228        const MTLRenderPassAttachmentDescriptor* attachment) const {
229    for (int i = 0; i < fSamplerBindings.count(); ++i) {
230        if (attachment.texture == fSamplerBindings[i].fTexture ||
231            attachment.resolveTexture == fSamplerBindings[i].fTexture) {
232            return false;
233        }
234    }
235    return true;
236}
237
238GR_NORETAIN_END
239