xref: /aosp_15_r20/external/angle/src/compiler/translator/tree_ops/ClampIndirectIndices.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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:
ClampIndirectIndicesTraverser(TCompiler * compiler,TSymbolTable * symbolTable)26     ClampIndirectIndicesTraverser(TCompiler *compiler, TSymbolTable *symbolTable)
27         : TIntermTraverser(true, false, false, symbolTable), mCompiler(compiler)
28     {}
29 
visitBinary(Visit visit,TIntermBinary * node)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:
createClampValue(int value,bool useFloat)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 
ClampIndirectIndices(TCompiler * compiler,TIntermNode * root,TSymbolTable * symbolTable)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
137