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