ValidateClipCullDistance.cpp (6029B)
1 // 2 // Copyright 2020 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 // The ValidateClipCullDistance function checks if the sum of array sizes for gl_ClipDistance and 7 // gl_CullDistance exceeds gl_MaxCombinedClipAndCullDistances 8 // 9 10 #include "ValidateClipCullDistance.h" 11 12 #include "compiler/translator/Diagnostics.h" 13 #include "compiler/translator/SymbolTable.h" 14 #include "compiler/translator/tree_util/IntermTraverse.h" 15 #include "compiler/translator/util.h" 16 17 namespace sh 18 { 19 20 namespace 21 { 22 23 void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) 24 { 25 diagnostics->error(symbol.getLine(), reason, symbol.getName().data()); 26 } 27 28 class ValidateClipCullDistanceTraverser : public TIntermTraverser 29 { 30 public: 31 ValidateClipCullDistanceTraverser(); 32 void validate(TDiagnostics *diagnostics, const unsigned int maxCombinedClipAndCullDistances); 33 34 private: 35 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; 36 bool visitBinary(Visit visit, TIntermBinary *node) override; 37 38 unsigned int mClipDistanceSize; 39 unsigned int mCullDistanceSize; 40 41 unsigned int mMaxClipDistanceIndex; 42 unsigned int mMaxCullDistanceIndex; 43 44 const TIntermSymbol *mClipDistance; 45 const TIntermSymbol *mCullDistance; 46 }; 47 48 ValidateClipCullDistanceTraverser::ValidateClipCullDistanceTraverser() 49 : TIntermTraverser(true, false, false), 50 mClipDistanceSize(0), 51 mCullDistanceSize(0), 52 mMaxClipDistanceIndex(0), 53 mMaxCullDistanceIndex(0), 54 mClipDistance(nullptr), 55 mCullDistance(nullptr) 56 {} 57 58 bool ValidateClipCullDistanceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) 59 { 60 const TIntermSequence &sequence = *(node->getSequence()); 61 62 if (sequence.size() != 1) 63 { 64 return true; 65 } 66 67 const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode(); 68 if (symbol == nullptr) 69 { 70 return true; 71 } 72 73 if (symbol->getName() == "gl_ClipDistance") 74 { 75 mClipDistanceSize = symbol->getOutermostArraySize(); 76 mClipDistance = symbol; 77 } 78 else if (symbol->getName() == "gl_CullDistance") 79 { 80 mCullDistanceSize = symbol->getOutermostArraySize(); 81 mCullDistance = symbol; 82 } 83 84 return true; 85 } 86 87 bool ValidateClipCullDistanceTraverser::visitBinary(Visit visit, TIntermBinary *node) 88 { 89 TOperator op = node->getOp(); 90 if (op != EOpIndexDirect && op != EOpIndexIndirect) 91 { 92 return true; 93 } 94 95 TIntermSymbol *left = node->getLeft()->getAsSymbolNode(); 96 if (!left) 97 { 98 return true; 99 } 100 101 ImmutableString varName(left->getName()); 102 if (varName != "gl_ClipDistance" && varName != "gl_CullDistance") 103 { 104 return true; 105 } 106 107 const TConstantUnion *constIdx = node->getRight()->getConstantValue(); 108 if (constIdx) 109 { 110 unsigned int idx = 0; 111 switch (constIdx->getType()) 112 { 113 case EbtInt: 114 idx = constIdx->getIConst(); 115 break; 116 case EbtUInt: 117 idx = constIdx->getUConst(); 118 break; 119 case EbtFloat: 120 idx = static_cast<unsigned int>(constIdx->getFConst()); 121 break; 122 case EbtBool: 123 idx = constIdx->getBConst() ? 1 : 0; 124 break; 125 default: 126 UNREACHABLE(); 127 break; 128 } 129 130 if (varName == "gl_ClipDistance") 131 { 132 if (idx > mMaxClipDistanceIndex) 133 { 134 mMaxClipDistanceIndex = idx; 135 if (!mClipDistance) 136 { 137 mClipDistance = left; 138 } 139 } 140 } 141 else 142 { 143 ASSERT(varName == "gl_CullDistance"); 144 if (idx > mMaxCullDistanceIndex) 145 { 146 mMaxCullDistanceIndex = idx; 147 if (!mCullDistance) 148 { 149 mCullDistance = left; 150 } 151 } 152 } 153 } 154 155 return true; 156 } 157 158 void ValidateClipCullDistanceTraverser::validate(TDiagnostics *diagnostics, 159 const unsigned int maxCombinedClipAndCullDistances) 160 { 161 ASSERT(diagnostics); 162 163 unsigned int enabledClipDistances = 164 (mClipDistanceSize > 0 ? mClipDistanceSize 165 : (mClipDistance ? mMaxClipDistanceIndex + 1 : 0)); 166 unsigned int enabledCullDistances = 167 (mCullDistanceSize > 0 ? mCullDistanceSize 168 : (mCullDistance ? mMaxCullDistanceIndex + 1 : 0)); 169 unsigned int combinedClipAndCullDistances = 170 (enabledClipDistances > 0 && enabledCullDistances > 0 171 ? enabledClipDistances + enabledCullDistances 172 : 0); 173 174 if (combinedClipAndCullDistances > maxCombinedClipAndCullDistances) 175 { 176 const TIntermSymbol *greaterSymbol = 177 (enabledClipDistances >= enabledCullDistances ? mClipDistance : mCullDistance); 178 179 std::stringstream strstr = sh::InitializeStream<std::stringstream>(); 180 strstr << "The sum of 'gl_ClipDistance' and 'gl_CullDistance' size is greater than " 181 "gl_MaxCombinedClipAndCullDistances (" 182 << combinedClipAndCullDistances << " > " << maxCombinedClipAndCullDistances << ")"; 183 error(*greaterSymbol, strstr.str().c_str(), diagnostics); 184 } 185 } 186 187 } // anonymous namespace 188 189 bool ValidateClipCullDistance(TIntermBlock *root, 190 TDiagnostics *diagnostics, 191 const unsigned int maxCombinedClipAndCullDistances) 192 { 193 ValidateClipCullDistanceTraverser varyingValidator; 194 root->traverse(&varyingValidator); 195 int numErrorsBefore = diagnostics->numErrors(); 196 varyingValidator.validate(diagnostics, maxCombinedClipAndCullDistances); 197 return (diagnostics->numErrors() == numErrorsBefore); 198 } 199 200 } // namespace sh