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