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 
7 #include "compiler/translator/tree_ops/ForcePrecisionQualifier.h"
8 #include "angle_gl.h"
9 #include "common/debug.h"
10 #include "compiler/translator/Compiler.h"
11 #include "compiler/translator/tree_util/IntermTraverse.h"
12 #include "compiler/translator/util.h"
13 
14 namespace sh
15 {
16 
17 namespace
18 {
19 class TPrecisionTraverser : public TIntermTraverser
20 {
21   public:
22     TPrecisionTraverser(TSymbolTable *symbolTable);
23 
24   protected:
25     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
26 
27     void overwriteVariablePrecision(TType *type) const;
28 };
29 
TPrecisionTraverser(TSymbolTable * symbolTable)30 TPrecisionTraverser::TPrecisionTraverser(TSymbolTable *symbolTable)
31     : TIntermTraverser(true, true, true, symbolTable)
32 {}
33 
overwriteVariablePrecision(TType * type) const34 void TPrecisionTraverser::overwriteVariablePrecision(TType *type) const
35 {
36     if (type->getPrecision() == EbpHigh)
37     {
38         type->setPrecision(EbpMedium);
39     }
40 }
41 
visitDeclaration(Visit visit,TIntermDeclaration * node)42 bool TPrecisionTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
43 {
44     // Variable declaration.
45     if (visit == PreVisit)
46     {
47         const TIntermSequence &sequence = *(node->getSequence());
48         TIntermTyped *variable          = sequence.front()->getAsTyped();
49         const TType &type               = variable->getType();
50         TQualifier qualifier            = variable->getQualifier();
51 
52         // Don't modify uniform since it might be shared between vertex and fragment shader
53         if (qualifier == EvqUniform)
54         {
55             return true;
56         }
57 
58         // Visit the struct.
59         if (type.isStructSpecifier())
60         {
61             const TStructure *structure = type.getStruct();
62             const TFieldList &fields    = structure->fields();
63             for (size_t i = 0; i < fields.size(); ++i)
64             {
65                 const TField *field    = fields[i];
66                 const TType *fieldType = field->type();
67                 overwriteVariablePrecision((TType *)fieldType);
68             }
69         }
70         else if (type.getBasicType() == EbtInterfaceBlock)
71         {
72             const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
73             const TFieldList &fields              = interfaceBlock->fields();
74             for (const TField *field : fields)
75             {
76                 const TType *fieldType = field->type();
77                 overwriteVariablePrecision((TType *)fieldType);
78             }
79         }
80         else
81         {
82             overwriteVariablePrecision((TType *)&type);
83         }
84     }
85     return true;
86 }
87 }  // namespace
88 
ForceShaderPrecisionToMediump(TIntermNode * root,TSymbolTable * symbolTable,GLenum shaderType)89 bool ForceShaderPrecisionToMediump(TIntermNode *root, TSymbolTable *symbolTable, GLenum shaderType)
90 {
91     if (shaderType != GL_FRAGMENT_SHADER)
92     {
93         return true;
94     }
95 
96     TPrecisionTraverser traverser(symbolTable);
97     root->traverse(&traverser);
98     return true;
99 }
100 
101 }  // namespace sh
102