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