1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrPipeline.h"
12cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
13cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
14cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h"
15cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include <queue>
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ciGrGeometryProcessor::GrGeometryProcessor(ClassID classID) : GrProcessor(classID) {}
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ciconst GrGeometryProcessor::TextureSampler& GrGeometryProcessor::textureSampler(int i) const {
22cb93a386Sopenharmony_ci    SkASSERT(i >= 0 && i < this->numTextureSamplers());
23cb93a386Sopenharmony_ci    return this->onTextureSampler(i);
24cb93a386Sopenharmony_ci}
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ciuint32_t GrGeometryProcessor::ComputeCoordTransformsKey(const GrFragmentProcessor& fp) {
27cb93a386Sopenharmony_ci    // This is highly coupled with the code in ProgramImpl::collectTransforms().
28cb93a386Sopenharmony_ci    uint32_t key = static_cast<uint32_t>(fp.sampleUsage().kind()) << 1;
29cb93a386Sopenharmony_ci    // This needs to be updated if GP starts specializing varyings on additional matrix types.
30cb93a386Sopenharmony_ci    if (fp.sampleUsage().hasPerspective()) {
31cb93a386Sopenharmony_ci        key |= 0b1;
32cb93a386Sopenharmony_ci    }
33cb93a386Sopenharmony_ci    return key;
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_cistatic inline GrSamplerState::Filter clamp_filter(GrTextureType type,
39cb93a386Sopenharmony_ci                                                  GrSamplerState::Filter requestedFilter) {
40cb93a386Sopenharmony_ci    if (GrTextureTypeHasRestrictedSampling(type)) {
41cb93a386Sopenharmony_ci        return std::min(requestedFilter, GrSamplerState::Filter::kLinear);
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    return requestedFilter;
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ciGrGeometryProcessor::TextureSampler::TextureSampler(GrSamplerState samplerState,
47cb93a386Sopenharmony_ci                                                    const GrBackendFormat& backendFormat,
48cb93a386Sopenharmony_ci                                                    const GrSwizzle& swizzle) {
49cb93a386Sopenharmony_ci    this->reset(samplerState, backendFormat, swizzle);
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_civoid GrGeometryProcessor::TextureSampler::reset(GrSamplerState samplerState,
53cb93a386Sopenharmony_ci                                                const GrBackendFormat& backendFormat,
54cb93a386Sopenharmony_ci                                                const GrSwizzle& swizzle) {
55cb93a386Sopenharmony_ci    fSamplerState = samplerState;
56cb93a386Sopenharmony_ci    fSamplerState.setFilterMode(clamp_filter(backendFormat.textureType(), samplerState.filter()));
57cb93a386Sopenharmony_ci    fBackendFormat = backendFormat;
58cb93a386Sopenharmony_ci    fSwizzle = swizzle;
59cb93a386Sopenharmony_ci    fIsInitialized = true;
60cb93a386Sopenharmony_ci}
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciusing ProgramImpl = GrGeometryProcessor::ProgramImpl;
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ciProgramImpl::FPCoordsMap ProgramImpl::emitCode(EmitArgs& args, const GrPipeline& pipeline) {
67cb93a386Sopenharmony_ci    GrGPArgs gpArgs;
68cb93a386Sopenharmony_ci    this->onEmitCode(args, &gpArgs);
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    GrShaderVar positionVar = gpArgs.fPositionVar;
71cb93a386Sopenharmony_ci    // skia:12198
72cb93a386Sopenharmony_ci    if (args.fGeomProc.willUseTessellationShaders()) {
73cb93a386Sopenharmony_ci        positionVar = {};
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci    FPCoordsMap transformMap = this->collectTransforms(args.fVertBuilder,
76cb93a386Sopenharmony_ci                                                       args.fVaryingHandler,
77cb93a386Sopenharmony_ci                                                       args.fUniformHandler,
78cb93a386Sopenharmony_ci                                                       gpArgs.fLocalCoordVar,
79cb93a386Sopenharmony_ci                                                       positionVar,
80cb93a386Sopenharmony_ci                                                       pipeline);
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci    if (args.fGeomProc.willUseTessellationShaders()) {
83cb93a386Sopenharmony_ci        // Tessellation shaders are temporarily responsible for integrating their own code strings
84cb93a386Sopenharmony_ci        // while we work out full support.
85cb93a386Sopenharmony_ci        return transformMap;
86cb93a386Sopenharmony_ci    }
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
89cb93a386Sopenharmony_ci    // Emit the vertex position to the hardware in the normalized window coordinates it expects.
90cb93a386Sopenharmony_ci    SkASSERT(kFloat2_GrSLType == gpArgs.fPositionVar.getType() ||
91cb93a386Sopenharmony_ci                kFloat3_GrSLType == gpArgs.fPositionVar.getType());
92cb93a386Sopenharmony_ci    vBuilder->emitNormalizedSkPosition(gpArgs.fPositionVar.c_str(),
93cb93a386Sopenharmony_ci                                        gpArgs.fPositionVar.getType());
94cb93a386Sopenharmony_ci    if (kFloat2_GrSLType == gpArgs.fPositionVar.getType()) {
95cb93a386Sopenharmony_ci        args.fVaryingHandler->setNoPerspective();
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci    return transformMap;
98cb93a386Sopenharmony_ci}
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ciProgramImpl::FPCoordsMap ProgramImpl::collectTransforms(GrGLSLVertexBuilder* vb,
101cb93a386Sopenharmony_ci                                                        GrGLSLVaryingHandler* varyingHandler,
102cb93a386Sopenharmony_ci                                                        GrGLSLUniformHandler* uniformHandler,
103cb93a386Sopenharmony_ci                                                        const GrShaderVar& localCoordsVar,
104cb93a386Sopenharmony_ci                                                        const GrShaderVar& positionVar,
105cb93a386Sopenharmony_ci                                                        const GrPipeline& pipeline) {
106cb93a386Sopenharmony_ci    SkASSERT(localCoordsVar.getType() == kFloat2_GrSLType ||
107cb93a386Sopenharmony_ci             localCoordsVar.getType() == kFloat3_GrSLType ||
108cb93a386Sopenharmony_ci             localCoordsVar.getType() == kVoid_GrSLType);
109cb93a386Sopenharmony_ci    SkASSERT(positionVar.getType() == kFloat2_GrSLType ||
110cb93a386Sopenharmony_ci             positionVar.getType() == kFloat3_GrSLType ||
111cb93a386Sopenharmony_ci             positionVar.getType() == kVoid_GrSLType);
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    enum class BaseCoord { kNone, kLocal, kPosition };
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci    auto baseLocalCoordFSVar = [&, baseLocalCoord = GrGLSLVarying()]() mutable {
116cb93a386Sopenharmony_ci        SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType()));
117cb93a386Sopenharmony_ci        if (baseLocalCoord.type() == kVoid_GrSLType) {
118cb93a386Sopenharmony_ci            // Initialize to the GP provided coordinate
119cb93a386Sopenharmony_ci            baseLocalCoord = GrGLSLVarying(localCoordsVar.getType());
120cb93a386Sopenharmony_ci            varyingHandler->addVarying("LocalCoord", &baseLocalCoord);
121cb93a386Sopenharmony_ci            vb->codeAppendf("%s = %s;\n", baseLocalCoord.vsOut(), localCoordsVar.getName().c_str());
122cb93a386Sopenharmony_ci        }
123cb93a386Sopenharmony_ci        return baseLocalCoord.fsInVar();
124cb93a386Sopenharmony_ci    };
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    bool canUsePosition = positionVar.getType() != kVoid_GrSLType;
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    FPCoordsMap result;
129cb93a386Sopenharmony_ci    // Performs a pre-order traversal of FP hierarchy rooted at fp and identifies FPs that are
130cb93a386Sopenharmony_ci    // sampled with a series of matrices applied to local coords. For each such FP a varying is
131cb93a386Sopenharmony_ci    // added to the varying handler and added to 'result'.
132cb93a386Sopenharmony_ci    auto liftTransforms = [&, traversalIndex = 0](
133cb93a386Sopenharmony_ci                                  auto& self,
134cb93a386Sopenharmony_ci                                  const GrFragmentProcessor& fp,
135cb93a386Sopenharmony_ci                                  bool hasPerspective,
136cb93a386Sopenharmony_ci                                  const GrFragmentProcessor* lastMatrixFP = nullptr,
137cb93a386Sopenharmony_ci                                  int lastMatrixTraversalIndex = -1,
138cb93a386Sopenharmony_ci                                  BaseCoord baseCoord = BaseCoord::kLocal) mutable -> void {
139cb93a386Sopenharmony_ci        ++traversalIndex;
140cb93a386Sopenharmony_ci        switch (fp.sampleUsage().kind()) {
141cb93a386Sopenharmony_ci            case SkSL::SampleUsage::Kind::kNone:
142cb93a386Sopenharmony_ci                // This should only happen at the root. Otherwise how did this FP get added?
143cb93a386Sopenharmony_ci                SkASSERT(!fp.parent());
144cb93a386Sopenharmony_ci                break;
145cb93a386Sopenharmony_ci            case SkSL::SampleUsage::Kind::kPassThrough:
146cb93a386Sopenharmony_ci                break;
147cb93a386Sopenharmony_ci            case SkSL::SampleUsage::Kind::kUniformMatrix:
148cb93a386Sopenharmony_ci                // Update tracking of last matrix and matrix props.
149cb93a386Sopenharmony_ci                hasPerspective |= fp.sampleUsage().hasPerspective();
150cb93a386Sopenharmony_ci                lastMatrixFP = &fp;
151cb93a386Sopenharmony_ci                lastMatrixTraversalIndex = traversalIndex;
152cb93a386Sopenharmony_ci                break;
153cb93a386Sopenharmony_ci            case SkSL::SampleUsage::Kind::kFragCoord:
154cb93a386Sopenharmony_ci                hasPerspective = positionVar.getType() == kFloat3_GrSLType;
155cb93a386Sopenharmony_ci                lastMatrixFP = nullptr;
156cb93a386Sopenharmony_ci                lastMatrixTraversalIndex = -1;
157cb93a386Sopenharmony_ci                baseCoord = BaseCoord::kPosition;
158cb93a386Sopenharmony_ci                break;
159cb93a386Sopenharmony_ci            case SkSL::SampleUsage::Kind::kExplicit:
160cb93a386Sopenharmony_ci                baseCoord = BaseCoord::kNone;
161cb93a386Sopenharmony_ci                break;
162cb93a386Sopenharmony_ci        }
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci        auto& [varyingFSVar, hasCoordsParam] = result[&fp];
165cb93a386Sopenharmony_ci        hasCoordsParam = fp.usesSampleCoordsDirectly();
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci        // We add a varying if we're in a chain of matrices multiplied by local or device coords.
168cb93a386Sopenharmony_ci        // If the coord is the untransformed local coord we add a varying. We don't if it is
169cb93a386Sopenharmony_ci        // untransformed device coords since it doesn't save us anything over "sk_FragCoord.xy". Of
170cb93a386Sopenharmony_ci        // course, if the FP doesn't directly use its coords then we don't add a varying.
171cb93a386Sopenharmony_ci        if (fp.usesSampleCoordsDirectly() &&
172cb93a386Sopenharmony_ci            (baseCoord == BaseCoord::kLocal ||
173cb93a386Sopenharmony_ci             (baseCoord == BaseCoord::kPosition && lastMatrixFP && canUsePosition))) {
174cb93a386Sopenharmony_ci            // Associate the varying with the highest possible node in the FP tree that shares the
175cb93a386Sopenharmony_ci            // same coordinates so that multiple FPs in a subtree can share. If there are no matrix
176cb93a386Sopenharmony_ci            // sample nodes on the way up the tree then directly use the local coord.
177cb93a386Sopenharmony_ci            if (!lastMatrixFP) {
178cb93a386Sopenharmony_ci                varyingFSVar = baseLocalCoordFSVar();
179cb93a386Sopenharmony_ci            } else {
180cb93a386Sopenharmony_ci                // If there is an already a varying that incorporates all matrices from the root to
181cb93a386Sopenharmony_ci                // lastMatrixFP just use it. Otherwise, we add it.
182cb93a386Sopenharmony_ci                auto& [varying, inputCoords, varyingIdx] = fTransformVaryingsMap[lastMatrixFP];
183cb93a386Sopenharmony_ci                if (varying.type() == kVoid_GrSLType) {
184cb93a386Sopenharmony_ci                    varying = GrGLSLVarying(hasPerspective ? kFloat3_GrSLType : kFloat2_GrSLType);
185cb93a386Sopenharmony_ci                    SkString strVaryingName = SkStringPrintf("TransformedCoords_%d",
186cb93a386Sopenharmony_ci                                                             lastMatrixTraversalIndex);
187cb93a386Sopenharmony_ci                    varyingHandler->addVarying(strVaryingName.c_str(), &varying);
188cb93a386Sopenharmony_ci                    inputCoords = baseCoord == BaseCoord::kLocal ? localCoordsVar : positionVar;
189cb93a386Sopenharmony_ci                    varyingIdx = lastMatrixTraversalIndex;
190cb93a386Sopenharmony_ci                }
191cb93a386Sopenharmony_ci                SkASSERT(varyingIdx == lastMatrixTraversalIndex);
192cb93a386Sopenharmony_ci                // The FP will use the varying in the fragment shader as its coords.
193cb93a386Sopenharmony_ci                varyingFSVar = varying.fsInVar();
194cb93a386Sopenharmony_ci            }
195cb93a386Sopenharmony_ci            hasCoordsParam = false;
196cb93a386Sopenharmony_ci        }
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci        for (int c = 0; c < fp.numChildProcessors(); ++c) {
199cb93a386Sopenharmony_ci            if (auto* child = fp.childProcessor(c)) {
200cb93a386Sopenharmony_ci                self(self,
201cb93a386Sopenharmony_ci                     *child,
202cb93a386Sopenharmony_ci                     hasPerspective,
203cb93a386Sopenharmony_ci                     lastMatrixFP,
204cb93a386Sopenharmony_ci                     lastMatrixTraversalIndex,
205cb93a386Sopenharmony_ci                     baseCoord);
206cb93a386Sopenharmony_ci                // If we have a varying then we never need a param. Otherwise, if one of our
207cb93a386Sopenharmony_ci                // children takes a non-explicit coord then we'll need our coord.
208cb93a386Sopenharmony_ci                hasCoordsParam |= varyingFSVar.getType() == kVoid_GrSLType &&
209cb93a386Sopenharmony_ci                                  !child->sampleUsage().isExplicit()       &&
210cb93a386Sopenharmony_ci                                  !child->sampleUsage().isFragCoord()      &&
211cb93a386Sopenharmony_ci                                  result[child].hasCoordsParam;
212cb93a386Sopenharmony_ci            }
213cb93a386Sopenharmony_ci        }
214cb93a386Sopenharmony_ci    };
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    bool hasPerspective = GrSLTypeVecLength(localCoordsVar.getType()) == 3;
217cb93a386Sopenharmony_ci    for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
218cb93a386Sopenharmony_ci        liftTransforms(liftTransforms, pipeline.getFragmentProcessor(i), hasPerspective);
219cb93a386Sopenharmony_ci    }
220cb93a386Sopenharmony_ci    return result;
221cb93a386Sopenharmony_ci}
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_civoid ProgramImpl::emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler) {
224cb93a386Sopenharmony_ci    // Because descendant varyings may be computed using the varyings of ancestor FPs we make
225cb93a386Sopenharmony_ci    // sure to visit the varyings according to FP pre-order traversal by dumping them into a
226cb93a386Sopenharmony_ci    // priority queue.
227cb93a386Sopenharmony_ci    using FPAndInfo = std::tuple<const GrFragmentProcessor*, TransformInfo>;
228cb93a386Sopenharmony_ci    auto compare = [](const FPAndInfo& a, const FPAndInfo& b) {
229cb93a386Sopenharmony_ci        return std::get<1>(a).traversalOrder > std::get<1>(b).traversalOrder;
230cb93a386Sopenharmony_ci    };
231cb93a386Sopenharmony_ci    std::priority_queue<FPAndInfo, std::vector<FPAndInfo>, decltype(compare)> pq(compare);
232cb93a386Sopenharmony_ci    std::for_each(fTransformVaryingsMap.begin(), fTransformVaryingsMap.end(), [&pq](auto entry) {
233cb93a386Sopenharmony_ci        pq.push(entry);
234cb93a386Sopenharmony_ci    });
235cb93a386Sopenharmony_ci    for (; !pq.empty(); pq.pop()) {
236cb93a386Sopenharmony_ci        const auto& [fp, info] = pq.top();
237cb93a386Sopenharmony_ci        // If we recorded a transform info, its sample matrix must be uniform
238cb93a386Sopenharmony_ci        SkASSERT(fp->sampleUsage().isUniformMatrix());
239cb93a386Sopenharmony_ci        GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
240cb93a386Sopenharmony_ci                *fp->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
241cb93a386Sopenharmony_ci        // Start with this matrix and accumulate additional matrices as we walk up the FP tree
242cb93a386Sopenharmony_ci        // to either the base coords or an ancestor FP that has an associated varying.
243cb93a386Sopenharmony_ci        SkString transformExpression = uniform.getName();
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci        // If we hit an ancestor with a varying on our walk up then save off the varying as the
246cb93a386Sopenharmony_ci        // input to our accumulated transformExpression. Start off assuming we'll reach the root.
247cb93a386Sopenharmony_ci        GrShaderVar inputCoords = info.inputCoords;
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci        for (const auto* base = fp->parent(); base; base = base->parent()) {
250cb93a386Sopenharmony_ci            if (auto iter = fTransformVaryingsMap.find(base); iter != fTransformVaryingsMap.end()) {
251cb93a386Sopenharmony_ci                // Can stop here, as this varying already holds all transforms from higher FPs
252cb93a386Sopenharmony_ci                // We'll apply the residual transformExpression we've accumulated up from our
253cb93a386Sopenharmony_ci                // starting FP to this varying.
254cb93a386Sopenharmony_ci                inputCoords = iter->second.varying.vsOutVar();
255cb93a386Sopenharmony_ci                break;
256cb93a386Sopenharmony_ci            } else if (base->sampleUsage().isUniformMatrix()) {
257cb93a386Sopenharmony_ci                // Accumulate any matrices along the path to either the original local/device coords
258cb93a386Sopenharmony_ci                // or a parent varying. Getting here means this FP was sampled with a uniform matrix
259cb93a386Sopenharmony_ci                // but all uses of coords below here in the FP hierarchy are beneath additional
260cb93a386Sopenharmony_ci                // matrix samples and thus this node wasn't assigned a varying.
261cb93a386Sopenharmony_ci                GrShaderVar parentUniform = uniformHandler->liftUniformToVertexShader(
262cb93a386Sopenharmony_ci                        *base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
263cb93a386Sopenharmony_ci                transformExpression.appendf(" * %s", parentUniform.getName().c_str());
264cb93a386Sopenharmony_ci            } else if (base->sampleUsage().isFragCoord()) {
265cb93a386Sopenharmony_ci                // Our chain of matrices starts here and is based on the device space position.
266cb93a386Sopenharmony_ci                break;
267cb93a386Sopenharmony_ci            } else {
268cb93a386Sopenharmony_ci                // This intermediate FP is just a pass through and doesn't need to be built
269cb93a386Sopenharmony_ci                // in to the expression, but we must visit its parents in case they add transforms.
270cb93a386Sopenharmony_ci                SkASSERT(base->sampleUsage().isPassThrough() || !base->sampleUsage().isSampled());
271cb93a386Sopenharmony_ci            }
272cb93a386Sopenharmony_ci        }
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci        SkString inputStr;
275cb93a386Sopenharmony_ci        if (inputCoords.getType() == kFloat2_GrSLType) {
276cb93a386Sopenharmony_ci            inputStr = SkStringPrintf("%s.xy1", inputCoords.getName().c_str());
277cb93a386Sopenharmony_ci        } else {
278cb93a386Sopenharmony_ci            SkASSERT(inputCoords.getType() == kFloat3_GrSLType);
279cb93a386Sopenharmony_ci            inputStr = inputCoords.getName();
280cb93a386Sopenharmony_ci        }
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci        vb->codeAppend("{\n");
283cb93a386Sopenharmony_ci        if (info.varying.type() == kFloat2_GrSLType) {
284cb93a386Sopenharmony_ci            if (vb->getProgramBuilder()->shaderCaps()->nonsquareMatrixSupport()) {
285cb93a386Sopenharmony_ci                vb->codeAppendf("%s = float3x2(%s) * %s",
286cb93a386Sopenharmony_ci                                info.varying.vsOut(),
287cb93a386Sopenharmony_ci                                transformExpression.c_str(),
288cb93a386Sopenharmony_ci                                inputStr.c_str());
289cb93a386Sopenharmony_ci            } else {
290cb93a386Sopenharmony_ci                vb->codeAppendf("%s = (%s * %s).xy",
291cb93a386Sopenharmony_ci                                info.varying.vsOut(),
292cb93a386Sopenharmony_ci                                transformExpression.c_str(),
293cb93a386Sopenharmony_ci                                inputStr.c_str());
294cb93a386Sopenharmony_ci            }
295cb93a386Sopenharmony_ci        } else {
296cb93a386Sopenharmony_ci            SkASSERT(info.varying.type() == kFloat3_GrSLType);
297cb93a386Sopenharmony_ci            vb->codeAppendf("%s = %s * %s",
298cb93a386Sopenharmony_ci                            info.varying.vsOut(),
299cb93a386Sopenharmony_ci                            transformExpression.c_str(),
300cb93a386Sopenharmony_ci                            inputStr.c_str());
301cb93a386Sopenharmony_ci        }
302cb93a386Sopenharmony_ci        vb->codeAppend(";\n");
303cb93a386Sopenharmony_ci        vb->codeAppend("}\n");
304cb93a386Sopenharmony_ci    }
305cb93a386Sopenharmony_ci    // We don't need this map anymore.
306cb93a386Sopenharmony_ci    fTransformVaryingsMap.clear();
307cb93a386Sopenharmony_ci}
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_civoid ProgramImpl::setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
310cb93a386Sopenharmony_ci                                    GrGLSLUniformHandler* uniformHandler,
311cb93a386Sopenharmony_ci                                    const char* outputName,
312cb93a386Sopenharmony_ci                                    UniformHandle* colorUniform) {
313cb93a386Sopenharmony_ci    SkASSERT(colorUniform);
314cb93a386Sopenharmony_ci    const char* stagedLocalVarName;
315cb93a386Sopenharmony_ci    *colorUniform = uniformHandler->addUniform(nullptr,
316cb93a386Sopenharmony_ci                                               kFragment_GrShaderFlag,
317cb93a386Sopenharmony_ci                                               kHalf4_GrSLType,
318cb93a386Sopenharmony_ci                                               "Color",
319cb93a386Sopenharmony_ci                                               &stagedLocalVarName);
320cb93a386Sopenharmony_ci    fragBuilder->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
321cb93a386Sopenharmony_ci    if (fragBuilder->getProgramBuilder()->shaderCaps()->mustObfuscateUniformColor()) {
322cb93a386Sopenharmony_ci        fragBuilder->codeAppendf("%s = max(%s, half4(0));", outputName, outputName);
323cb93a386Sopenharmony_ci    }
324cb93a386Sopenharmony_ci}
325cb93a386Sopenharmony_ci
326cb93a386Sopenharmony_civoid ProgramImpl::SetTransform(const GrGLSLProgramDataManager& pdman,
327cb93a386Sopenharmony_ci                               const GrShaderCaps& shaderCaps,
328cb93a386Sopenharmony_ci                               const UniformHandle& uniform,
329cb93a386Sopenharmony_ci                               const SkMatrix& matrix,
330cb93a386Sopenharmony_ci                               SkMatrix* state) {
331cb93a386Sopenharmony_ci    if (!uniform.isValid() || (state && SkMatrixPriv::CheapEqual(*state, matrix))) {
332cb93a386Sopenharmony_ci        // No update needed
333cb93a386Sopenharmony_ci        return;
334cb93a386Sopenharmony_ci    }
335cb93a386Sopenharmony_ci    if (state) {
336cb93a386Sopenharmony_ci        *state = matrix;
337cb93a386Sopenharmony_ci    }
338cb93a386Sopenharmony_ci    if (matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode()) {
339cb93a386Sopenharmony_ci        // ComputeMatrixKey and writeX() assume the uniform is a float4 (can't assert since nothing
340cb93a386Sopenharmony_ci        // is exposed on a handle, but should be caught lower down).
341cb93a386Sopenharmony_ci        float values[4] = {matrix.getScaleX(), matrix.getTranslateX(),
342cb93a386Sopenharmony_ci                           matrix.getScaleY(), matrix.getTranslateY()};
343cb93a386Sopenharmony_ci        pdman.set4fv(uniform, 1, values);
344cb93a386Sopenharmony_ci    } else {
345cb93a386Sopenharmony_ci        pdman.setSkMatrix(uniform, matrix);
346cb93a386Sopenharmony_ci    }
347cb93a386Sopenharmony_ci}
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_cistatic void write_passthrough_vertex_position(GrGLSLVertexBuilder* vertBuilder,
350cb93a386Sopenharmony_ci                                              const GrShaderVar& inPos,
351cb93a386Sopenharmony_ci                                              GrShaderVar* outPos) {
352cb93a386Sopenharmony_ci    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
353cb93a386Sopenharmony_ci    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
354cb93a386Sopenharmony_ci    outPos->set(inPos.getType(), outName.c_str());
355cb93a386Sopenharmony_ci    vertBuilder->codeAppendf("float%d %s = %s;",
356cb93a386Sopenharmony_ci                             GrSLTypeVecLength(inPos.getType()),
357cb93a386Sopenharmony_ci                             outName.c_str(),
358cb93a386Sopenharmony_ci                             inPos.getName().c_str());
359cb93a386Sopenharmony_ci}
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_cistatic void write_vertex_position(GrGLSLVertexBuilder* vertBuilder,
362cb93a386Sopenharmony_ci                                  GrGLSLUniformHandler* uniformHandler,
363cb93a386Sopenharmony_ci                                  const GrShaderCaps& shaderCaps,
364cb93a386Sopenharmony_ci                                  const GrShaderVar& inPos,
365cb93a386Sopenharmony_ci                                  const SkMatrix& matrix,
366cb93a386Sopenharmony_ci                                  const char* matrixName,
367cb93a386Sopenharmony_ci                                  GrShaderVar* outPos,
368cb93a386Sopenharmony_ci                                  ProgramImpl::UniformHandle* matrixUniform) {
369cb93a386Sopenharmony_ci    SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType);
370cb93a386Sopenharmony_ci    SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
371cb93a386Sopenharmony_ci
372cb93a386Sopenharmony_ci    if (matrix.isIdentity() && !shaderCaps.reducedShaderMode()) {
373cb93a386Sopenharmony_ci        write_passthrough_vertex_position(vertBuilder, inPos, outPos);
374cb93a386Sopenharmony_ci        return;
375cb93a386Sopenharmony_ci    }
376cb93a386Sopenharmony_ci    SkASSERT(matrixUniform);
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ci    bool useCompactTransform = matrix.isScaleTranslate() && !shaderCaps.reducedShaderMode();
379cb93a386Sopenharmony_ci    const char* mangledMatrixName;
380cb93a386Sopenharmony_ci    *matrixUniform = uniformHandler->addUniform(nullptr,
381cb93a386Sopenharmony_ci                                                kVertex_GrShaderFlag,
382cb93a386Sopenharmony_ci                                                useCompactTransform ? kFloat4_GrSLType
383cb93a386Sopenharmony_ci                                                                    : kFloat3x3_GrSLType,
384cb93a386Sopenharmony_ci                                                matrixName,
385cb93a386Sopenharmony_ci                                                &mangledMatrixName);
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci    if (inPos.getType() == kFloat3_GrSLType) {
388cb93a386Sopenharmony_ci        // A float3 stays a float3 whether or not the matrix adds perspective
389cb93a386Sopenharmony_ci        if (useCompactTransform) {
390cb93a386Sopenharmony_ci            vertBuilder->codeAppendf("float3 %s = %s.xz1 * %s + %s.yw0;\n",
391cb93a386Sopenharmony_ci                                     outName.c_str(),
392cb93a386Sopenharmony_ci                                     mangledMatrixName,
393cb93a386Sopenharmony_ci                                     inPos.getName().c_str(),
394cb93a386Sopenharmony_ci                                     mangledMatrixName);
395cb93a386Sopenharmony_ci        } else {
396cb93a386Sopenharmony_ci            vertBuilder->codeAppendf("float3 %s = %s * %s;\n",
397cb93a386Sopenharmony_ci                                     outName.c_str(),
398cb93a386Sopenharmony_ci                                     mangledMatrixName,
399cb93a386Sopenharmony_ci                                     inPos.getName().c_str());
400cb93a386Sopenharmony_ci        }
401cb93a386Sopenharmony_ci        outPos->set(kFloat3_GrSLType, outName.c_str());
402cb93a386Sopenharmony_ci        return;
403cb93a386Sopenharmony_ci    }
404cb93a386Sopenharmony_ci    if (matrix.hasPerspective()) {
405cb93a386Sopenharmony_ci        // A float2 is promoted to a float3 if we add perspective via the matrix
406cb93a386Sopenharmony_ci        SkASSERT(!useCompactTransform);
407cb93a386Sopenharmony_ci        vertBuilder->codeAppendf("float3 %s = (%s * %s.xy1);",
408cb93a386Sopenharmony_ci                                 outName.c_str(),
409cb93a386Sopenharmony_ci                                 mangledMatrixName,
410cb93a386Sopenharmony_ci                                 inPos.getName().c_str());
411cb93a386Sopenharmony_ci        outPos->set(kFloat3_GrSLType, outName.c_str());
412cb93a386Sopenharmony_ci        return;
413cb93a386Sopenharmony_ci    }
414cb93a386Sopenharmony_ci    if (useCompactTransform) {
415cb93a386Sopenharmony_ci        vertBuilder->codeAppendf("float2 %s = %s.xz * %s + %s.yw;\n",
416cb93a386Sopenharmony_ci                                 outName.c_str(),
417cb93a386Sopenharmony_ci                                 mangledMatrixName,
418cb93a386Sopenharmony_ci                                 inPos.getName().c_str(),
419cb93a386Sopenharmony_ci                                 mangledMatrixName);
420cb93a386Sopenharmony_ci    } else if (shaderCaps.nonsquareMatrixSupport()) {
421cb93a386Sopenharmony_ci        vertBuilder->codeAppendf("float2 %s = float3x2(%s) * %s.xy1;\n",
422cb93a386Sopenharmony_ci                                 outName.c_str(),
423cb93a386Sopenharmony_ci                                 mangledMatrixName,
424cb93a386Sopenharmony_ci                                 inPos.getName().c_str());
425cb93a386Sopenharmony_ci    } else {
426cb93a386Sopenharmony_ci        vertBuilder->codeAppendf("float2 %s = (%s * %s.xy1).xy;\n",
427cb93a386Sopenharmony_ci                                 outName.c_str(),
428cb93a386Sopenharmony_ci                                 mangledMatrixName,
429cb93a386Sopenharmony_ci                                 inPos.getName().c_str());
430cb93a386Sopenharmony_ci    }
431cb93a386Sopenharmony_ci    outPos->set(kFloat2_GrSLType, outName.c_str());
432cb93a386Sopenharmony_ci}
433cb93a386Sopenharmony_ci
434cb93a386Sopenharmony_civoid ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
435cb93a386Sopenharmony_ci                                      GrGPArgs* gpArgs,
436cb93a386Sopenharmony_ci                                      const char* posName) {
437cb93a386Sopenharmony_ci    // writeOutputPosition assumes the incoming pos name points to a float2 variable
438cb93a386Sopenharmony_ci    GrShaderVar inPos(posName, kFloat2_GrSLType);
439cb93a386Sopenharmony_ci    write_passthrough_vertex_position(vertBuilder, inPos, &gpArgs->fPositionVar);
440cb93a386Sopenharmony_ci}
441cb93a386Sopenharmony_ci
442cb93a386Sopenharmony_civoid ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
443cb93a386Sopenharmony_ci                                      GrGLSLUniformHandler* uniformHandler,
444cb93a386Sopenharmony_ci                                      const GrShaderCaps& shaderCaps,
445cb93a386Sopenharmony_ci                                      GrGPArgs* gpArgs,
446cb93a386Sopenharmony_ci                                      const char* posName,
447cb93a386Sopenharmony_ci                                      const SkMatrix& mat,
448cb93a386Sopenharmony_ci                                      UniformHandle* viewMatrixUniform) {
449cb93a386Sopenharmony_ci    GrShaderVar inPos(posName, kFloat2_GrSLType);
450cb93a386Sopenharmony_ci    write_vertex_position(vertBuilder,
451cb93a386Sopenharmony_ci                          uniformHandler,
452cb93a386Sopenharmony_ci                          shaderCaps,
453cb93a386Sopenharmony_ci                          inPos,
454cb93a386Sopenharmony_ci                          mat,
455cb93a386Sopenharmony_ci                          "viewMatrix",
456cb93a386Sopenharmony_ci                          &gpArgs->fPositionVar,
457cb93a386Sopenharmony_ci                          viewMatrixUniform);
458cb93a386Sopenharmony_ci}
459cb93a386Sopenharmony_ci
460cb93a386Sopenharmony_civoid ProgramImpl::WriteLocalCoord(GrGLSLVertexBuilder* vertBuilder,
461cb93a386Sopenharmony_ci                                  GrGLSLUniformHandler* uniformHandler,
462cb93a386Sopenharmony_ci                                  const GrShaderCaps& shaderCaps,
463cb93a386Sopenharmony_ci                                  GrGPArgs* gpArgs,
464cb93a386Sopenharmony_ci                                  GrShaderVar localVar,
465cb93a386Sopenharmony_ci                                  const SkMatrix& localMatrix,
466cb93a386Sopenharmony_ci                                  UniformHandle* localMatrixUniform) {
467cb93a386Sopenharmony_ci    write_vertex_position(vertBuilder,
468cb93a386Sopenharmony_ci                          uniformHandler,
469cb93a386Sopenharmony_ci                          shaderCaps,
470cb93a386Sopenharmony_ci                          localVar,
471cb93a386Sopenharmony_ci                          localMatrix,
472cb93a386Sopenharmony_ci                          "localMatrix",
473cb93a386Sopenharmony_ci                          &gpArgs->fLocalCoordVar,
474cb93a386Sopenharmony_ci                          localMatrixUniform);
475cb93a386Sopenharmony_ci}
476