RewriteCubeMapSamplersAs2DArray.cpp (46198B)
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 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 44 TIntermTyped *Swizzle1(TIntermTyped *array, int i) 45 { 46 return new TIntermSwizzle(array, {i}); 47 } 48 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. 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 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 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 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 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 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 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 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 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: 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 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 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 262 TIntermFunctionDefinition *getCoordTranslationFunctionDecl() 263 { 264 return mCoordTranslationFunctionDecl; 265 } 266 267 TIntermFunctionDefinition *getCoordTranslationFunctionDeclImplicit() 268 { 269 return mCoordTranslationFunctionImplicitDecl; 270 } 271 272 private: 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 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 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 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 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 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 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