• 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 MonomorphizeUnsupportedFunctionsInVulkanGLSL 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));
94     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
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));
147     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
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));
200     dvValue               = new TIntermBinary(EOpMul, dvValue, CreateFloatNode(0.5f));
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 MonomorphizeUnsupportedFunctionsInVulkanGLSL.
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, 3>();
398         TType *inVec3Type     = new TType(*vec3Type);
399         inVec3Type->setQualifier(EvqIn);
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, 2>();
409         TType *outVec2Type    = new TType(*vec2Type);
410         outVec2Type->setQualifier(EvqOut);
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>();
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, 3, 3>();
460         TIntermSymbol *recipOuter = new TIntermSymbol(CreateTempVariable(mSymbolTable, mat3Type));
461 
462         TIntermTyped *pRecip     = new TIntermBinary(EOpDiv, CreateFloatNode(1.0), p->deepCopy());
463         TIntermSymbol *pRecipVar = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
464 
465         body->appendStatement(CreateTempInitDeclarationNode(&pRecipVar->variable(), pRecip));
466 
467         TIntermSequence args = {
468             p->deepCopy(),
469             new TIntermBinary(EOpVectorTimesScalar, CreateFloatNode(0.5), pRecipVar->deepCopy())};
470         TIntermDeclaration *recipOuterDecl = CreateTempInitDeclarationNode(
471             &recipOuter->variable(),
472             CreateBuiltInFunctionCallNode("outerProduct", &args, *mSymbolTable, 300));
473         body->appendStatement(recipOuterDecl);
474 
475         TIntermSymbol *dPDXdx = nullptr;
476         TIntermSymbol *dPDYdx = nullptr;
477         TIntermSymbol *dPDZdx = nullptr;
478         TIntermSymbol *dPDXdy = nullptr;
479         TIntermSymbol *dPDYdy = nullptr;
480         TIntermSymbol *dPDZdy = nullptr;
481         if (implicit)
482         {
483             dPDXdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
484             dPDYdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
485             dPDZdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
486             dPDXdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
487             dPDYdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
488             dPDZdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
489 
490             TIntermDeclaration *dPDXdxDecl = CreateTempInitDeclarationNode(
491                 &dPDXdx->variable(),
492                 CreateBuiltInUnaryFunctionCallNode("dFdx", IndexDirect(recipOuter, 0)->deepCopy(),
493                                                    *mSymbolTable, 300));
494             TIntermDeclaration *dPDYdxDecl = CreateTempInitDeclarationNode(
495                 &dPDYdx->variable(),
496                 CreateBuiltInUnaryFunctionCallNode("dFdx", IndexDirect(recipOuter, 1)->deepCopy(),
497                                                    *mSymbolTable, 300));
498             TIntermDeclaration *dPDZdxDecl = CreateTempInitDeclarationNode(
499                 &dPDZdx->variable(),
500                 CreateBuiltInUnaryFunctionCallNode("dFdx", IndexDirect(recipOuter, 2)->deepCopy(),
501                                                    *mSymbolTable, 300));
502             TIntermDeclaration *dPDXdyDecl = CreateTempInitDeclarationNode(
503                 &dPDXdy->variable(),
504                 CreateBuiltInUnaryFunctionCallNode("dFdy", IndexDirect(recipOuter, 0)->deepCopy(),
505                                                    *mSymbolTable, 300));
506             TIntermDeclaration *dPDYdyDecl = CreateTempInitDeclarationNode(
507                 &dPDYdy->variable(),
508                 CreateBuiltInUnaryFunctionCallNode("dFdy", IndexDirect(recipOuter, 1)->deepCopy(),
509                                                    *mSymbolTable, 300));
510             TIntermDeclaration *dPDZdyDecl = CreateTempInitDeclarationNode(
511                 &dPDZdy->variable(),
512                 CreateBuiltInUnaryFunctionCallNode("dFdy", IndexDirect(recipOuter, 2)->deepCopy(),
513                                                    *mSymbolTable, 300));
514 
515             body->appendStatement(dPDXdxDecl);
516             body->appendStatement(dPDYdxDecl);
517             body->appendStatement(dPDZdxDecl);
518             body->appendStatement(dPDXdyDecl);
519             body->appendStatement(dPDYdyDecl);
520             body->appendStatement(dPDZdyDecl);
521         }
522 
523         // Create temporary variables for ma, uc, vc, and l (layer), as well as dUdx, dVdx, dUdy
524         // and dVdy.
525         TIntermSymbol *ma   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
526         TIntermSymbol *l    = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
527         TIntermSymbol *uc   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
528         TIntermSymbol *vc   = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
529         TIntermSymbol *dUdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
530         TIntermSymbol *dVdx = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
531         TIntermSymbol *dUdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
532         TIntermSymbol *dVdy = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
533 
534         body->appendStatement(CreateTempDeclarationNode(&ma->variable()));
535         body->appendStatement(CreateTempDeclarationNode(&l->variable()));
536         body->appendStatement(CreateTempDeclarationNode(&uc->variable()));
537         body->appendStatement(CreateTempDeclarationNode(&vc->variable()));
538         body->appendStatement(CreateTempDeclarationNode(&dUdx->variable()));
539         body->appendStatement(CreateTempDeclarationNode(&dVdx->variable()));
540         body->appendStatement(CreateTempDeclarationNode(&dUdy->variable()));
541         body->appendStatement(CreateTempDeclarationNode(&dVdy->variable()));
542 
543         // ma = max(|x|, max(|y|, |z|))
544         TIntermSequence argsMaxYZ = {absY->deepCopy(), absZ->deepCopy()};
545         TIntermTyped *maxYZ = CreateBuiltInFunctionCallNode("max", &argsMaxYZ, *mSymbolTable, 100);
546         TIntermSequence argsMaxValue = {absX->deepCopy(), maxYZ};
547         TIntermTyped *maValue =
548             CreateBuiltInFunctionCallNode("max", &argsMaxValue, *mSymbolTable, 100);
549         body->appendStatement(new TIntermBinary(EOpAssign, ma, maValue));
550 
551         // ma == |x| and ma == |y| expressions
552         TIntermTyped *isXMajor = new TIntermBinary(EOpEqual, ma->deepCopy(), absX->deepCopy());
553         TIntermTyped *isYMajor = new TIntermBinary(EOpEqual, ma->deepCopy(), absY->deepCopy());
554 
555         // Determine the cube face:
556 
557         // The case where x is major:
558         //     layer = float(x < 0)
559         TIntermSequence argsNegX = {isNegX};
560         TIntermTyped *xl         = TIntermAggregate::CreateConstructor(*floatType, &argsNegX);
561 
562         TIntermBlock *calculateXL = new TIntermBlock;
563         calculateXL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), xl));
564 
565         // The case where y is major:
566         //     layer = 2 + float(y < 0)
567         TIntermSequence argsNegY = {isNegY};
568         TIntermTyped *yl =
569             new TIntermBinary(EOpAdd, CreateFloatNode(2.0f),
570                               TIntermAggregate::CreateConstructor(*floatType, &argsNegY));
571 
572         TIntermBlock *calculateYL = new TIntermBlock;
573         calculateYL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), yl));
574 
575         // The case where z is major:
576         //     layer = 4 + float(z < 0)
577         TIntermSequence argsNegZ = {isNegZ};
578         TIntermTyped *zl =
579             new TIntermBinary(EOpAdd, CreateFloatNode(4.0f),
580                               TIntermAggregate::CreateConstructor(*floatType, &argsNegZ));
581 
582         TIntermBlock *calculateZL = new TIntermBlock;
583         calculateZL->appendStatement(new TIntermBinary(EOpAssign, l->deepCopy(), zl));
584 
585         // Create the if-else paths:
586         TIntermIfElse *calculateYZL     = new TIntermIfElse(isYMajor, calculateYL, calculateZL);
587         TIntermBlock *calculateYZLBlock = new TIntermBlock;
588         calculateYZLBlock->appendStatement(calculateYZL);
589         TIntermIfElse *calculateXYZL = new TIntermIfElse(isXMajor, calculateXL, calculateYZLBlock);
590         body->appendStatement(calculateXYZL);
591 
592         // layer < 1.5 (covering faces 0 and 1, corresponding to major axis being X) and layer < 3.5
593         // (covering faces 2 and 3, corresponding to major axis being Y).  Used to determine which
594         // of the three transformations to apply.  Previously, ma == |X| and ma == |Y| was used,
595         // which is no longer correct for helper invocations.  The value of ma is updated in each
596         // case for these invocations.
597         isXMajor = new TIntermBinary(EOpLessThan, l->deepCopy(), CreateFloatNode(1.5f));
598         isYMajor = new TIntermBinary(EOpLessThan, l->deepCopy(), CreateFloatNode(3.5f));
599 
600         TIntermSwizzle *dPdxX = new TIntermSwizzle(dPdx->deepCopy(), {0});
601         TIntermSwizzle *dPdxY = new TIntermSwizzle(dPdx->deepCopy(), {1});
602         TIntermSwizzle *dPdxZ = new TIntermSwizzle(dPdx->deepCopy(), {2});
603 
604         TIntermSwizzle *dPdyX = new TIntermSwizzle(dPdy->deepCopy(), {0});
605         TIntermSwizzle *dPdyY = new TIntermSwizzle(dPdy->deepCopy(), {1});
606         TIntermSwizzle *dPdyZ = new TIntermSwizzle(dPdy->deepCopy(), {2});
607 
608         TIntermBlock *calculateXUcVc = new TIntermBlock;
609         calculateXUcVc->appendStatement(
610             new TIntermBinary(EOpAssign, ma->deepCopy(), absX->deepCopy()));
611         TransformXMajor(*mSymbolTable, calculateXUcVc, x, y, z, uc, vc);
612 
613         TIntermBlock *calculateYUcVc = new TIntermBlock;
614         calculateYUcVc->appendStatement(
615             new TIntermBinary(EOpAssign, ma->deepCopy(), absY->deepCopy()));
616         TransformYMajor(*mSymbolTable, calculateYUcVc, x, y, z, uc, vc);
617 
618         TIntermBlock *calculateZUcVc = new TIntermBlock;
619         calculateZUcVc->appendStatement(
620             new TIntermBinary(EOpAssign, ma->deepCopy(), absZ->deepCopy()));
621         TransformZMajor(*mSymbolTable, calculateZUcVc, x, y, z, uc, vc);
622 
623         // Compute derivatives.
624         if (implicit)
625         {
626             TransformImplicitDerivativeXMajor(calculateXUcVc, dPDXdx, dUdx, dVdx);
627             TransformImplicitDerivativeXMajor(calculateXUcVc, dPDXdy, dUdy, dVdy);
628             TransformImplicitDerivativeYMajor(calculateYUcVc, dPDYdx, dUdx, dVdx);
629             TransformImplicitDerivativeYMajor(calculateYUcVc, dPDYdy, dUdy, dVdy);
630             TransformImplicitDerivativeZMajor(calculateZUcVc, dPDZdx, dUdx, dVdx);
631             TransformImplicitDerivativeZMajor(calculateZUcVc, dPDZdy, dUdy, dVdy);
632         }
633         else
634         {
635             TransformDerivativeXMajor(calculateXUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
636                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 0));
637             TransformDerivativeXMajor(calculateXUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
638                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 0));
639             TransformDerivativeYMajor(calculateYUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
640                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 1));
641             TransformDerivativeYMajor(calculateYUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
642                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 1));
643             TransformDerivativeZMajor(calculateZUcVc, mSymbolTable, x, y, z, dPdxX, dPdxY, dPdxZ,
644                                       dUdx, dVdx, Swizzle1(pRecipVar->deepCopy(), 2));
645             TransformDerivativeZMajor(calculateZUcVc, mSymbolTable, x, y, z, dPdyX, dPdyY, dPdyZ,
646                                       dUdy, dVdy, Swizzle1(pRecipVar->deepCopy(), 2));
647         }
648 
649         // Create the if-else paths:
650         TIntermIfElse *calculateYZUcVc =
651             new TIntermIfElse(isYMajor, calculateYUcVc, calculateZUcVc);
652         TIntermBlock *calculateYZUcVcBlock = new TIntermBlock;
653         calculateYZUcVcBlock->appendStatement(calculateYZUcVc);
654         TIntermIfElse *calculateXYZUcVc =
655             new TIntermIfElse(isXMajor, calculateXUcVc, calculateYZUcVcBlock);
656         body->appendStatement(calculateXYZUcVc);
657 
658         // u = (1 + uc/|ma|) / 2
659         // v = (1 + vc/|ma|) / 2
660         TIntermTyped *maTimesTwoRecip =
661             new TIntermBinary(EOpAssign, ma->deepCopy(),
662                               new TIntermBinary(EOpDiv, CreateFloatNode(0.5f), ma->deepCopy()));
663         body->appendStatement(maTimesTwoRecip);
664 
665         TIntermTyped *ucDivMa     = new TIntermBinary(EOpMul, uc, ma->deepCopy());
666         TIntermTyped *vcDivMa     = new TIntermBinary(EOpMul, vc, ma->deepCopy());
667         TIntermTyped *uNormalized = new TIntermBinary(EOpAdd, CreateFloatNode(0.5f), ucDivMa);
668         TIntermTyped *vNormalized = new TIntermBinary(EOpAdd, CreateFloatNode(0.5f), vcDivMa);
669 
670         body->appendStatement(new TIntermBinary(EOpAssign, uc->deepCopy(), uNormalized));
671         body->appendStatement(new TIntermBinary(EOpAssign, vc->deepCopy(), vNormalized));
672 
673         TIntermSequence argsDUVdx = {dUdx, dVdx};
674         TIntermTyped *dUVdxValue  = TIntermAggregate::CreateConstructor(*vec2Type, &argsDUVdx);
675 
676         TIntermSequence argsDUVdy = {dUdy, dVdy};
677         TIntermTyped *dUVdyValue  = TIntermAggregate::CreateConstructor(*vec2Type, &argsDUVdy);
678 
679         body->appendStatement(new TIntermBinary(EOpAssign, dUVdx, dUVdxValue));
680         body->appendStatement(new TIntermBinary(EOpAssign, dUVdy, dUVdyValue));
681 
682         // return vec3(u, v, l)
683         TIntermSequence argsUVL = {uc->deepCopy(), vc->deepCopy(), l};
684         TIntermBranch *returnStatement =
685             new TIntermBranch(EOpReturn, TIntermAggregate::CreateConstructor(*vec3Type, &argsUVL));
686         body->appendStatement(returnStatement);
687 
688         TFunction *function;
689         function = new TFunction(mSymbolTable, name, SymbolType::AngleInternal, vec3Type, true);
690         function->addParameter(pVar);
691         function->addParameter(dPdxVar);
692         function->addParameter(dPdyVar);
693         function->addParameter(dUVdxVar);
694         function->addParameter(dUVdyVar);
695 
696         *functionOut = function;
697 
698         *declOut = CreateInternalFunctionDefinitionNode(*function, body);
699     }
700 
createCoordTransformationCall(TIntermTyped * P,TIntermTyped * dPdx,TIntermTyped * dPdy,TIntermTyped * dUVdx,TIntermTyped * dUVdy)701     TIntermTyped *createCoordTransformationCall(TIntermTyped *P,
702                                                 TIntermTyped *dPdx,
703                                                 TIntermTyped *dPdy,
704                                                 TIntermTyped *dUVdx,
705                                                 TIntermTyped *dUVdy)
706     {
707         TIntermSequence args = {P, dPdx, dPdy, dUVdx, dUVdy};
708         return TIntermAggregate::CreateFunctionCall(*mCubeXYZToArrayUVL, &args);
709     }
710 
createImplicitCoordTransformationCall(TIntermTyped * P,TIntermTyped * dUVdx,TIntermTyped * dUVdy)711     TIntermTyped *createImplicitCoordTransformationCall(TIntermTyped *P,
712                                                         TIntermTyped *dUVdx,
713                                                         TIntermTyped *dUVdy)
714     {
715         const TType *vec3Type = StaticType::GetBasic<EbtFloat, 3>();
716         TIntermTyped *dPdx    = CreateZeroNode(*vec3Type);
717         TIntermTyped *dPdy    = CreateZeroNode(*vec3Type);
718         TIntermSequence args  = {P, dPdx, dPdy, dUVdx, dUVdy};
719         return TIntermAggregate::CreateFunctionCall(*mCubeXYZToArrayUVLImplicit, &args);
720     }
721 
getMappedSamplerExpression(TIntermNode * samplerCubeExpression)722     TIntermTyped *getMappedSamplerExpression(TIntermNode *samplerCubeExpression)
723     {
724         // The argument passed to a function can either be the sampler, if not array, or a subscript
725         // into the sampler array.
726         TIntermSymbol *asSymbol = samplerCubeExpression->getAsSymbolNode();
727         TIntermBinary *asBinary = samplerCubeExpression->getAsBinaryNode();
728 
729         if (asBinary)
730         {
731             // Only constant indexing is supported in ES2.0.
732             ASSERT(asBinary->getOp() == EOpIndexDirect);
733             asSymbol = asBinary->getLeft()->getAsSymbolNode();
734         }
735 
736         // Arrays of arrays are not available in ES2.0.
737         ASSERT(asSymbol != nullptr);
738         const TVariable *samplerCubeVar = &asSymbol->variable();
739 
740         ASSERT(mSamplerMap.find(samplerCubeVar) != mSamplerMap.end());
741         const TVariable *mappedSamplerVar = mSamplerMap.at(samplerCubeVar);
742 
743         TIntermTyped *mappedExpression = new TIntermSymbol(mappedSamplerVar);
744         if (asBinary)
745         {
746             mappedExpression =
747                 new TIntermBinary(asBinary->getOp(), mappedExpression, asBinary->getRight());
748         }
749 
750         return mappedExpression;
751     }
752 
convertBuiltinFunction(TIntermAggregate * node)753     bool convertBuiltinFunction(TIntermAggregate *node)
754     {
755         const TFunction *function = node->getFunction();
756         if (!function->name().beginsWith("textureCube"))
757         {
758             return false;
759         }
760 
761         // All textureCube* functions are in the form:
762         //
763         //     textureCube??(samplerCube, vec3, ??)
764         //
765         // They should be converted to:
766         //
767         //     texture??(sampler2DArray, convertCoords(vec3), ??)
768         //
769         // We assume the target platform supports texture() functions (currently only used in
770         // Vulkan).
771         //
772         // The intrinsics map as follows:
773         //
774         //     textureCube -> textureGrad
775         //     textureCubeLod -> textureLod
776         //     textureCubeLodEXT -> textureLod
777         //     textureCubeGrad -> textureGrad
778         //     textureCubeGradEXT -> textureGrad
779         //
780         // Note that dPdx and dPdy in textureCubeGrad* are vec3, while the textureGrad equivalent
781         // for sampler2DArray is vec2.  The EXT_shader_texture_lod that introduces thid function
782         // says:
783         //
784         // > For the "Grad" functions, dPdx is the explicit derivative of P with respect
785         // > to window x, and similarly dPdy with respect to window y. ...  For a cube map texture,
786         // > dPdx and dPdy are vec3.
787         // >
788         // > Let
789         // >
790         // >     dSdx = dPdx.s;
791         // >     dSdy = dPdy.s;
792         // >     dTdx = dPdx.t;
793         // >     dTdy = dPdy.t;
794         // >
795         // > and
796         // >
797         // >             / 0.0;    for two-dimensional texture
798         // >     dRdx = (
799         // >             \ dPdx.p; for cube map texture
800         // >
801         // >             / 0.0;    for two-dimensional texture
802         // >     dRdy = (
803         // >             \ dPdy.p; for cube map texture
804         // >
805         // > (See equation 3.12a in The OpenGL ES 2.0 Specification.)
806         //
807         // It's unclear to me what dRdx and dRdy are.  EXT_gpu_shader4 that promotes this function
808         // has the following additional information:
809         //
810         // > For the "Cube" versions, the partial
811         // > derivatives ddx and ddy are assumed to be in the coordinate system used
812         // > before texture coordinates are projected onto the appropriate cube
813         // > face. The partial derivatives of the post-projection texture coordinates,
814         // > which are used for level-of-detail and anisotropic filtering
815         // > calculations, are derived from coord, ddx and ddy in an
816         // > implementation-dependent manner.
817         //
818         // The calculation of dPdx and dPdy is declared as implementation-dependent, so we have
819         // freedom to calculate it as fit, even if not precisely the same as hardware might.
820 
821         const char *substituteFunctionName = "textureGrad";
822         bool isGrad                        = false;
823         bool isTranslatedGrad              = true;
824         bool hasBias                       = false;
825         if (function->name().beginsWith("textureCubeLod"))
826         {
827             substituteFunctionName = "textureLod";
828             isTranslatedGrad       = false;
829         }
830         else if (function->name().beginsWith("textureCubeGrad"))
831         {
832             isGrad = true;
833         }
834         else if (!mIsFragmentShader)
835         {
836             substituteFunctionName = "texture";
837             isTranslatedGrad       = false;
838         }
839 
840         TIntermSequence *arguments = node->getSequence();
841         ASSERT(arguments->size() >= 2);
842 
843         const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
844         const TType *vec3Type = StaticType::GetBasic<EbtFloat, 3>();
845         TIntermSymbol *uvl    = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec3Type));
846         TIntermSymbol *dUVdx  = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
847         TIntermSymbol *dUVdy  = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
848 
849         TIntermTyped *dPdx = nullptr;
850         TIntermTyped *dPdy = nullptr;
851         if (isGrad)
852         {
853             ASSERT(arguments->size() == 4);
854             dPdx = (*arguments)[2]->getAsTyped()->deepCopy();
855             dPdy = (*arguments)[3]->getAsTyped()->deepCopy();
856         }
857         else if (isTranslatedGrad && mIsFragmentShader && arguments->size() == 3)
858         {
859             hasBias = true;
860         }
861         else
862         {
863             dPdx = CreateZeroNode(*vec3Type);
864             dPdy = CreateZeroNode(*vec3Type);
865         }
866 
867         if (isTranslatedGrad && !mIsFragmentShader)
868         {
869             substituteFunctionName = "texture";
870             isTranslatedGrad       = false;
871         }
872 
873         // The function call to transform the coordinates, dPdx and dPdy.  If not textureCubeGrad,
874         // the driver compiler will optimize out the unnecessary calculations.
875         TIntermSequence coordTransform;
876         coordTransform.push_back(CreateTempDeclarationNode(&dUVdx->variable()));
877         coordTransform.push_back(CreateTempDeclarationNode(&dUVdy->variable()));
878         TIntermTyped *coordTransformCall;
879         if (isGrad || !isTranslatedGrad)
880         {
881             coordTransformCall = createCoordTransformationCall(
882                 (*arguments)[1]->getAsTyped()->deepCopy(), dPdx, dPdy, dUVdx, dUVdy);
883         }
884         else
885         {
886             coordTransformCall = createImplicitCoordTransformationCall(
887                 (*arguments)[1]->getAsTyped()->deepCopy(), dUVdx, dUVdy);
888         }
889         coordTransform.push_back(
890             CreateTempInitDeclarationNode(&uvl->variable(), coordTransformCall));
891 
892         TIntermTyped *dUVdxArg = dUVdx;
893         TIntermTyped *dUVdyArg = dUVdy;
894         if (hasBias)
895         {
896             const TType *floatType   = StaticType::GetBasic<EbtFloat>();
897             TIntermTyped *bias       = (*arguments)[2]->getAsTyped()->deepCopy();
898             TIntermSequence exp2Args = {bias};
899             TIntermTyped *exp2Call =
900                 CreateBuiltInFunctionCallNode("exp2", &exp2Args, *mSymbolTable, 100);
901             TIntermSymbol *biasFac = new TIntermSymbol(CreateTempVariable(mSymbolTable, floatType));
902             coordTransform.push_back(CreateTempInitDeclarationNode(&biasFac->variable(), exp2Call));
903             dUVdxArg =
904                 new TIntermBinary(EOpVectorTimesScalar, biasFac->deepCopy(), dUVdx->deepCopy());
905             dUVdyArg =
906                 new TIntermBinary(EOpVectorTimesScalar, biasFac->deepCopy(), dUVdy->deepCopy());
907         }
908 
909         insertStatementsInParentBlock(coordTransform);
910 
911         TIntermSequence substituteArguments;
912         // Replace the first argument (samplerCube) with the sampler2DArray.
913         substituteArguments.push_back(getMappedSamplerExpression((*arguments)[0]));
914         // Replace the second argument with the coordination transformation.
915         substituteArguments.push_back(uvl->deepCopy());
916         if (isTranslatedGrad)
917         {
918             substituteArguments.push_back(dUVdxArg->deepCopy());
919             substituteArguments.push_back(dUVdyArg->deepCopy());
920         }
921         else
922         {
923             // Pass the rest of the parameters as is.
924             for (size_t argIndex = 2; argIndex < arguments->size(); ++argIndex)
925             {
926                 substituteArguments.push_back((*arguments)[argIndex]->getAsTyped()->deepCopy());
927             }
928         }
929 
930         TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
931             substituteFunctionName, &substituteArguments, *mSymbolTable, 300);
932 
933         queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
934 
935         return true;
936     }
937 
938     // A map from the samplerCube variable to the sampler2DArray one.
939     angle::HashMap<const TVariable *, const TVariable *> mSamplerMap;
940 
941     // A helper function to convert xyz coordinates passed to a cube map sampling function into the
942     // array layer (cube map face) and uv coordinates.
943     TFunction *mCubeXYZToArrayUVL;
944     // A specialized version of the same function which uses implicit derivatives.
945     TFunction *mCubeXYZToArrayUVLImplicit;
946 
947     bool mIsFragmentShader;
948 
949     // Stored to be put before the first function after the pass.
950     TIntermFunctionDefinition *mCoordTranslationFunctionDecl;
951     TIntermFunctionDefinition *mCoordTranslationFunctionImplicitDecl;
952 };
953 
954 }  // anonymous namespace
955 
RewriteCubeMapSamplersAs2DArray(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,bool isFragmentShader)956 bool RewriteCubeMapSamplersAs2DArray(TCompiler *compiler,
957                                      TIntermBlock *root,
958                                      TSymbolTable *symbolTable,
959                                      bool isFragmentShader)
960 {
961     RewriteCubeMapSamplersAs2DArrayTraverser traverser(symbolTable, isFragmentShader);
962     root->traverse(&traverser);
963     if (!traverser.updateTree(compiler, root))
964     {
965         return false;
966     }
967 
968     TIntermFunctionDefinition *coordTranslationFunctionDecl =
969         traverser.getCoordTranslationFunctionDecl();
970     TIntermFunctionDefinition *coordTranslationFunctionDeclImplicit =
971         traverser.getCoordTranslationFunctionDeclImplicit();
972     size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
973     if (coordTranslationFunctionDecl)
974     {
975         root->insertChildNodes(firstFunctionIndex, TIntermSequence({coordTranslationFunctionDecl}));
976     }
977     if (coordTranslationFunctionDeclImplicit)
978     {
979         root->insertChildNodes(firstFunctionIndex,
980                                TIntermSequence({coordTranslationFunctionDeclImplicit}));
981     }
982 
983     return compiler->validateAST(root);
984 }
985 
986 }  // namespace sh
987