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 | |
14 | void GrGLSLFragmentProcessor::setData(const GrGLSLProgramDataManager& pdman, |
15 | const GrFragmentProcessor& processor) { |
16 | this->onSetData(pdman, processor); |
17 | } |
18 | |
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 | "_output" , |
35 | "_input" , |
36 | "_coords" , |
37 | coordVars); |
38 | fFunctionNames[childIndex] = |
39 | fragBuilder->writeProcessorFunction(this->childProcessor(childIndex), childArgs); |
40 | } |
41 | } |
42 | |
43 | SkString GrGLSLFragmentProcessor::invokeChild(int childIndex, const char* inputColor, |
44 | EmitArgs& args, SkSL::String skslCoords) { |
45 | if (!inputColor) { |
46 | inputColor = args.fInputColor; |
47 | } |
48 | |
49 | SkASSERT(childIndex >= 0); |
50 | const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex); |
51 | if (!childProc) { |
52 | return SkString(inputColor); |
53 | } |
54 | |
55 | this->emitChildFunction(childIndex, args); |
56 | |
57 | if (skslCoords.empty()) { |
58 | // Empty coords means passing through the coords of the parent |
59 | skslCoords = args.fSampleCoord; |
60 | } |
61 | |
62 | if (childProc->isSampledWithExplicitCoords()) { |
63 | // The child's function takes a half4 color and a float2 coordinate |
64 | return SkStringPrintf("%s(%s, %s)" , fFunctionNames[childIndex].c_str(), |
65 | inputColor, skslCoords.c_str()); |
66 | } else { |
67 | // The child's function just takes a color. We should only get here for a call to sample |
68 | // without explicit coordinates. Assert that the child has no sample matrix and skslCoords |
69 | // is _coords (a uniform matrix sample call would go through invokeChildWithMatrix, and if |
70 | // a child was sampled with sample(matrix) and sample(), it should have been flagged as |
71 | // variable and hit the branch above). |
72 | SkASSERT(skslCoords == args.fSampleCoord && !childProc->sampleUsage().hasMatrix()); |
73 | return SkStringPrintf("%s(%s)" , fFunctionNames[childIndex].c_str(), inputColor); |
74 | } |
75 | } |
76 | |
77 | SkString GrGLSLFragmentProcessor::invokeChildWithMatrix(int childIndex, const char* inputColor, |
78 | EmitArgs& args, |
79 | SkSL::String skslMatrix) { |
80 | if (!inputColor) { |
81 | inputColor = args.fInputColor; |
82 | } |
83 | |
84 | SkASSERT(childIndex >= 0); |
85 | const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex); |
86 | if (!childProc) { |
87 | return SkString(inputColor); |
88 | } |
89 | |
90 | this->emitChildFunction(childIndex, args); |
91 | |
92 | SkASSERT(childProc->sampleUsage().hasMatrix()); |
93 | |
94 | // Since this is uniform, the provided sksl expression should exactly match the expression |
95 | // stored on the FP, or it should match the mangled uniform name. |
96 | if (skslMatrix.empty()) { |
97 | // Empty matrix expression replaces with the sample matrix expression stored on the FP, but |
98 | // that is only valid for uniform sampled FPs |
99 | SkASSERT(childProc->sampleUsage().hasUniformMatrix()); |
100 | skslMatrix.assign(childProc->sampleUsage().fExpression); |
101 | } |
102 | |
103 | if (childProc->sampleUsage().hasUniformMatrix()) { |
104 | // Attempt to resolve the uniform name from the raw name stored in the sample usage. |
105 | // Since this is uniform, the provided expression better match what was given to the FP. |
106 | SkASSERT(childProc->sampleUsage().fExpression == skslMatrix); |
107 | GrShaderVar uniform = args.fUniformHandler->getUniformMapping( |
108 | args.fFp, SkString(childProc->sampleUsage().fExpression)); |
109 | if (uniform.getType() != kVoid_GrSLType) { |
110 | // Found the uniform, so replace the expression with the actual uniform name |
111 | SkASSERT(uniform.getType() == kFloat3x3_GrSLType); |
112 | skslMatrix = uniform.getName().c_str(); |
113 | } // else assume it's a constant expression |
114 | } |
115 | |
116 | // Produce a string containing the call to the helper function. sample(matrix) is special where |
117 | // the provided skslMatrix expression means that the child FP should be invoked with coords |
118 | // equal to matrix * parent coords. However, if matrix is a uniform expression AND the parent |
119 | // coords were produced by uniform transforms, then this expression is lifted to a vertex |
120 | // shader and is stored in a varying. In that case, childProc will not have a variable sample |
121 | // matrix and will not be sampled explicitly, so its function signature will not take in coords. |
122 | // |
123 | // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke |
124 | // the function. |
125 | if (childProc->isSampledWithExplicitCoords()) { |
126 | // Only check perspective for this specific matrix transform, not the aggregate FP property. |
127 | // Any parent perspective will have already been applied when evaluated in the FS. |
128 | if (childProc->sampleUsage().fHasPerspective) { |
129 | return SkStringPrintf("%s(%s, proj((%s) * %s.xy1))" , fFunctionNames[childIndex].c_str(), |
130 | inputColor, skslMatrix.c_str(), args.fSampleCoord); |
131 | } else { |
132 | return SkStringPrintf("%s(%s, ((%s) * %s.xy1).xy)" , fFunctionNames[childIndex].c_str(), |
133 | inputColor, skslMatrix.c_str(), args.fSampleCoord); |
134 | } |
135 | } else { |
136 | // A variable matrix expression should mark the child as explicitly sampled. A no-op |
137 | // matrix should match sample(color), not sample(color, matrix). |
138 | SkASSERT(childProc->sampleUsage().hasUniformMatrix()); |
139 | |
140 | // Since this is uniform and not explicitly sampled, it's transform has been promoted to |
141 | // the vertex shader and the signature doesn't take a float2 coord. |
142 | return SkStringPrintf("%s(%s)" , fFunctionNames[childIndex].c_str(), inputColor); |
143 | } |
144 | } |
145 | |
146 | ////////////////////////////////////////////////////////////////////////////// |
147 | |
148 | GrGLSLFragmentProcessor::Iter::Iter(std::unique_ptr<GrGLSLFragmentProcessor> fps[], int cnt) { |
149 | for (int i = cnt - 1; i >= 0; --i) { |
150 | fFPStack.push_back(fps[i].get()); |
151 | } |
152 | } |
153 | |
154 | GrGLSLFragmentProcessor::ParallelIter::ParallelIter(const GrFragmentProcessor& fp, |
155 | GrGLSLFragmentProcessor& glslFP) |
156 | : fpIter(fp), glslIter(glslFP) {} |
157 | |
158 | GrGLSLFragmentProcessor::ParallelIter& GrGLSLFragmentProcessor::ParallelIter::operator++() { |
159 | ++fpIter; |
160 | ++glslIter; |
161 | SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter)); |
162 | return *this; |
163 | } |
164 | |
165 | std::tuple<const GrFragmentProcessor&, GrGLSLFragmentProcessor&> |
166 | GrGLSLFragmentProcessor::ParallelIter::operator*() const { |
167 | return {*fpIter, *glslIter}; |
168 | } |
169 | |
170 | bool GrGLSLFragmentProcessor::ParallelIter::operator==(const ParallelIterEnd& end) const { |
171 | SkASSERT(static_cast<bool>(fpIter) == static_cast<bool>(glslIter)); |
172 | return !fpIter; |
173 | } |
174 | |
175 | GrGLSLFragmentProcessor& GrGLSLFragmentProcessor::Iter::operator*() const { |
176 | return *fFPStack.back(); |
177 | } |
178 | |
179 | GrGLSLFragmentProcessor* GrGLSLFragmentProcessor::Iter::operator->() const { |
180 | return fFPStack.back(); |
181 | } |
182 | |
183 | GrGLSLFragmentProcessor::Iter& GrGLSLFragmentProcessor::Iter::operator++() { |
184 | SkASSERT(!fFPStack.empty()); |
185 | const GrGLSLFragmentProcessor* back = fFPStack.back(); |
186 | fFPStack.pop_back(); |
187 | for (int i = back->numChildProcessors() - 1; i >= 0; --i) { |
188 | if (auto child = back->childProcessor(i)) { |
189 | fFPStack.push_back(child); |
190 | } |
191 | } |
192 | return *this; |
193 | } |
194 | |
195 | GrGLSLFragmentProcessor::ParallelRange::ParallelRange(const GrFragmentProcessor& fp, |
196 | GrGLSLFragmentProcessor& glslFP) |
197 | : fInitialFP(fp), fInitialGLSLFP(glslFP) {} |
198 | |