• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // RewriteCubeMapSamplersAs2DArray: Change samplerCube samplers to sampler2DArray for seamful cube
7 // map emulation.
8 //
9 
10 #include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
11 
12 #include "compiler/translator/Compiler.h"
13 #include "compiler/translator/ImmutableStringBuilder.h"
14 #include "compiler/translator/StaticType.h"
15 #include "compiler/translator/SymbolTable.h"
16 #include "compiler/translator/tree_util/IntermNode_util.h"
17 #include "compiler/translator/tree_util/IntermTraverse.h"
18 #include "compiler/translator/tree_util/ReplaceVariable.h"
19 
20 namespace sh
21 {
22 namespace
23 {
24 constexpr ImmutableString kCoordTransformFuncName("ANGLECubeMapCoordTransform");
25 constexpr ImmutableString kCoordTransformFuncNameImplicit("ANGLECubeMapCoordTransformImplicit");
26 
DerivativeQuotient(TIntermTyped * u,TIntermTyped * du,TIntermTyped * v,TIntermTyped * dv,TIntermTyped * vRecip)27 TIntermTyped *DerivativeQuotient(TIntermTyped *u,
28                                  TIntermTyped *du,
29                                  TIntermTyped *v,
30                                  TIntermTyped *dv,
31                                  TIntermTyped *vRecip)
32 {
33     // (du v - dv u) / v^2
34     return new TIntermBinary(
35         EOpMul,
36         new TIntermBinary(EOpSub, new TIntermBinary(EOpMul, du->deepCopy(), v->deepCopy()),
37                           new TIntermBinary(EOpMul, dv->deepCopy(), u->deepCopy())),
38         new TIntermBinary(EOpMul, vRecip->deepCopy(), vRecip->deepCopy()));
39 }
40 
Swizzle1(TIntermTyped * array,int i)41 TIntermTyped *Swizzle1(TIntermTyped *array, int i)
42 {
43     return new TIntermSwizzle(array, {i});
44 }
45 
IndexDirect(TIntermTyped * array,int i)46 TIntermTyped *IndexDirect(TIntermTyped *array, int i)
47 {
48     return new TIntermBinary(EOpIndexDirect, array, CreateIndexNode(i));
49 }
50 
51 // Generated the common transformation in each coord transformation case.  See comment in
52 // declareCoordTranslationFunction().  Called with P, dPdx and dPdy.
TransformXMajor(TIntermBlock * block,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * uc,TIntermTyped * vc)53 void TransformXMajor(TIntermBlock *block,
54                      TIntermTyped *x,
55                      TIntermTyped *y,
56                      TIntermTyped *z,
57                      TIntermTyped *uc,
58                      TIntermTyped *vc)
59 {
60     // uc = -sign(x)*z
61     // vc = -y
62     TIntermTyped *signX = new TIntermUnary(EOpSign, x->deepCopy(), nullptr);
63 
64     TIntermTyped *ucValue =
65         new TIntermUnary(EOpNegative, new TIntermBinary(EOpMul, signX, z->deepCopy()), nullptr);
66     TIntermTyped *vcValue = new TIntermUnary(EOpNegative, y->deepCopy(), nullptr);
67 
68     block->appendStatement(new TIntermBinary(EOpAssign, uc->deepCopy(), ucValue));
69     block->appendStatement(new TIntermBinary(EOpAssign, vc->deepCopy(), vcValue));
70 }
71 
TransformDerivativeXMajor(TIntermBlock * block,TSymbolTable * symbolTable,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * dx,TIntermTyped * dy,TIntermTyped * dz,TIntermTyped * du,TIntermTyped * dv,TIntermTyped * xRecip)72 void TransformDerivativeXMajor(TIntermBlock *block,
73                                TSymbolTable *symbolTable,
74                                TIntermTyped *x,
75                                TIntermTyped *y,
76                                TIntermTyped *z,
77                                TIntermTyped *dx,
78                                TIntermTyped *dy,
79                                TIntermTyped *dz,
80                                TIntermTyped *du,
81                                TIntermTyped *dv,
82                                TIntermTyped *xRecip)
83 {
84     // Only the magnitude of the derivative matters, so we ignore the sign(x)
85     // and the negations.
86     TIntermTyped *duValue = DerivativeQuotient(z, dz, x, dx, xRecip);
87     TIntermTyped *dvValue = DerivativeQuotient(y, dy, x, dx, xRecip);
88     duValue               = new TIntermBinary(EOpMul, duValue, CreateFloatNode(0.5f));
89     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
90     block->appendStatement(new TIntermBinary(EOpAssign, du->deepCopy(), duValue));
91     block->appendStatement(new TIntermBinary(EOpAssign, dv->deepCopy(), dvValue));
92 }
93 
TransformImplicitDerivativeXMajor(TIntermBlock * block,TIntermTyped * dOuter,TIntermTyped * du,TIntermTyped * dv)94 void TransformImplicitDerivativeXMajor(TIntermBlock *block,
95                                        TIntermTyped *dOuter,
96                                        TIntermTyped *du,
97                                        TIntermTyped *dv)
98 {
99     block->appendStatement(
100         new TIntermBinary(EOpAssign, du->deepCopy(), Swizzle1(dOuter->deepCopy(), 2)));
101     block->appendStatement(
102         new TIntermBinary(EOpAssign, dv->deepCopy(), Swizzle1(dOuter->deepCopy(), 1)));
103 }
104 
TransformYMajor(TIntermBlock * block,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * uc,TIntermTyped * vc)105 void TransformYMajor(TIntermBlock *block,
106                      TIntermTyped *x,
107                      TIntermTyped *y,
108                      TIntermTyped *z,
109                      TIntermTyped *uc,
110                      TIntermTyped *vc)
111 {
112     // uc = x
113     // vc = sign(y)*z
114     TIntermTyped *signY = new TIntermUnary(EOpSign, y->deepCopy(), nullptr);
115 
116     TIntermTyped *ucValue = x->deepCopy();
117     TIntermTyped *vcValue = new TIntermBinary(EOpMul, signY, z->deepCopy());
118 
119     block->appendStatement(new TIntermBinary(EOpAssign, uc->deepCopy(), ucValue));
120     block->appendStatement(new TIntermBinary(EOpAssign, vc->deepCopy(), vcValue));
121 }
122 
TransformDerivativeYMajor(TIntermBlock * block,TSymbolTable * symbolTable,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * dx,TIntermTyped * dy,TIntermTyped * dz,TIntermTyped * du,TIntermTyped * dv,TIntermTyped * yRecip)123 void TransformDerivativeYMajor(TIntermBlock *block,
124                                TSymbolTable *symbolTable,
125                                TIntermTyped *x,
126                                TIntermTyped *y,
127                                TIntermTyped *z,
128                                TIntermTyped *dx,
129                                TIntermTyped *dy,
130                                TIntermTyped *dz,
131                                TIntermTyped *du,
132                                TIntermTyped *dv,
133                                TIntermTyped *yRecip)
134 {
135     // Only the magnitude of the derivative matters, so we ignore the sign(x)
136     // and the negations.
137     TIntermTyped *duValue = DerivativeQuotient(x, dx, y, dy, yRecip);
138     TIntermTyped *dvValue = DerivativeQuotient(z, dz, y, dy, yRecip);
139     duValue               = new TIntermBinary(EOpMul, duValue, CreateFloatNode(0.5f));
140     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
141     block->appendStatement(new TIntermBinary(EOpAssign, du->deepCopy(), duValue));
142     block->appendStatement(new TIntermBinary(EOpAssign, dv->deepCopy(), dvValue));
143 }
144 
TransformImplicitDerivativeYMajor(TIntermBlock * block,TIntermTyped * dOuter,TIntermTyped * du,TIntermTyped * dv)145 void TransformImplicitDerivativeYMajor(TIntermBlock *block,
146                                        TIntermTyped *dOuter,
147                                        TIntermTyped *du,
148                                        TIntermTyped *dv)
149 {
150     block->appendStatement(
151         new TIntermBinary(EOpAssign, du->deepCopy(), Swizzle1(dOuter->deepCopy(), 0)));
152     block->appendStatement(
153         new TIntermBinary(EOpAssign, dv->deepCopy(), Swizzle1(dOuter->deepCopy(), 2)));
154 }
155 
TransformZMajor(TIntermBlock * block,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * uc,TIntermTyped * vc)156 void TransformZMajor(TIntermBlock *block,
157                      TIntermTyped *x,
158                      TIntermTyped *y,
159                      TIntermTyped *z,
160                      TIntermTyped *uc,
161                      TIntermTyped *vc)
162 {
163     // uc = size(z)*x
164     // vc = -y
165     TIntermTyped *signZ = new TIntermUnary(EOpSign, z->deepCopy(), nullptr);
166 
167     TIntermTyped *ucValue = new TIntermBinary(EOpMul, signZ, x->deepCopy());
168     TIntermTyped *vcValue = new TIntermUnary(EOpNegative, y->deepCopy(), nullptr);
169 
170     block->appendStatement(new TIntermBinary(EOpAssign, uc->deepCopy(), ucValue));
171     block->appendStatement(new TIntermBinary(EOpAssign, vc->deepCopy(), vcValue));
172 }
173 
TransformDerivativeZMajor(TIntermBlock * block,TSymbolTable * symbolTable,TIntermTyped * x,TIntermTyped * y,TIntermTyped * z,TIntermTyped * dx,TIntermTyped * dy,TIntermTyped * dz,TIntermTyped * du,TIntermTyped * dv,TIntermTyped * zRecip)174 void TransformDerivativeZMajor(TIntermBlock *block,
175                                TSymbolTable *symbolTable,
176                                TIntermTyped *x,
177                                TIntermTyped *y,
178                                TIntermTyped *z,
179                                TIntermTyped *dx,
180                                TIntermTyped *dy,
181                                TIntermTyped *dz,
182                                TIntermTyped *du,
183                                TIntermTyped *dv,
184                                TIntermTyped *zRecip)
185 {
186     // Only the magnitude of the derivative matters, so we ignore the sign(x)
187     // and the negations.
188     TIntermTyped *duValue = DerivativeQuotient(x, dx, z, dz, zRecip);
189     TIntermTyped *dvValue = DerivativeQuotient(y, dy, z, dz, zRecip);
190     duValue               = new TIntermBinary(EOpMul, duValue, CreateFloatNode(0.5f));
191     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
192     block->appendStatement(new TIntermBinary(EOpAssign, du->deepCopy(), duValue));
193     block->appendStatement(new TIntermBinary(EOpAssign, dv->deepCopy(), dvValue));
194 }
195 
TransformImplicitDerivativeZMajor(TIntermBlock * block,TIntermTyped * dOuter,TIntermTyped * du,TIntermTyped * dv)196 void TransformImplicitDerivativeZMajor(TIntermBlock *block,
197                                        TIntermTyped *dOuter,
198                                        TIntermTyped *du,
199                                        TIntermTyped *dv)
200 {
201     block->appendStatement(
202         new TIntermBinary(EOpAssign, du->deepCopy(), Swizzle1(dOuter->deepCopy(), 0)));
203     block->appendStatement(
204         new TIntermBinary(EOpAssign, dv->deepCopy(), Swizzle1(dOuter->deepCopy(), 1)));
205 }
206 
207 class RewriteCubeMapSamplersAs2DArrayTraverser : public TIntermTraverser
208 {
209   public:
RewriteCubeMapSamplersAs2DArrayTraverser(TSymbolTable * symbolTable,bool isFragmentShader)210     RewriteCubeMapSamplersAs2DArrayTraverser(TSymbolTable *symbolTable, bool isFragmentShader)
211         : TIntermTraverser(true, true, true, symbolTable),
212           mCubeXYZToArrayUVL(nullptr),
213           mCubeXYZToArrayUVLImplicit(nullptr),
214           mIsFragmentShader(isFragmentShader),
215           mCoordTranslationFunctionDecl(nullptr),
216           mCoordTranslationFunctionImplicitDecl(nullptr)
217     {}
218 
visitDeclaration(Visit visit,TIntermDeclaration * node)219     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
220     {
221         if (visit != PreVisit)
222         {
223             return true;
224         }
225 
226         const TIntermSequence &sequence = *(node->getSequence());
227 
228         TIntermTyped *variable = sequence.front()->getAsTyped();
229         const TType &type      = variable->getType();
230         bool isSamplerCube     = type.getQualifier() == EvqUniform && type.isSamplerCube();
231 
232         if (isSamplerCube)
233         {
234             // Samplers cannot have initializers, so the declaration must necessarily be a symbol.
235             TIntermSymbol *samplerVariable = variable->getAsSymbolNode();
236             ASSERT(samplerVariable != nullptr);
237 
238             declareSampler2DArray(&samplerVariable->variable(), node);
239             return false;
240         }
241 
242         return true;
243     }
244 
visitFunctionPrototype(TIntermFunctionPrototype * node)245     void visitFunctionPrototype(TIntermFunctionPrototype *node) override
246     {
247         const TFunction *function = node->getFunction();
248         // Go over the parameters and replace the samplerCube arguments with a sampler2DArray.
249         mRetyper.visitFunctionPrototype();
250         for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
251         {
252             const TVariable *param = function->getParam(paramIndex);
253             TVariable *replacement = convertFunctionParameter(node, param);
254             if (replacement)
255             {
256                 mRetyper.replaceFunctionParam(param, replacement);
257             }
258         }
259 
260         TIntermFunctionPrototype *replacementPrototype =
261             mRetyper.convertFunctionPrototype(mSymbolTable, function);
262         if (replacementPrototype)
263         {
264             queueReplacement(replacementPrototype, OriginalNode::IS_DROPPED);
265         }
266     }
267 
visitAggregate(Visit visit,TIntermAggregate * node)268     bool visitAggregate(Visit visit, TIntermAggregate *node) override
269     {
270         if (visit == PreVisit)
271         {
272             mRetyper.preVisitAggregate();
273         }
274 
275         if (visit != PostVisit)
276         {
277             return true;
278         }
279 
280         if (node->getOp() == EOpCallBuiltInFunction)
281         {
282             convertBuiltinFunction(node);
283         }
284         else if (node->getOp() == EOpCallFunctionInAST)
285         {
286             TIntermAggregate *substituteCall = mRetyper.convertASTFunction(node);
287             if (substituteCall)
288             {
289                 queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
290             }
291         }
292         mRetyper.postVisitAggregate();
293 
294         return true;
295     }
296 
visitSymbol(TIntermSymbol * symbol)297     void visitSymbol(TIntermSymbol *symbol) override
298     {
299         if (!symbol->getType().isSamplerCube())
300         {
301             return;
302         }
303 
304         const TVariable *samplerCubeVar = &symbol->variable();
305 
306         TIntermTyped *sampler2DArrayVar =
307             new TIntermSymbol(mRetyper.getVariableReplacement(samplerCubeVar));
308         ASSERT(sampler2DArrayVar != nullptr);
309 
310         TIntermNode *argument = symbol;
311 
312         // We need to replace the whole function call argument with the symbol replaced.  The
313         // argument can either be the sampler (array) itself, or a subscript into a sampler array.
314         TIntermBinary *arrayExpression = getParentNode()->getAsBinaryNode();
315         if (arrayExpression)
316         {
317             ASSERT(arrayExpression->getOp() == EOpIndexDirect ||
318                    arrayExpression->getOp() == EOpIndexIndirect);
319 
320             argument = arrayExpression;
321 
322             sampler2DArrayVar = new TIntermBinary(arrayExpression->getOp(), sampler2DArrayVar,
323                                                   arrayExpression->getRight()->deepCopy());
324         }
325 
326         mRetyper.replaceFunctionCallArg(argument, sampler2DArrayVar);
327     }
328 
getCoordTranslationFunctionDecl()329     TIntermFunctionDefinition *getCoordTranslationFunctionDecl()
330     {
331         return mCoordTranslationFunctionDecl;
332     }
333 
getCoordTranslationFunctionDeclImplicit()334     TIntermFunctionDefinition *getCoordTranslationFunctionDeclImplicit()
335     {
336         return mCoordTranslationFunctionImplicitDecl;
337     }
338 
339   private:
declareSampler2DArray(const TVariable * samplerCubeVar,TIntermDeclaration * node)340     void declareSampler2DArray(const TVariable *samplerCubeVar, TIntermDeclaration *node)
341     {
342         if (mCubeXYZToArrayUVL == nullptr)
343         {
344             // If not done yet, declare the function that transforms cube map texture sampling
345             // coordinates to face index and uv coordinates.
346             declareCoordTranslationFunction(false, kCoordTransformFuncName, &mCubeXYZToArrayUVL,
347                                             &mCoordTranslationFunctionDecl);
348         }
349         if (mCubeXYZToArrayUVLImplicit == nullptr && mIsFragmentShader)
350         {
351             declareCoordTranslationFunction(true, kCoordTransformFuncNameImplicit,
352                                             &mCubeXYZToArrayUVLImplicit,
353                                             &mCoordTranslationFunctionImplicitDecl);
354         }
355 
356         TType *newType = new TType(samplerCubeVar->getType());
357         newType->setBasicType(EbtSampler2DArray);
358 
359         TVariable *sampler2DArrayVar =
360             new TVariable(mSymbolTable, samplerCubeVar->name(), newType, SymbolType::UserDefined);
361 
362         TIntermDeclaration *sampler2DArrayDecl = new TIntermDeclaration();
363         sampler2DArrayDecl->appendDeclarator(new TIntermSymbol(sampler2DArrayVar));
364 
365         TIntermSequence replacement;
366         replacement.push_back(sampler2DArrayDecl);
367         mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, replacement);
368 
369         // Remember the sampler2DArray variable.
370         mRetyper.replaceGlobalVariable(samplerCubeVar, sampler2DArrayVar);
371     }
372 
declareCoordTranslationFunction(bool implicit,const ImmutableString & name,TFunction ** functionOut,TIntermFunctionDefinition ** declOut)373     void declareCoordTranslationFunction(bool implicit,
374                                          const ImmutableString &name,
375                                          TFunction **functionOut,
376                                          TIntermFunctionDefinition **declOut)
377     {
378         // GLES2.0 (as well as desktop OpenGL 2.0) define the coordination transformation as
379         // follows.  Given xyz cube coordinates, where each channel is in [-1, 1], the following
380         // table calculates uc, vc and ma as well as the cube map face.
381         //
382         //    Major    Axis Direction Target     uc  vc  ma
383         //     +x   TEXTURE_CUBE_MAP_POSITIVE_X  −z  −y  |x|
384         //     −x   TEXTURE_CUBE_MAP_NEGATIVE_X   z  −y  |x|
385         //     +y   TEXTURE_CUBE_MAP_POSITIVE_Y   x   z  |y|
386         //     −y   TEXTURE_CUBE_MAP_NEGATIVE_Y   x  −z  |y|
387         //     +z   TEXTURE_CUBE_MAP_POSITIVE_Z   x  −y  |z|
388         //     −z   TEXTURE_CUBE_MAP_NEGATIVE_Z  −x  −y  |z|
389         //
390         // "Major" is an indication of the axis with the largest value.  The cube map face indicates
391         // the layer to sample from.  The uv coordinates to sample from are calculated as,
392         // effectively transforming the uv values to [0, 1]:
393         //
394         //     u = (1 + uc/ma) / 2
395         //     v = (1 + vc/ma) / 2
396         //
397         // The function can be implemented as 6 ifs, though it would be far from efficient.  The
398         // following calculations implement the table above in a smaller number of instructions.
399         //
400         // First, ma can be calculated as the max of the three axes.
401         //
402         //     ma = max3(|x|, |y|, |z|)
403         //
404         // We have three cases:
405         //
406         //     ma == |x|:      uc = -sign(x)*z
407         //                     vc = -y
408         //                  layer = float(x < 0)
409         //
410         //     ma == |y|:      uc = x
411         //                     vc = sign(y)*z
412         //                  layer = 2 + float(y < 0)
413         //
414         //     ma == |z|:      uc = size(z)*x
415         //                     vc = -y
416         //                  layer = 4 + float(z < 0)
417         //
418         // This can be implemented with a number of ?: instructions or 3 ifs. ?: would require all
419         // expressions to be evaluated (vector ALU) while if would require exec mask and jumps
420         // (scalar operations).  We implement this using ifs as there would otherwise be many vector
421         // operations and not much of anything else.
422         //
423         // If textureCubeGrad is used, we also need to transform the provided dPdx and dPdy (both
424         // vec3) to a dUVdx and dUVdy.  Assume P=(r,s,t) and we are investigating dx (note the
425         // change from xyz to rst to not confuse with dx and dy):
426         //
427         //     uv = (f(r,s,t)/ma + 1)/2
428         //
429         // Where f is one of the transformations above for uc and vc.  Between two neighbors along
430         // the x axis, we have P0=(r0,s0,t0) and P1=(r1,s1,t1)
431         //
432         //     dP = (r1-r0, s1-s0, t1-t0)
433         //     dUV = (f(r1,s1,t1)/ma1 - g(r0,s0,t0)/ma0) / 2
434         //
435         // f and g may not necessarily be the same because the two points may have different major
436         // axes.  Even with the same major access, the sign that's used in the formulas may not be
437         // the same.  Furthermore, ma0 and ma1 may not be the same.  This makes it impossible to
438         // derive dUV from dP exactly.
439         //
440         // However, gradient transformation is implementation dependant, so we will simplify and
441         // assume all the above complications are non-existent.  We therefore have:
442         //
443         //      dUV = (f(r1,s1,t1)/ma0 - f(r0,s0,t0)/ma0)/2
444         //
445         // Given that we assumed the sign functions are returning identical results for the two
446         // points, f becomes a linear transformation.  Thus:
447         //
448         //      dUV = f(r1-r0,s1-0,t1-t0)/ma0/2
449         //
450         // In other words, we use the same formulae that transform XYZ (RST here) to UV to
451         // transform the derivatives.
452         //
453         //     ma == |x|:    dUdx = -sign(x)*dPdx.z / ma / 2
454         //                   dVdx = -dPdx.y / ma / 2
455         //
456         //     ma == |y|:    dUdx = dPdx.x / ma / 2
457         //                   dVdx = sign(y)*dPdx.z / ma / 2
458         //
459         //     ma == |z|:    dUdx = size(z)*dPdx.x / ma / 2
460         //                   dVdx = -dPdx.y / ma / 2
461         //
462         // Similarly for dy.
463 
464         // Create the function parameters: vec3 P, vec3 dPdx, vec3 dPdy,
465         //                                 out vec2 dUVdx, out vec2 dUVdy
466         const TType *vec3Type = StaticType::GetBasic<EbtFloat, 3>();
467         TVariable *pVar =
468             new TVariable(mSymbolTable, ImmutableString("P"), vec3Type, SymbolType::AngleInternal);
469         TVariable *dPdxVar = new TVariable(mSymbolTable, ImmutableString("dPdx"), vec3Type,
470                                            SymbolType::AngleInternal);
471         TVariable *dPdyVar = new TVariable(mSymbolTable, ImmutableString("dPdy"), vec3Type,
472                                            SymbolType::AngleInternal);
473 
474         const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
475         TType *outVec2Type    = new TType(*vec2Type);
476         outVec2Type->setQualifier(EvqOut);
477 
478         TVariable *dUVdxVar = new TVariable(mSymbolTable, ImmutableString("dUVdx"), outVec2Type,
479                                             SymbolType::AngleInternal);
480         TVariable *dUVdyVar = new TVariable(mSymbolTable, ImmutableString("dUVdy"), outVec2Type,
481                                             SymbolType::AngleInternal);
482 
483         TIntermSymbol *p     = new TIntermSymbol(pVar);
484         TIntermSymbol *dPdx  = new TIntermSymbol(dPdxVar);
485         TIntermSymbol *dPdy  = new TIntermSymbol(dPdyVar);
486         TIntermSymbol *dUVdx = new TIntermSymbol(dUVdxVar);
487         TIntermSymbol *dUVdy = new TIntermSymbol(dUVdyVar);
488 
489         // Create the function body as statements are generated.
490         TIntermBlock *body = new TIntermBlock;
491 
492         // Create the swizzle nodes that will be used in multiple expressions:
493         TIntermSwizzle *x = new TIntermSwizzle(p->deepCopy(), {0});
494         TIntermSwizzle *y = new TIntermSwizzle(p->deepCopy(), {1});
495         TIntermSwizzle *z = new TIntermSwizzle(p->deepCopy(), {2});
496 
497         // Create abs and "< 0" expressions from the channels.
498         const TType *floatType = StaticType::GetBasic<EbtFloat>();
499 
500         TIntermTyped *isNegX = new TIntermBinary(EOpLessThan, x, CreateZeroNode(*floatType));
501         TIntermTyped *isNegY = new TIntermBinary(EOpLessThan, y, CreateZeroNode(*floatType));
502         TIntermTyped *isNegZ = new TIntermBinary(EOpLessThan, z, CreateZeroNode(*floatType));
503 
504         TIntermSymbol *absX = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
505         TIntermSymbol *absY = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
506         TIntermSymbol *absZ = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
507 
508         TIntermDeclaration *absXDecl = CreateTempInitDeclarationNode(
509             &absX->variable(), new TIntermUnary(EOpAbs, x->deepCopy(), nullptr));
510         TIntermDeclaration *absYDecl = CreateTempInitDeclarationNode(
511             &absY->variable(), new TIntermUnary(EOpAbs, y->deepCopy(), nullptr));
512         TIntermDeclaration *absZDecl = CreateTempInitDeclarationNode(
513             &absZ->variable(), new TIntermUnary(EOpAbs, z->deepCopy(), nullptr));
514 
515         body->appendStatement(absXDecl);
516         body->appendStatement(absYDecl);
517         body->appendStatement(absZDecl);
518 
519         // Create temporary variable for division outer product matrix and its
520         // derivatives.
521         // recipOuter[i][j] = 0.5 * P[j] / P[i]
522         const TType *mat3Type     = StaticType::GetBasic<EbtFloat, 3, 3>();
523         TIntermSymbol *recipOuter = new TIntermSymbol(CreateTempVariable(mSymbolTable, mat3Type));
524 
525         TIntermTyped *pRecip     = new TIntermBinary(EOpDiv, CreateFloatNode(1.0), p->deepCopy());
526         TIntermSymbol *pRecipVar = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
527 
528         body->appendStatement(CreateTempInitDeclarationNode(&pRecipVar->variable(), pRecip));
529 
530         TIntermDeclaration *recipOuterDecl = CreateTempInitDeclarationNode(
531             &recipOuter->variable(),
532             CreateBuiltInFunctionCallNode(
533                 "outerProduct",
534                 new TIntermSequence(
535                     {p->deepCopy(), new TIntermBinary(EOpVectorTimesScalar, CreateFloatNode(0.5),
536                                                       pRecipVar->deepCopy())}),
537                 *mSymbolTable, 300));
538         body->appendStatement(recipOuterDecl);
539 
540         TIntermSymbol *dPDXdx = nullptr;
541         TIntermSymbol *dPDYdx = nullptr;
542         TIntermSymbol *dPDZdx = nullptr;
543         TIntermSymbol *dPDXdy = nullptr;
544         TIntermSymbol *dPDYdy = nullptr;
545         TIntermSymbol *dPDZdy = nullptr;
546         if (implicit)
547         {
548             dPDXdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
549             dPDYdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
550             dPDZdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
551             dPDXdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
552             dPDYdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
553             dPDZdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
554 
555             TIntermDeclaration *dPDXdxDecl = CreateTempInitDeclarationNode(
556                 &dPDXdx->variable(),
557                 new TIntermUnary(EOpDFdx, IndexDirect(recipOuter, 0)->deepCopy(), nullptr));
558             TIntermDeclaration *dPDYdxDecl = CreateTempInitDeclarationNode(
559                 &dPDYdx->variable(),
560                 new TIntermUnary(EOpDFdx, IndexDirect(recipOuter, 1)->deepCopy(), nullptr));
561             TIntermDeclaration *dPDZdxDecl = CreateTempInitDeclarationNode(
562                 &dPDZdx->variable(),
563                 new TIntermUnary(EOpDFdx, IndexDirect(recipOuter, 2)->deepCopy(), nullptr));
564             TIntermDeclaration *dPDXdyDecl = CreateTempInitDeclarationNode(
565                 &dPDXdy->variable(),
566                 new TIntermUnary(EOpDFdy, IndexDirect(recipOuter, 0)->deepCopy(), nullptr));
567             TIntermDeclaration *dPDYdyDecl = CreateTempInitDeclarationNode(
568                 &dPDYdy->variable(),
569                 new TIntermUnary(EOpDFdy, IndexDirect(recipOuter, 1)->deepCopy(), nullptr));
570             TIntermDeclaration *dPDZdyDecl = CreateTempInitDeclarationNode(
571                 &dPDZdy->variable(),
572                 new TIntermUnary(EOpDFdy, IndexDirect(recipOuter, 2)->deepCopy(), nullptr));
573 
574             body->appendStatement(dPDXdxDecl);
575             body->appendStatement(dPDYdxDecl);
576             body->appendStatement(dPDZdxDecl);
577             body->appendStatement(dPDXdyDecl);
578             body->appendStatement(dPDYdyDecl);
579             body->appendStatement(dPDZdyDecl);
580         }
581 
582         // Create temporary variables for ma, uc, vc, and l (layer), as well as dUdx, dVdx, dUdy
583         // and dVdy.
584         TIntermSymbol *ma   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
585         TIntermSymbol *l    = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
586         TIntermSymbol *uc   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
587         TIntermSymbol *vc   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
588         TIntermSymbol *dUdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
589         TIntermSymbol *dVdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
590         TIntermSymbol *dUdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
591         TIntermSymbol *dVdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
592 
593         body->appendStatement(CreateTempDeclarationNode(&ma->variable()));
594         body->appendStatement(CreateTempDeclarationNode(&l->variable()));
595         body->appendStatement(CreateTempDeclarationNode(&uc->variable()));
596         body->appendStatement(CreateTempDeclarationNode(&vc->variable()));
597         body->appendStatement(CreateTempDeclarationNode(&dUdx->variable()));
598         body->appendStatement(CreateTempDeclarationNode(&dVdx->variable()));
599         body->appendStatement(CreateTempDeclarationNode(&dUdy->variable()));
600         body->appendStatement(CreateTempDeclarationNode(&dVdy->variable()));
601 
602         // ma = max(|x|, max(|y|, |z|))
603         TIntermTyped *maxYZ = CreateBuiltInFunctionCallNode(
604             "max", new TIntermSequence({absY->deepCopy(), absZ->deepCopy()}), *mSymbolTable, 100);
605         TIntermTyped *maValue = CreateBuiltInFunctionCallNode(
606             "max", new TIntermSequence({absX->deepCopy(), maxYZ}), *mSymbolTable, 100);
607         body->appendStatement(new TIntermBinary(EOpAssign, ma, maValue));
608 
609         // ma == |x| and ma == |y| expressions
610         TIntermTyped *isXMajor = new TIntermBinary(EOpEqual, ma->deepCopy(), absX->deepCopy());
611         TIntermTyped *isYMajor = new TIntermBinary(EOpEqual, ma->deepCopy(), absY->deepCopy());
612 
613         // Determine the cube face:
614 
615         // The case where x is major:
616         //     layer = float(x < 0)
617         TIntermTyped *xl =
618             TIntermAggregate::CreateConstructor(*floatType, new TIntermSequence({isNegX}));
619 
620         TIntermBlock *calculateXL = new TIntermBlock;
621         calculateXL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), xl));
622 
623         // The case where y is major:
624         //     layer = 2 + float(y < 0)
625         TIntermTyped *yl = new TIntermBinary(
626             EOpAdd, CreateFloatNode(2.0f),
627             TIntermAggregate::CreateConstructor(*floatType, new TIntermSequence({isNegY})));
628 
629         TIntermBlock *calculateYL = new TIntermBlock;
630         calculateYL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), yl));
631 
632         // The case where z is major:
633         //     layer = 4 + float(z < 0)
634         TIntermTyped *zl = new TIntermBinary(
635             EOpAdd, CreateFloatNode(4.0f),
636             TIntermAggregate::CreateConstructor(*floatType, new TIntermSequence({isNegZ})));
637 
638         TIntermBlock *calculateZL = new TIntermBlock;
639         calculateZL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), zl));
640 
641         // Create the if-else paths:
642         TIntermIfElse *calculateYZL     = new TIntermIfElse(isYMajor, calculateYL, calculateZL);
643         TIntermBlock *calculateYZLBlock = new TIntermBlock;
644         calculateYZLBlock->appendStatement(calculateYZL);
645         TIntermIfElse *calculateXYZL = new TIntermIfElse(isXMajor, calculateXL, calculateYZLBlock);
646         body->appendStatement(calculateXYZL);
647 
648         // layer < 1.5 (covering faces 0 and 1, corresponding to major axis being X) and layer < 3.5
649         // (covering faces 2 and 3, corresponding to major axis being Y).  Used to determine which
650         // of the three transformations to apply.  Previously, ma == |X| and ma == |Y| was used,
651         // which is no longer correct for helper invocations.  The value of ma is updated in each
652         // case for these invocations.
653         isXMajor = new TIntermBinary(EOpLessThan, l->deepCopy(), CreateFloatNode(1.5f));
654         isYMajor = new TIntermBinary(EOpLessThan, l->deepCopy(), CreateFloatNode(3.5f));
655 
656         TIntermSwizzle *dPdxX = new TIntermSwizzle(dPdx->deepCopy(), {0});
657         TIntermSwizzle *dPdxY = new TIntermSwizzle(dPdx->deepCopy(), {1});
658         TIntermSwizzle *dPdxZ = new TIntermSwizzle(dPdx->deepCopy(), {2});
659 
660         TIntermSwizzle *dPdyX = new TIntermSwizzle(dPdy->deepCopy(), {0});
661         TIntermSwizzle *dPdyY = new TIntermSwizzle(dPdy->deepCopy(), {1});
662         TIntermSwizzle *dPdyZ = new TIntermSwizzle(dPdy->deepCopy(), {2});
663 
664         TIntermBlock *calculateXUcVc = new TIntermBlock;
665         calculateXUcVc->appendStatement(
666             new TIntermBinary(EOpAssign, ma->deepCopy(), absX->deepCopy()));
667         TransformXMajor(calculateXUcVc, x, y, z, uc, vc);
668 
669         TIntermBlock *calculateYUcVc = new TIntermBlock;
670         calculateYUcVc->appendStatement(
671             new TIntermBinary(EOpAssign, ma->deepCopy(), absY->deepCopy()));
672         TransformYMajor(calculateYUcVc, x, y, z, uc, vc);
673 
674         TIntermBlock *calculateZUcVc = new TIntermBlock;
675         calculateZUcVc->appendStatement(
676             new TIntermBinary(EOpAssign, ma->deepCopy(), absZ->deepCopy()));
677         TransformZMajor(calculateZUcVc, x, y, z, uc, vc);
678 
679         // Compute derivatives.
680         if (implicit)
681         {
682             TransformImplicitDerivativeXMajor(calculateXUcVc, dPDXdx, dUdx, dVdx);
683             TransformImplicitDerivativeXMajor(calculateXUcVc, dPDXdy, dUdy, dVdy);
684             TransformImplicitDerivativeYMajor(calculateYUcVc, dPDYdx, dUdx, dVdx);
685             TransformImplicitDerivativeYMajor(calculateYUcVc, dPDYdy, dUdy, dVdy);
686             TransformImplicitDerivativeZMajor(calculateZUcVc, dPDZdx, dUdx, dVdx);
687             TransformImplicitDerivativeZMajor(calculateZUcVc, dPDZdy, dUdy, dVdy);
688         }
689         else
690         {
691             TransformDerivativeXMajor(calculateXUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
692                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 0));
693             TransformDerivativeXMajor(calculateXUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
694                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 0));
695             TransformDerivativeYMajor(calculateYUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
696                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 1));
697             TransformDerivativeYMajor(calculateYUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
698                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 1));
699             TransformDerivativeZMajor(calculateZUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
700                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 2));
701             TransformDerivativeZMajor(calculateZUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
702                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 2));
703         }
704 
705         // Create the if-else paths:
706         TIntermIfElse *calculateYZUcVc =
707             new TIntermIfElse(isYMajor, calculateYUcVc, calculateZUcVc);
708         TIntermBlock *calculateYZUcVcBlock = new TIntermBlock;
709         calculateYZUcVcBlock->appendStatement(calculateYZUcVc);
710         TIntermIfElse *calculateXYZUcVc =
711             new TIntermIfElse(isXMajor, calculateXUcVc, calculateYZUcVcBlock);
712         body->appendStatement(calculateXYZUcVc);
713 
714         // u = (1 + uc/|ma|) / 2
715         // v = (1 + vc/|ma|) / 2
716         TIntermTyped *maTimesTwoRecip =
717             new TIntermBinary(EOpAssign, ma->deepCopy(),
718                               new TIntermBinary(EOpDiv, CreateFloatNode(0.5f), ma->deepCopy()));
719         body->appendStatement(maTimesTwoRecip);
720 
721         TIntermTyped *ucDivMa     = new TIntermBinary(EOpMul, uc, ma->deepCopy());
722         TIntermTyped *vcDivMa     = new TIntermBinary(EOpMul, vc, ma->deepCopy());
723         TIntermTyped *uNormalized = new TIntermBinary(EOpAdd, CreateFloatNode(0.5f), ucDivMa);
724         TIntermTyped *vNormalized = new TIntermBinary(EOpAdd, CreateFloatNode(0.5f), vcDivMa);
725 
726         body->appendStatement(new TIntermBinary(EOpAssign, uc->deepCopy(), uNormalized));
727         body->appendStatement(new TIntermBinary(EOpAssign, vc->deepCopy(), vNormalized));
728 
729         TIntermTyped *dUVdxValue =
730             TIntermAggregate::CreateConstructor(*vec2Type, new TIntermSequence({dUdx, dVdx}));
731         TIntermTyped *dUVdyValue =
732             TIntermAggregate::CreateConstructor(*vec2Type, new TIntermSequence({dUdy, dVdy}));
733 
734         body->appendStatement(new TIntermBinary(EOpAssign, dUVdx, dUVdxValue));
735         body->appendStatement(new TIntermBinary(EOpAssign, dUVdy, dUVdyValue));
736 
737         // return vec3(u, v, l)
738         TIntermBranch *returnStatement = new TIntermBranch(
739             EOpReturn, TIntermAggregate::CreateConstructor(
740                            *vec3Type, new TIntermSequence({uc->deepCopy(), vc->deepCopy(), l})));
741         body->appendStatement(returnStatement);
742 
743         TFunction *function;
744         function = new TFunction(mSymbolTable, name, SymbolType::AngleInternal, vec3Type, true);
745         function->addParameter(pVar);
746         function->addParameter(dPdxVar);
747         function->addParameter(dPdyVar);
748         function->addParameter(dUVdxVar);
749         function->addParameter(dUVdyVar);
750 
751         *functionOut = function;
752 
753         *declOut = CreateInternalFunctionDefinitionNode(*function, body);
754     }
755 
createCoordTransformationCall(TIntermTyped * P,TIntermTyped * dPdx,TIntermTyped * dPdy,TIntermTyped * dUVdx,TIntermTyped * dUVdy)756     TIntermTyped *createCoordTransformationCall(TIntermTyped *P,
757                                                 TIntermTyped *dPdx,
758                                                 TIntermTyped *dPdy,
759                                                 TIntermTyped *dUVdx,
760                                                 TIntermTyped *dUVdy)
761     {
762         TIntermSequence *args = new TIntermSequence({P, dPdx, dPdy, dUVdx, dUVdy});
763         return TIntermAggregate::CreateFunctionCall(*mCubeXYZToArrayUVL, args);
764     }
765 
createImplicitCoordTransformationCall(TIntermTyped * P,TIntermTyped * dUVdx,TIntermTyped * dUVdy)766     TIntermTyped *createImplicitCoordTransformationCall(TIntermTyped *P,
767                                                         TIntermTyped *dUVdx,
768                                                         TIntermTyped *dUVdy)
769     {
770         const TType *vec3Type = StaticType::GetBasic<EbtFloat, 3>();
771         TIntermTyped *dPdx    = CreateZeroNode(*vec3Type);
772         TIntermTyped *dPdy    = CreateZeroNode(*vec3Type);
773         TIntermSequence *args = new TIntermSequence({P, dPdx, dPdy, dUVdx, dUVdy});
774         return TIntermAggregate::CreateFunctionCall(*mCubeXYZToArrayUVLImplicit, args);
775     }
776 
convertFunctionParameter(TIntermNode * parent,const TVariable * param)777     TVariable *convertFunctionParameter(TIntermNode *parent, const TVariable *param)
778     {
779         if (!param->getType().isSamplerCube())
780         {
781             return nullptr;
782         }
783 
784         TType *newType = new TType(param->getType());
785         newType->setBasicType(EbtSampler2DArray);
786 
787         TVariable *replacementVar =
788             new TVariable(mSymbolTable, param->name(), newType, SymbolType::UserDefined);
789 
790         return replacementVar;
791     }
792 
convertBuiltinFunction(TIntermAggregate * node)793     void convertBuiltinFunction(TIntermAggregate *node)
794     {
795         const TFunction *function = node->getFunction();
796         if (!function->name().beginsWith("textureCube"))
797         {
798             return;
799         }
800 
801         // All textureCube* functions are in the form:
802         //
803         //     textureCube??(samplerCube, vec3, ??)
804         //
805         // They should be converted to:
806         //
807         //     texture??(sampler2DArray, convertCoords(vec3), ??)
808         //
809         // We assume the target platform supports texture() functions (currently only used in
810         // Vulkan).
811         //
812         // The intrinsics map as follows:
813         //
814         //     textureCube -> textureGrad
815         //     textureCubeLod -> textureLod
816         //     textureCubeLodEXT -> textureLod
817         //     textureCubeGrad -> textureGrad
818         //     textureCubeGradEXT -> textureGrad
819         //
820         // Note that dPdx and dPdy in textureCubeGrad* are vec3, while the textureGrad equivalent
821         // for sampler2DArray is vec2.  The EXT_shader_texture_lod that introduces thid function
822         // says:
823         //
824         // > For the "Grad" functions, dPdx is the explicit derivative of P with respect
825         // > to window x, and similarly dPdy with respect to window y. ...  For a cube map texture,
826         // > dPdx and dPdy are vec3.
827         // >
828         // > Let
829         // >
830         // >     dSdx = dPdx.s;
831         // >     dSdy = dPdy.s;
832         // >     dTdx = dPdx.t;
833         // >     dTdy = dPdy.t;
834         // >
835         // > and
836         // >
837         // >             / 0.0;    for two-dimensional texture
838         // >     dRdx = (
839         // >             \ dPdx.p; for cube map texture
840         // >
841         // >             / 0.0;    for two-dimensional texture
842         // >     dRdy = (
843         // >             \ dPdy.p; for cube map texture
844         // >
845         // > (See equation 3.12a in The OpenGL ES 2.0 Specification.)
846         //
847         // It's unclear to me what dRdx and dRdy are.  EXT_gpu_shader4 that promotes this function
848         // has the following additional information:
849         //
850         // > For the "Cube" versions, the partial
851         // > derivatives ddx and ddy are assumed to be in the coordinate system used
852         // > before texture coordinates are projected onto the appropriate cube
853         // > face. The partial derivatives of the post-projection texture coordinates,
854         // > which are used for level-of-detail and anisotropic filtering
855         // > calculations, are derived from coord, ddx and ddy in an
856         // > implementation-dependent manner.
857         //
858         // The calculation of dPdx and dPdy is declared as implementation-dependent, so we have
859         // freedom to calculate it as fit, even if not precisely the same as hardware might.
860 
861         const char *substituteFunctionName = "textureGrad";
862         bool isGrad                        = false;
863         bool isTranslatedGrad              = true;
864         bool hasBias                       = false;
865         if (function->name().beginsWith("textureCubeLod"))
866         {
867             substituteFunctionName = "textureLod";
868             isTranslatedGrad       = false;
869         }
870         else if (function->name().beginsWith("textureCubeGrad"))
871         {
872             isGrad = true;
873         }
874         else if (!mIsFragmentShader)
875         {
876             substituteFunctionName = "texture";
877             isTranslatedGrad       = false;
878         }
879 
880         TIntermSequence *arguments = node->getSequence();
881         ASSERT(arguments->size() >= 2);
882 
883         const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
884         const TType *vec3Type = StaticType::GetBasic<EbtFloat, 3>();
885         TIntermSymbol *uvl    = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
886         TIntermSymbol *dUVdx  = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
887         TIntermSymbol *dUVdy  = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
888 
889         TIntermTyped *dPdx = nullptr;
890         TIntermTyped *dPdy = nullptr;
891         if (isGrad)
892         {
893             ASSERT(arguments->size() == 4);
894             dPdx = (*arguments)[2]->getAsTyped()->deepCopy();
895             dPdy = (*arguments)[3]->getAsTyped()->deepCopy();
896         }
897         else if (isTranslatedGrad && mIsFragmentShader && arguments->size() == 3)
898         {
899             hasBias = true;
900         }
901         else
902         {
903             dPdx = CreateZeroNode(*vec3Type);
904             dPdy = CreateZeroNode(*vec3Type);
905         }
906 
907         if (isTranslatedGrad && !mIsFragmentShader)
908         {
909             substituteFunctionName = "texture";
910             isTranslatedGrad       = false;
911         }
912 
913         // The function call to transform the coordinates, dPdx and dPdy.  If not textureCubeGrad,
914         // the driver compiler will optimize out the unnecessary calculations.
915         TIntermSequence *coordTransform = new TIntermSequence;
916         coordTransform->push_back(CreateTempDeclarationNode(&dUVdx->variable()));
917         coordTransform->push_back(CreateTempDeclarationNode(&dUVdy->variable()));
918         TIntermTyped *coordTransformCall;
919         if (isGrad || !isTranslatedGrad)
920         {
921             coordTransformCall = createCoordTransformationCall(
922                 (*arguments)[1]->getAsTyped()->deepCopy(), dPdx, dPdy, dUVdx, dUVdy);
923         }
924         else
925         {
926             coordTransformCall = createImplicitCoordTransformationCall(
927                 (*arguments)[1]->getAsTyped()->deepCopy(), dUVdx, dUVdy);
928         }
929         coordTransform->push_back(
930             CreateTempInitDeclarationNode(&uvl->variable(), coordTransformCall));
931 
932         TIntermTyped *dUVdxArg = dUVdx;
933         TIntermTyped *dUVdyArg = dUVdy;
934         if (hasBias)
935         {
936             const TType *floatType = StaticType::GetBasic<EbtFloat>();
937             TIntermTyped *bias     = (*arguments)[2]->getAsTyped()->deepCopy();
938             TIntermTyped *exp2Call = CreateBuiltInFunctionCallNode(
939                 "exp2", new TIntermSequence({bias}), *mSymbolTable, 100);
940             TIntermSymbol *biasFac = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
941             coordTransform->push_back(
942                 CreateTempInitDeclarationNode(&biasFac->variable(), exp2Call));
943             dUVdxArg =
944                 new TIntermBinary(EOpVectorTimesScalar, biasFac->deepCopy(), dUVdx->deepCopy());
945             dUVdyArg =
946                 new TIntermBinary(EOpVectorTimesScalar, biasFac->deepCopy(), dUVdy->deepCopy());
947         }
948 
949         insertStatementsInParentBlock(*coordTransform);
950 
951         TIntermSequence *substituteArguments = new TIntermSequence;
952         // Replace the first argument (samplerCube) with the sampler2DArray.
953         substituteArguments->push_back(mRetyper.getFunctionCallArgReplacement((*arguments)[0]));
954         // Replace the second argument with the coordination transformation.
955         substituteArguments->push_back(uvl->deepCopy());
956         if (isTranslatedGrad)
957         {
958             substituteArguments->push_back(dUVdxArg->deepCopy());
959             substituteArguments->push_back(dUVdyArg->deepCopy());
960         }
961         else
962         {
963             // Pass the rest of the parameters as is.
964             for (size_t argIndex = 2; argIndex < arguments->size(); ++argIndex)
965             {
966                 substituteArguments->push_back((*arguments)[argIndex]->getAsTyped()->deepCopy());
967             }
968         }
969 
970         TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
971             substituteFunctionName, substituteArguments, *mSymbolTable, 300);
972 
973         queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
974     }
975 
976     RetypeOpaqueVariablesHelper mRetyper;
977 
978     // A helper function to convert xyz coordinates passed to a cube map sampling function into the
979     // array layer (cube map face) and uv coordinates.
980     TFunction *mCubeXYZToArrayUVL;
981     // A specialized version of the same function which uses implicit derivatives.
982     TFunction *mCubeXYZToArrayUVLImplicit;
983 
984     bool mIsFragmentShader;
985 
986     // Stored to be put before the first function after the pass.
987     TIntermFunctionDefinition *mCoordTranslationFunctionDecl;
988     TIntermFunctionDefinition *mCoordTranslationFunctionImplicitDecl;
989 };
990 
991 }  // anonymous namespace
992 
RewriteCubeMapSamplersAs2DArray(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,bool isFragmentShader)993 bool RewriteCubeMapSamplersAs2DArray(TCompiler *compiler,
994                                      TIntermBlock *root,
995                                      TSymbolTable *symbolTable,
996                                      bool isFragmentShader)
997 {
998     RewriteCubeMapSamplersAs2DArrayTraverser traverser(symbolTable, isFragmentShader);
999     root->traverse(&traverser);
1000     if (!traverser.updateTree(compiler, root))
1001     {
1002         return false;
1003     }
1004 
1005     TIntermFunctionDefinition *coordTranslationFunctionDecl =
1006         traverser.getCoordTranslationFunctionDecl();
1007     TIntermFunctionDefinition *coordTranslationFunctionDeclImplicit =
1008         traverser.getCoordTranslationFunctionDeclImplicit();
1009     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
1010     if (coordTranslationFunctionDecl)
1011     {
1012         root->insertChildNodes(firstFunctionIndex, TIntermSequence({coordTranslationFunctionDecl}));
1013     }
1014     if (coordTranslationFunctionDeclImplicit)
1015     {
1016         root->insertChildNodes(firstFunctionIndex,
1017                                TIntermSequence({coordTranslationFunctionDeclImplicit}));
1018     }
1019 
1020     return compiler->validateAST(root);
1021 }
1022 
1023 }  // namespace sh
1024