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