ClampIndirectIndices.cpp (5007B)
1 // 2 // Copyright 2021 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 // ClampIndirectIndices.h: Add clamp to the indirect indices used on arrays. 7 // 8 9 #include "compiler/translator/tree_ops/ClampIndirectIndices.h" 10 11 #include "compiler/translator/Compiler.h" 12 #include "compiler/translator/StaticType.h" 13 #include "compiler/translator/SymbolTable.h" 14 #include "compiler/translator/tree_util/IntermNode_util.h" 15 #include "compiler/translator/tree_util/IntermTraverse.h" 16 17 namespace sh 18 { 19 namespace 20 { 21 // Traverser that finds EOpIndexIndirect nodes and applies a clamp to their right-hand side 22 // expression. 23 class ClampIndirectIndicesTraverser : public TIntermTraverser 24 { 25 public: 26 ClampIndirectIndicesTraverser(TCompiler *compiler, TSymbolTable *symbolTable) 27 : TIntermTraverser(true, false, false, symbolTable), mCompiler(compiler) 28 {} 29 30 bool visitBinary(Visit visit, TIntermBinary *node) override 31 { 32 ASSERT(visit == PreVisit); 33 34 // Only interested in EOpIndexIndirect nodes. 35 if (node->getOp() != EOpIndexIndirect) 36 { 37 return true; 38 } 39 40 // Apply the transformation to the left and right nodes 41 bool valid = ClampIndirectIndices(mCompiler, node->getLeft(), mSymbolTable); 42 ASSERT(valid); 43 valid = ClampIndirectIndices(mCompiler, node->getRight(), mSymbolTable); 44 ASSERT(valid); 45 46 // Generate clamp(right, 0, N), where N is the size of the array being indexed minus 1. If 47 // the array is runtime-sized, the length() method is called on it. 48 const TType &leftType = node->getLeft()->getType(); 49 const TType &rightType = node->getRight()->getType(); 50 51 // Don't clamp indirect indices on unsized arrays in buffer blocks. They are covered by the 52 // relevant robust access behavior of the backend. 53 if (leftType.isUnsizedArray()) 54 { 55 return true; 56 } 57 58 // On GLSL es 100, clamp is only defined for float, so float arguments are used. 59 // 60 // However, float clamp is unconditionally emitted to workaround driver bugs with integer 61 // clamp on Qualcomm. http://crbug.com/1217167 62 // 63 // const bool useFloatClamp = mCompiler->getShaderVersion() == 100; 64 const bool useFloatClamp = true; 65 66 TIntermConstantUnion *zero = createClampValue(0, useFloatClamp); 67 TIntermTyped *max; 68 69 if (leftType.isArray()) 70 { 71 max = createClampValue(static_cast<int>(leftType.getOutermostArraySize()) - 1, 72 useFloatClamp); 73 } 74 else 75 { 76 ASSERT(leftType.isVector() || leftType.isMatrix()); 77 max = createClampValue(leftType.getNominalSize() - 1, useFloatClamp); 78 } 79 80 TIntermTyped *index = node->getRight(); 81 // If the index node is not an int (i.e. it's a uint), or a float (if using float clamp), 82 // cast it. 83 const TBasicType requiredBasicType = useFloatClamp ? EbtFloat : EbtInt; 84 if (rightType.getBasicType() != requiredBasicType) 85 { 86 const TType *clampType = useFloatClamp ? StaticType::GetBasic<EbtFloat, EbpHigh>() 87 : StaticType::GetBasic<EbtInt, EbpHigh>(); 88 TIntermSequence constructorArgs = {index}; 89 index = TIntermAggregate::CreateConstructor(*clampType, &constructorArgs); 90 } 91 92 // min(gl_PointSize, maxPointSize) 93 TIntermSequence args; 94 args.push_back(index); 95 args.push_back(zero); 96 args.push_back(max); 97 TIntermTyped *clamped = 98 CreateBuiltInFunctionCallNode("clamp", &args, *mSymbolTable, useFloatClamp ? 100 : 300); 99 100 // Cast back to int if float clamp was used. 101 if (useFloatClamp) 102 { 103 TIntermSequence constructorArgs = {clamped}; 104 clamped = TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtInt, EbpHigh>(), 105 &constructorArgs); 106 } 107 108 // Replace the right node (the index) with the clamped result. 109 queueReplacementWithParent(node, node->getRight(), clamped, OriginalNode::IS_DROPPED); 110 111 // Don't recurse as left and right nodes are already processed. 112 return false; 113 } 114 115 private: 116 TIntermConstantUnion *createClampValue(int value, bool useFloat) 117 { 118 if (useFloat) 119 { 120 return CreateFloatNode(static_cast<float>(value), EbpHigh); 121 } 122 return CreateIndexNode(value); 123 } 124 125 TCompiler *mCompiler; 126 }; 127 } // anonymous namespace 128 129 bool ClampIndirectIndices(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable) 130 { 131 ClampIndirectIndicesTraverser traverser(compiler, symbolTable); 132 root->traverse(&traverser); 133 return traverser.updateTree(compiler, root); 134 } 135 136 } // namespace sh