• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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/GrFragmentProcessor.h"
9 #include "src/gpu/GrProcessor.h"
10 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
11 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
12 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
13 
setData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & processor)14 void GrGLSLFragmentProcessor::setData(const GrGLSLProgramDataManager& pdman,
15                                       const GrFragmentProcessor& processor) {
16     this->onSetData(pdman, processor);
17 }
18 
emitChildFunction(int childIndex,EmitArgs & args)19 void GrGLSLFragmentProcessor::emitChildFunction(int childIndex, EmitArgs& args) {
20     SkASSERT(childIndex >= 0);
21     SkASSERT(args.fFp.childProcessor(childIndex));
22     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
23     while (childIndex >= (int) fFunctionNames.size()) {
24         fFunctionNames.emplace_back();
25     }
26 
27     // Emit the child's helper function if this is the first time we've seen a call
28     if (fFunctionNames[childIndex].size() == 0) {
29         TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex);
30         EmitArgs childArgs(fragBuilder,
31                            args.fUniformHandler,
32                            args.fShaderCaps,
33                            *args.fFp.childProcessor(childIndex),
34                            "_input",
35                            "_coords",
36                            coordVars);
37         fFunctionNames[childIndex] =
38                 fragBuilder->writeProcessorFunction(this->childProcessor(childIndex), childArgs);
39     }
40 }
41 
invokeChild(int childIndex,const char * inputColor,EmitArgs & args,SkSL::String skslCoords)42 SkString GrGLSLFragmentProcessor::invokeChild(int childIndex, const char* inputColor,
43                                               EmitArgs& args, SkSL::String skslCoords) {
44     if (!inputColor) {
45         inputColor = args.fInputColor;
46     }
47 
48     SkASSERT(childIndex >= 0);
49     const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
50     if (!childProc) {
51         return SkString(inputColor);
52     }
53 
54     this->emitChildFunction(childIndex, args);
55 
56     if (skslCoords.empty()) {
57         // Empty coords means passing through the coords of the parent
58         skslCoords = args.fSampleCoord;
59     }
60 
61     if (childProc->isSampledWithExplicitCoords()) {
62         // The child's function takes a half4 color and a float2 coordinate
63         return SkStringPrintf("%s(%s, %s)", fFunctionNames[childIndex].c_str(),
64                                             inputColor, skslCoords.c_str());
65     } else {
66         // The child's function just takes a color. We should only get here for a call to sample
67         // without explicit coordinates. Assert that the child has no sample matrix and skslCoords
68         // is _coords (a uniform matrix sample call would go through invokeChildWithMatrix).
69         SkASSERT(skslCoords == args.fSampleCoord && childProc->sampleUsage().isPassThrough());
70         return SkStringPrintf("%s(%s)", fFunctionNames[childIndex].c_str(), inputColor);
71     }
72 }
73 
invokeChildWithMatrix(int childIndex,const char * inputColor,EmitArgs & args)74 SkString GrGLSLFragmentProcessor::invokeChildWithMatrix(int childIndex, const char* inputColor,
75                                                         EmitArgs& args) {
76     if (!inputColor) {
77         inputColor = args.fInputColor;
78     }
79 
80     SkASSERT(childIndex >= 0);
81     const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
82     if (!childProc) {
83         return SkString(inputColor);
84     }
85 
86     this->emitChildFunction(childIndex, args);
87 
88     SkASSERT(childProc->sampleUsage().isUniformMatrix());
89 
90     // Empty matrix expression replaces with the sample matrix expression stored on the FP, but
91     // that is only valid for uniform sampled FPs
92     SkString matrixExpr(childProc->sampleUsage().fExpression);
93 
94     // Attempt to resolve the uniform name from the raw name stored in the sample usage.
95     GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
96             args.fFp, SkString(childProc->sampleUsage().fExpression));
97     if (uniform.getType() != kVoid_GrSLType) {
98         // Found the uniform, so replace the expression with the actual uniform name
99         SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
100         matrixExpr = uniform.getName().c_str();
101     }  // else assume it's a constant expression
102 
103     // Produce a string containing the call to the helper function. We have a const-or-uniform
104     // expression containing our transform (matrixExpr). If the parent coords were produced by
105     // uniform transforms, then the entire expression (matrixExpr * coords) is lifted to a vertex
106     // shader and is stored in a varying. In that case, childProc will not be sampled explicitly,
107     // so its function signature will not take in coords.
108     //
109     // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
110     // the function.
111     if (childProc->isSampledWithExplicitCoords()) {
112         // Only check perspective for this specific matrix transform, not the aggregate FP property.
113         // Any parent perspective will have already been applied when evaluated in the FS.
114         if (childProc->sampleUsage().fHasPerspective) {
115             return SkStringPrintf("%s(%s, proj((%s) * %s.xy1))", fFunctionNames[childIndex].c_str(),
116                                   inputColor, matrixExpr.c_str(), args.fSampleCoord);
117         } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
118             return SkStringPrintf("%s(%s, float3x2(%s) * %s.xy1)",
119                                   fFunctionNames[childIndex].c_str(), inputColor,
120                                   matrixExpr.c_str(), args.fSampleCoord);
121         } else {
122             return SkStringPrintf("%s(%s, ((%s) * %s.xy1).xy)", fFunctionNames[childIndex].c_str(),
123                                   inputColor, matrixExpr.c_str(), args.fSampleCoord);
124         }
125     } else {
126         // Since this is uniform and not explicitly sampled, it's transform has been promoted to
127         // the vertex shader and the signature doesn't take a float2 coord.
128         return SkStringPrintf("%s(%s)", fFunctionNames[childIndex].c_str(), inputColor);
129     }
130 }
131 
132 //////////////////////////////////////////////////////////////////////////////
133 
Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[],int cnt)134 GrGLSLFragmentProcessor::Iter::Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[], int cnt) {
135     for (int i = cnt - 1; i >= 0; --i) {
136         fFPStack.push_back(fps[i].get());
137     }
138 }
139 
ParallelIter(const GrFragmentProcessor & fp,GrGLSLFragmentProcessor & glslFP)140 GrGLSLFragmentProcessor::ParallelIter::ParallelIter(const GrFragmentProcessor& fp,
141                                                     GrGLSLFragmentProcessor& glslFP)
142         : fpIter(fp), glslIter(glslFP) {}
143 
operator ++()144 GrGLSLFragmentProcessor::ParallelIter& GrGLSLFragmentProcessor::ParallelIter::operator++() {
145     ++fpIter;
146     ++glslIter;
147     SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter));
148     return *this;
149 }
150 
151 std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&>
operator *() const152 GrGLSLFragmentProcessor::ParallelIter::operator*() const {
153     return {*fpIter, *glslIter};
154 }
155 
operator ==(const ParallelIterEnd & end) const156 bool GrGLSLFragmentProcessor::ParallelIter::operator==(const ParallelIterEnd& end) const {
157     SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter));
158     return !fpIter;
159 }
160 
operator *() const161 GrGLSLFragmentProcessor& GrGLSLFragmentProcessor::Iter::operator*() const {
162     return *fFPStack.back();
163 }
164 
operator ->() const165 GrGLSLFragmentProcessor* GrGLSLFragmentProcessor::Iter::operator->() const {
166     return fFPStack.back();
167 }
168 
operator ++()169 GrGLSLFragmentProcessor::Iter& GrGLSLFragmentProcessor::Iter::operator++() {
170     SkASSERT(!fFPStack.empty());
171     const GrGLSLFragmentProcessor* back = fFPStack.back();
172     fFPStack.pop_back();
173     for (int i = back->numChildProcessors() - 1; i >= 0; --i) {
174         if (auto child = back->childProcessor(i)) {
175             fFPStack.push_back(child);
176         }
177     }
178     return *this;
179 }
180 
ParallelRange(const GrFragmentProcessor & fp,GrGLSLFragmentProcessor & glslFP)181 GrGLSLFragmentProcessor::ParallelRange::ParallelRange(const GrFragmentProcessor& fp,
182                                                       GrGLSLFragmentProcessor& glslFP)
183         : fInitialFP(fp), fInitialGLSLFP(glslFP) {}
184