xref: /aosp_15_r20/external/angle/src/libANGLE/ProgramLinkedResources.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker 
7*8975f5c5SAndroid Build Coastguard Worker // ProgramLinkedResources.cpp: implements link-time checks for default block uniforms, and generates
8*8975f5c5SAndroid Build Coastguard Worker // uniform locations. Populates data structures related to uniforms so that they can be stored in
9*8975f5c5SAndroid Build Coastguard Worker // program state.
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/ProgramLinkedResources.h"
12*8975f5c5SAndroid Build Coastguard Worker 
13*8975f5c5SAndroid Build Coastguard Worker #include "common/string_utils.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "common/utilities.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Caps.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Shader.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/features.h"
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker namespace gl
21*8975f5c5SAndroid Build Coastguard Worker {
22*8975f5c5SAndroid Build Coastguard Worker namespace
23*8975f5c5SAndroid Build Coastguard Worker {
FindUniform(std::vector<UsedUniform> & list,const std::string & name)24*8975f5c5SAndroid Build Coastguard Worker UsedUniform *FindUniform(std::vector<UsedUniform> &list, const std::string &name)
25*8975f5c5SAndroid Build Coastguard Worker {
26*8975f5c5SAndroid Build Coastguard Worker     for (UsedUniform &uniform : list)
27*8975f5c5SAndroid Build Coastguard Worker     {
28*8975f5c5SAndroid Build Coastguard Worker         if (uniform.name == name)
29*8975f5c5SAndroid Build Coastguard Worker             return &uniform;
30*8975f5c5SAndroid Build Coastguard Worker     }
31*8975f5c5SAndroid Build Coastguard Worker 
32*8975f5c5SAndroid Build Coastguard Worker     return nullptr;
33*8975f5c5SAndroid Build Coastguard Worker }
34*8975f5c5SAndroid Build Coastguard Worker 
35*8975f5c5SAndroid Build Coastguard Worker template <typename VarT>
SetActive(std::vector<VarT> * list,const std::string & name,ShaderType shaderType,bool active,uint32_t id)36*8975f5c5SAndroid Build Coastguard Worker void SetActive(std::vector<VarT> *list,
37*8975f5c5SAndroid Build Coastguard Worker                const std::string &name,
38*8975f5c5SAndroid Build Coastguard Worker                ShaderType shaderType,
39*8975f5c5SAndroid Build Coastguard Worker                bool active,
40*8975f5c5SAndroid Build Coastguard Worker                uint32_t id)
41*8975f5c5SAndroid Build Coastguard Worker {
42*8975f5c5SAndroid Build Coastguard Worker     for (auto &variable : *list)
43*8975f5c5SAndroid Build Coastguard Worker     {
44*8975f5c5SAndroid Build Coastguard Worker         if (variable.name == name)
45*8975f5c5SAndroid Build Coastguard Worker         {
46*8975f5c5SAndroid Build Coastguard Worker             variable.setActive(shaderType, active, id);
47*8975f5c5SAndroid Build Coastguard Worker             return;
48*8975f5c5SAndroid Build Coastguard Worker         }
49*8975f5c5SAndroid Build Coastguard Worker     }
50*8975f5c5SAndroid Build Coastguard Worker }
51*8975f5c5SAndroid Build Coastguard Worker 
52*8975f5c5SAndroid Build Coastguard Worker template <typename VarT>
SetActive(std::vector<VarT> * list,std::vector<std::string> * nameList,const std::string & name,ShaderType shaderType,bool active,uint32_t id)53*8975f5c5SAndroid Build Coastguard Worker void SetActive(std::vector<VarT> *list,
54*8975f5c5SAndroid Build Coastguard Worker                std::vector<std::string> *nameList,
55*8975f5c5SAndroid Build Coastguard Worker                const std::string &name,
56*8975f5c5SAndroid Build Coastguard Worker                ShaderType shaderType,
57*8975f5c5SAndroid Build Coastguard Worker                bool active,
58*8975f5c5SAndroid Build Coastguard Worker                uint32_t id)
59*8975f5c5SAndroid Build Coastguard Worker {
60*8975f5c5SAndroid Build Coastguard Worker     for (GLint index = 0; index < static_cast<GLint>(nameList->size()); index++)
61*8975f5c5SAndroid Build Coastguard Worker     {
62*8975f5c5SAndroid Build Coastguard Worker         if ((*nameList)[index] == name)
63*8975f5c5SAndroid Build Coastguard Worker         {
64*8975f5c5SAndroid Build Coastguard Worker             (*list)[index].setActive(shaderType, active, id);
65*8975f5c5SAndroid Build Coastguard Worker             return;
66*8975f5c5SAndroid Build Coastguard Worker         }
67*8975f5c5SAndroid Build Coastguard Worker     }
68*8975f5c5SAndroid Build Coastguard Worker }
69*8975f5c5SAndroid Build Coastguard Worker 
70*8975f5c5SAndroid Build Coastguard Worker // GLSL ES Spec 3.00.3, section 4.3.5.
LinkValidateUniforms(const sh::ShaderVariable & uniform1,const sh::ShaderVariable & uniform2,std::string * mismatchedStructFieldName)71*8975f5c5SAndroid Build Coastguard Worker LinkMismatchError LinkValidateUniforms(const sh::ShaderVariable &uniform1,
72*8975f5c5SAndroid Build Coastguard Worker                                        const sh::ShaderVariable &uniform2,
73*8975f5c5SAndroid Build Coastguard Worker                                        std::string *mismatchedStructFieldName)
74*8975f5c5SAndroid Build Coastguard Worker {
75*8975f5c5SAndroid Build Coastguard Worker #if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION
76*8975f5c5SAndroid Build Coastguard Worker     const bool validatePrecisionFeature = true;
77*8975f5c5SAndroid Build Coastguard Worker #else
78*8975f5c5SAndroid Build Coastguard Worker     const bool validatePrecisionFeature = false;
79*8975f5c5SAndroid Build Coastguard Worker #endif
80*8975f5c5SAndroid Build Coastguard Worker 
81*8975f5c5SAndroid Build Coastguard Worker     // Validate precision match of uniforms iff they are statically used
82*8975f5c5SAndroid Build Coastguard Worker     bool validatePrecision = uniform1.staticUse && uniform2.staticUse && validatePrecisionFeature;
83*8975f5c5SAndroid Build Coastguard Worker     LinkMismatchError linkError = LinkValidateProgramVariables(
84*8975f5c5SAndroid Build Coastguard Worker         uniform1, uniform2, validatePrecision, false, false, mismatchedStructFieldName);
85*8975f5c5SAndroid Build Coastguard Worker     if (linkError != LinkMismatchError::NO_MISMATCH)
86*8975f5c5SAndroid Build Coastguard Worker     {
87*8975f5c5SAndroid Build Coastguard Worker         return linkError;
88*8975f5c5SAndroid Build Coastguard Worker     }
89*8975f5c5SAndroid Build Coastguard Worker 
90*8975f5c5SAndroid Build Coastguard Worker     // GLSL ES Spec 3.10.4, section 4.4.5.
91*8975f5c5SAndroid Build Coastguard Worker     if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
92*8975f5c5SAndroid Build Coastguard Worker     {
93*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::BINDING_MISMATCH;
94*8975f5c5SAndroid Build Coastguard Worker     }
95*8975f5c5SAndroid Build Coastguard Worker 
96*8975f5c5SAndroid Build Coastguard Worker     // GLSL ES Spec 3.10.4, section 9.2.1.
97*8975f5c5SAndroid Build Coastguard Worker     if (uniform1.location != -1 && uniform2.location != -1 &&
98*8975f5c5SAndroid Build Coastguard Worker         uniform1.location != uniform2.location)
99*8975f5c5SAndroid Build Coastguard Worker     {
100*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::LOCATION_MISMATCH;
101*8975f5c5SAndroid Build Coastguard Worker     }
102*8975f5c5SAndroid Build Coastguard Worker     if (uniform1.offset != uniform2.offset)
103*8975f5c5SAndroid Build Coastguard Worker     {
104*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::OFFSET_MISMATCH;
105*8975f5c5SAndroid Build Coastguard Worker     }
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker     return LinkMismatchError::NO_MISMATCH;
108*8975f5c5SAndroid Build Coastguard Worker }
109*8975f5c5SAndroid Build Coastguard Worker 
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)110*8975f5c5SAndroid Build Coastguard Worker GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
111*8975f5c5SAndroid Build Coastguard Worker {
112*8975f5c5SAndroid Build Coastguard Worker     switch (shaderType)
113*8975f5c5SAndroid Build Coastguard Worker     {
114*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::Vertex:
115*8975f5c5SAndroid Build Coastguard Worker             return static_cast<GLuint>(caps.maxVertexUniformVectors);
116*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::Fragment:
117*8975f5c5SAndroid Build Coastguard Worker             return static_cast<GLuint>(caps.maxFragmentUniformVectors);
118*8975f5c5SAndroid Build Coastguard Worker 
119*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::Compute:
120*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::Geometry:
121*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::TessControl:
122*8975f5c5SAndroid Build Coastguard Worker         case ShaderType::TessEvaluation:
123*8975f5c5SAndroid Build Coastguard Worker             return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
124*8975f5c5SAndroid Build Coastguard Worker 
125*8975f5c5SAndroid Build Coastguard Worker         default:
126*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
127*8975f5c5SAndroid Build Coastguard Worker             return 0u;
128*8975f5c5SAndroid Build Coastguard Worker     }
129*8975f5c5SAndroid Build Coastguard Worker }
130*8975f5c5SAndroid Build Coastguard Worker 
131*8975f5c5SAndroid Build Coastguard Worker enum class UniformType : uint8_t
132*8975f5c5SAndroid Build Coastguard Worker {
133*8975f5c5SAndroid Build Coastguard Worker     Variable      = 0,
134*8975f5c5SAndroid Build Coastguard Worker     Sampler       = 1,
135*8975f5c5SAndroid Build Coastguard Worker     Image         = 2,
136*8975f5c5SAndroid Build Coastguard Worker     AtomicCounter = 3,
137*8975f5c5SAndroid Build Coastguard Worker 
138*8975f5c5SAndroid Build Coastguard Worker     InvalidEnum = 4,
139*8975f5c5SAndroid Build Coastguard Worker     EnumCount   = 4,
140*8975f5c5SAndroid Build Coastguard Worker };
141*8975f5c5SAndroid Build Coastguard Worker 
GetUniformResourceNameString(UniformType uniformType)142*8975f5c5SAndroid Build Coastguard Worker const char *GetUniformResourceNameString(UniformType uniformType)
143*8975f5c5SAndroid Build Coastguard Worker {
144*8975f5c5SAndroid Build Coastguard Worker     switch (uniformType)
145*8975f5c5SAndroid Build Coastguard Worker     {
146*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Variable:
147*8975f5c5SAndroid Build Coastguard Worker             return "uniform";
148*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Sampler:
149*8975f5c5SAndroid Build Coastguard Worker             return "texture image unit";
150*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Image:
151*8975f5c5SAndroid Build Coastguard Worker             return "image uniform";
152*8975f5c5SAndroid Build Coastguard Worker         case UniformType::AtomicCounter:
153*8975f5c5SAndroid Build Coastguard Worker             return "atomic counter";
154*8975f5c5SAndroid Build Coastguard Worker         default:
155*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
156*8975f5c5SAndroid Build Coastguard Worker             return "";
157*8975f5c5SAndroid Build Coastguard Worker     }
158*8975f5c5SAndroid Build Coastguard Worker }
159*8975f5c5SAndroid Build Coastguard Worker 
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)160*8975f5c5SAndroid Build Coastguard Worker std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
161*8975f5c5SAndroid Build Coastguard Worker {
162*8975f5c5SAndroid Build Coastguard Worker     // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
163*8975f5c5SAndroid Build Coastguard Worker     if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
164*8975f5c5SAndroid Build Coastguard Worker     {
165*8975f5c5SAndroid Build Coastguard Worker         return "MAX_TEXTURE_IMAGE_UNITS";
166*8975f5c5SAndroid Build Coastguard Worker     }
167*8975f5c5SAndroid Build Coastguard Worker 
168*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream ostream;
169*8975f5c5SAndroid Build Coastguard Worker     ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
170*8975f5c5SAndroid Build Coastguard Worker 
171*8975f5c5SAndroid Build Coastguard Worker     switch (uniformType)
172*8975f5c5SAndroid Build Coastguard Worker     {
173*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Variable:
174*8975f5c5SAndroid Build Coastguard Worker             // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
175*8975f5c5SAndroid Build Coastguard Worker             // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
176*8975f5c5SAndroid Build Coastguard Worker             if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
177*8975f5c5SAndroid Build Coastguard Worker             {
178*8975f5c5SAndroid Build Coastguard Worker                 ostream << "UNIFORM_VECTORS";
179*8975f5c5SAndroid Build Coastguard Worker                 break;
180*8975f5c5SAndroid Build Coastguard Worker             }
181*8975f5c5SAndroid Build Coastguard Worker             // For compute and geometry shaders, there are no definitions on
182*8975f5c5SAndroid Build Coastguard Worker             // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
183*8975f5c5SAndroid Build Coastguard Worker             // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
184*8975f5c5SAndroid Build Coastguard Worker             else
185*8975f5c5SAndroid Build Coastguard Worker             {
186*8975f5c5SAndroid Build Coastguard Worker                 ostream << "UNIFORM_COMPONENTS";
187*8975f5c5SAndroid Build Coastguard Worker             }
188*8975f5c5SAndroid Build Coastguard Worker             break;
189*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Sampler:
190*8975f5c5SAndroid Build Coastguard Worker             ostream << "TEXTURE_IMAGE_UNITS";
191*8975f5c5SAndroid Build Coastguard Worker             break;
192*8975f5c5SAndroid Build Coastguard Worker         case UniformType::Image:
193*8975f5c5SAndroid Build Coastguard Worker             ostream << "IMAGE_UNIFORMS";
194*8975f5c5SAndroid Build Coastguard Worker             break;
195*8975f5c5SAndroid Build Coastguard Worker         case UniformType::AtomicCounter:
196*8975f5c5SAndroid Build Coastguard Worker             ostream << "ATOMIC_COUNTERS";
197*8975f5c5SAndroid Build Coastguard Worker             break;
198*8975f5c5SAndroid Build Coastguard Worker         default:
199*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
200*8975f5c5SAndroid Build Coastguard Worker             return "";
201*8975f5c5SAndroid Build Coastguard Worker     }
202*8975f5c5SAndroid Build Coastguard Worker 
203*8975f5c5SAndroid Build Coastguard Worker     if (shaderType == ShaderType::Geometry)
204*8975f5c5SAndroid Build Coastguard Worker     {
205*8975f5c5SAndroid Build Coastguard Worker         ostream << "_EXT";
206*8975f5c5SAndroid Build Coastguard Worker     }
207*8975f5c5SAndroid Build Coastguard Worker 
208*8975f5c5SAndroid Build Coastguard Worker     return ostream.str();
209*8975f5c5SAndroid Build Coastguard Worker }
210*8975f5c5SAndroid Build Coastguard Worker 
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)211*8975f5c5SAndroid Build Coastguard Worker void LogUniformsExceedLimit(ShaderType shaderType,
212*8975f5c5SAndroid Build Coastguard Worker                             UniformType uniformType,
213*8975f5c5SAndroid Build Coastguard Worker                             GLuint limit,
214*8975f5c5SAndroid Build Coastguard Worker                             InfoLog &infoLog)
215*8975f5c5SAndroid Build Coastguard Worker {
216*8975f5c5SAndroid Build Coastguard Worker     infoLog << GetShaderTypeString(shaderType) << " shader "
217*8975f5c5SAndroid Build Coastguard Worker             << GetUniformResourceNameString(uniformType) << "s count exceeds "
218*8975f5c5SAndroid Build Coastguard Worker             << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
219*8975f5c5SAndroid Build Coastguard Worker }
220*8975f5c5SAndroid Build Coastguard Worker 
221*8975f5c5SAndroid Build Coastguard Worker // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
222*8975f5c5SAndroid Build Coastguard Worker // added to "uniformsOut".
223*8975f5c5SAndroid Build Coastguard Worker class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
224*8975f5c5SAndroid Build Coastguard Worker {
225*8975f5c5SAndroid Build Coastguard Worker   public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,ShaderType shaderType,int blockIndex)226*8975f5c5SAndroid Build Coastguard Worker     UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
227*8975f5c5SAndroid Build Coastguard Worker                                 const std::string &namePrefix,
228*8975f5c5SAndroid Build Coastguard Worker                                 const std::string &mappedNamePrefix,
229*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<LinkedUniform> *uniformsOut,
230*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<std::string> *uniformNamesOut,
231*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<std::string> *uniformMappedNamesOut,
232*8975f5c5SAndroid Build Coastguard Worker                                 ShaderType shaderType,
233*8975f5c5SAndroid Build Coastguard Worker                                 int blockIndex)
234*8975f5c5SAndroid Build Coastguard Worker         : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
235*8975f5c5SAndroid Build Coastguard Worker           mGetMemberInfo(getMemberInfo),
236*8975f5c5SAndroid Build Coastguard Worker           mUniformsOut(uniformsOut),
237*8975f5c5SAndroid Build Coastguard Worker           mUniformNamesOut(uniformNamesOut),
238*8975f5c5SAndroid Build Coastguard Worker           mUniformMappedNamesOut(uniformMappedNamesOut),
239*8975f5c5SAndroid Build Coastguard Worker           mShaderType(shaderType),
240*8975f5c5SAndroid Build Coastguard Worker           mBlockIndex(blockIndex)
241*8975f5c5SAndroid Build Coastguard Worker     {}
242*8975f5c5SAndroid Build Coastguard Worker 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)243*8975f5c5SAndroid Build Coastguard Worker     void visitNamedVariable(const sh::ShaderVariable &variable,
244*8975f5c5SAndroid Build Coastguard Worker                             bool isRowMajor,
245*8975f5c5SAndroid Build Coastguard Worker                             const std::string &name,
246*8975f5c5SAndroid Build Coastguard Worker                             const std::string &mappedName,
247*8975f5c5SAndroid Build Coastguard Worker                             const std::vector<unsigned int> &arraySizes) override
248*8975f5c5SAndroid Build Coastguard Worker     {
249*8975f5c5SAndroid Build Coastguard Worker         // If getBlockMemberInfo returns false, the variable is optimized out.
250*8975f5c5SAndroid Build Coastguard Worker         sh::BlockMemberInfo variableInfo;
251*8975f5c5SAndroid Build Coastguard Worker         if (!mGetMemberInfo(name, mappedName, &variableInfo))
252*8975f5c5SAndroid Build Coastguard Worker             return;
253*8975f5c5SAndroid Build Coastguard Worker 
254*8975f5c5SAndroid Build Coastguard Worker         std::string nameWithArrayIndex       = name;
255*8975f5c5SAndroid Build Coastguard Worker         std::string mappedNameWithArrayIndex = mappedName;
256*8975f5c5SAndroid Build Coastguard Worker 
257*8975f5c5SAndroid Build Coastguard Worker         if (variable.isArray())
258*8975f5c5SAndroid Build Coastguard Worker         {
259*8975f5c5SAndroid Build Coastguard Worker             nameWithArrayIndex += "[0]";
260*8975f5c5SAndroid Build Coastguard Worker             mappedNameWithArrayIndex += "[0]";
261*8975f5c5SAndroid Build Coastguard Worker         }
262*8975f5c5SAndroid Build Coastguard Worker 
263*8975f5c5SAndroid Build Coastguard Worker         if (mBlockIndex == -1)
264*8975f5c5SAndroid Build Coastguard Worker         {
265*8975f5c5SAndroid Build Coastguard Worker             SetActive(mUniformsOut, mUniformNamesOut, nameWithArrayIndex, mShaderType,
266*8975f5c5SAndroid Build Coastguard Worker                       variable.active, variable.id);
267*8975f5c5SAndroid Build Coastguard Worker             return;
268*8975f5c5SAndroid Build Coastguard Worker         }
269*8975f5c5SAndroid Build Coastguard Worker 
270*8975f5c5SAndroid Build Coastguard Worker         LinkedUniform newUniform(variable.type, variable.precision, variable.arraySizes, -1, -1, -1,
271*8975f5c5SAndroid Build Coastguard Worker                                  mBlockIndex, variableInfo);
272*8975f5c5SAndroid Build Coastguard Worker         newUniform.setActive(mShaderType, variable.active, variable.id);
273*8975f5c5SAndroid Build Coastguard Worker 
274*8975f5c5SAndroid Build Coastguard Worker         // Since block uniforms have no location, we don't need to store them in the uniform
275*8975f5c5SAndroid Build Coastguard Worker         // locations list.
276*8975f5c5SAndroid Build Coastguard Worker         mUniformsOut->push_back(newUniform);
277*8975f5c5SAndroid Build Coastguard Worker         mUniformNamesOut->push_back(nameWithArrayIndex);
278*8975f5c5SAndroid Build Coastguard Worker         mUniformMappedNamesOut->push_back(mappedNameWithArrayIndex);
279*8975f5c5SAndroid Build Coastguard Worker     }
280*8975f5c5SAndroid Build Coastguard Worker 
281*8975f5c5SAndroid Build Coastguard Worker   private:
282*8975f5c5SAndroid Build Coastguard Worker     const GetBlockMemberInfoFunc &mGetMemberInfo;
283*8975f5c5SAndroid Build Coastguard Worker     std::vector<LinkedUniform> *mUniformsOut;
284*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> *mUniformNamesOut;
285*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> *mUniformMappedNamesOut;
286*8975f5c5SAndroid Build Coastguard Worker     const ShaderType mShaderType;
287*8975f5c5SAndroid Build Coastguard Worker     const int mBlockIndex;
288*8975f5c5SAndroid Build Coastguard Worker };
289*8975f5c5SAndroid Build Coastguard Worker 
290*8975f5c5SAndroid Build Coastguard Worker // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
291*8975f5c5SAndroid Build Coastguard Worker // new buffer variable is stored in "bufferVariablesOut".
292*8975f5c5SAndroid Build Coastguard Worker class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
293*8975f5c5SAndroid Build Coastguard Worker {
294*8975f5c5SAndroid Build Coastguard Worker   public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)295*8975f5c5SAndroid Build Coastguard Worker     ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
296*8975f5c5SAndroid Build Coastguard Worker                               const std::string &namePrefix,
297*8975f5c5SAndroid Build Coastguard Worker                               const std::string &mappedNamePrefix,
298*8975f5c5SAndroid Build Coastguard Worker                               std::vector<BufferVariable> *bufferVariablesOut,
299*8975f5c5SAndroid Build Coastguard Worker                               ShaderType shaderType,
300*8975f5c5SAndroid Build Coastguard Worker                               int blockIndex)
301*8975f5c5SAndroid Build Coastguard Worker         : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mStubEncoder),
302*8975f5c5SAndroid Build Coastguard Worker           mGetMemberInfo(getMemberInfo),
303*8975f5c5SAndroid Build Coastguard Worker           mBufferVariablesOut(bufferVariablesOut),
304*8975f5c5SAndroid Build Coastguard Worker           mShaderType(shaderType),
305*8975f5c5SAndroid Build Coastguard Worker           mBlockIndex(blockIndex)
306*8975f5c5SAndroid Build Coastguard Worker     {}
307*8975f5c5SAndroid Build Coastguard Worker 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)308*8975f5c5SAndroid Build Coastguard Worker     void visitNamedVariable(const sh::ShaderVariable &variable,
309*8975f5c5SAndroid Build Coastguard Worker                             bool isRowMajor,
310*8975f5c5SAndroid Build Coastguard Worker                             const std::string &name,
311*8975f5c5SAndroid Build Coastguard Worker                             const std::string &mappedName,
312*8975f5c5SAndroid Build Coastguard Worker                             const std::vector<unsigned int> &arraySizes) override
313*8975f5c5SAndroid Build Coastguard Worker     {
314*8975f5c5SAndroid Build Coastguard Worker         if (mSkipEnabled)
315*8975f5c5SAndroid Build Coastguard Worker             return;
316*8975f5c5SAndroid Build Coastguard Worker 
317*8975f5c5SAndroid Build Coastguard Worker         // If getBlockMemberInfo returns false, the variable is optimized out.
318*8975f5c5SAndroid Build Coastguard Worker         sh::BlockMemberInfo variableInfo;
319*8975f5c5SAndroid Build Coastguard Worker         if (!mGetMemberInfo(name, mappedName, &variableInfo))
320*8975f5c5SAndroid Build Coastguard Worker             return;
321*8975f5c5SAndroid Build Coastguard Worker 
322*8975f5c5SAndroid Build Coastguard Worker         std::string nameWithArrayIndex       = name;
323*8975f5c5SAndroid Build Coastguard Worker         std::string mappedNameWithArrayIndex = mappedName;
324*8975f5c5SAndroid Build Coastguard Worker 
325*8975f5c5SAndroid Build Coastguard Worker         if (variable.isArray())
326*8975f5c5SAndroid Build Coastguard Worker         {
327*8975f5c5SAndroid Build Coastguard Worker             nameWithArrayIndex += "[0]";
328*8975f5c5SAndroid Build Coastguard Worker             mappedNameWithArrayIndex += "[0]";
329*8975f5c5SAndroid Build Coastguard Worker         }
330*8975f5c5SAndroid Build Coastguard Worker 
331*8975f5c5SAndroid Build Coastguard Worker         if (mBlockIndex == -1)
332*8975f5c5SAndroid Build Coastguard Worker         {
333*8975f5c5SAndroid Build Coastguard Worker             SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active,
334*8975f5c5SAndroid Build Coastguard Worker                       variable.id);
335*8975f5c5SAndroid Build Coastguard Worker             return;
336*8975f5c5SAndroid Build Coastguard Worker         }
337*8975f5c5SAndroid Build Coastguard Worker 
338*8975f5c5SAndroid Build Coastguard Worker         BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
339*8975f5c5SAndroid Build Coastguard Worker                                          variable.arraySizes, mBlockIndex, mTopLevelArraySize,
340*8975f5c5SAndroid Build Coastguard Worker                                          variableInfo);
341*8975f5c5SAndroid Build Coastguard Worker         newBufferVariable.mappedName = mappedNameWithArrayIndex;
342*8975f5c5SAndroid Build Coastguard Worker         newBufferVariable.setActive(mShaderType, variable.active, variable.id);
343*8975f5c5SAndroid Build Coastguard Worker 
344*8975f5c5SAndroid Build Coastguard Worker         mBufferVariablesOut->push_back(newBufferVariable);
345*8975f5c5SAndroid Build Coastguard Worker     }
346*8975f5c5SAndroid Build Coastguard Worker 
347*8975f5c5SAndroid Build Coastguard Worker   private:
348*8975f5c5SAndroid Build Coastguard Worker     const GetBlockMemberInfoFunc &mGetMemberInfo;
349*8975f5c5SAndroid Build Coastguard Worker     std::vector<BufferVariable> *mBufferVariablesOut;
350*8975f5c5SAndroid Build Coastguard Worker     const ShaderType mShaderType;
351*8975f5c5SAndroid Build Coastguard Worker     const int mBlockIndex;
352*8975f5c5SAndroid Build Coastguard Worker     sh::StubBlockEncoder mStubEncoder;
353*8975f5c5SAndroid Build Coastguard Worker };
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker struct ShaderUniformCount
356*8975f5c5SAndroid Build Coastguard Worker {
357*8975f5c5SAndroid Build Coastguard Worker     unsigned int vectorCount        = 0;
358*8975f5c5SAndroid Build Coastguard Worker     unsigned int samplerCount       = 0;
359*8975f5c5SAndroid Build Coastguard Worker     unsigned int imageCount         = 0;
360*8975f5c5SAndroid Build Coastguard Worker     unsigned int atomicCounterCount = 0;
361*8975f5c5SAndroid Build Coastguard Worker     unsigned int fragmentInOutCount = 0;
362*8975f5c5SAndroid Build Coastguard Worker };
363*8975f5c5SAndroid Build Coastguard Worker 
operator +=(ShaderUniformCount & lhs,const ShaderUniformCount & rhs)364*8975f5c5SAndroid Build Coastguard Worker ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
365*8975f5c5SAndroid Build Coastguard Worker {
366*8975f5c5SAndroid Build Coastguard Worker     lhs.vectorCount += rhs.vectorCount;
367*8975f5c5SAndroid Build Coastguard Worker     lhs.samplerCount += rhs.samplerCount;
368*8975f5c5SAndroid Build Coastguard Worker     lhs.imageCount += rhs.imageCount;
369*8975f5c5SAndroid Build Coastguard Worker     lhs.atomicCounterCount += rhs.atomicCounterCount;
370*8975f5c5SAndroid Build Coastguard Worker     lhs.fragmentInOutCount += rhs.fragmentInOutCount;
371*8975f5c5SAndroid Build Coastguard Worker     return lhs;
372*8975f5c5SAndroid Build Coastguard Worker }
373*8975f5c5SAndroid Build Coastguard Worker 
374*8975f5c5SAndroid Build Coastguard Worker // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
375*8975f5c5SAndroid Build Coastguard Worker // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
376*8975f5c5SAndroid Build Coastguard Worker // Counts for each uniform category are stored and can be queried with "getCounts".
377*8975f5c5SAndroid Build Coastguard Worker class FlattenUniformVisitor : public sh::VariableNameVisitor
378*8975f5c5SAndroid Build Coastguard Worker {
379*8975f5c5SAndroid Build Coastguard Worker   public:
FlattenUniformVisitor(ShaderType shaderType,const sh::ShaderVariable & uniform,std::vector<UsedUniform> * uniforms,std::vector<UsedUniform> * samplerUniforms,std::vector<UsedUniform> * imageUniforms,std::vector<UsedUniform> * atomicCounterUniforms,std::vector<UsedUniform> * inputAttachmentUniforms,std::vector<UnusedUniform> * unusedUniforms)380*8975f5c5SAndroid Build Coastguard Worker     FlattenUniformVisitor(ShaderType shaderType,
381*8975f5c5SAndroid Build Coastguard Worker                           const sh::ShaderVariable &uniform,
382*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UsedUniform> *uniforms,
383*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UsedUniform> *samplerUniforms,
384*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UsedUniform> *imageUniforms,
385*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UsedUniform> *atomicCounterUniforms,
386*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UsedUniform> *inputAttachmentUniforms,
387*8975f5c5SAndroid Build Coastguard Worker                           std::vector<UnusedUniform> *unusedUniforms)
388*8975f5c5SAndroid Build Coastguard Worker         : sh::VariableNameVisitor("", ""),
389*8975f5c5SAndroid Build Coastguard Worker           mShaderType(shaderType),
390*8975f5c5SAndroid Build Coastguard Worker           mMarkActive(uniform.active),
391*8975f5c5SAndroid Build Coastguard Worker           mMarkStaticUse(uniform.staticUse),
392*8975f5c5SAndroid Build Coastguard Worker           mBinding(uniform.binding),
393*8975f5c5SAndroid Build Coastguard Worker           mOffset(uniform.offset),
394*8975f5c5SAndroid Build Coastguard Worker           mLocation(uniform.location),
395*8975f5c5SAndroid Build Coastguard Worker           mUniforms(uniforms),
396*8975f5c5SAndroid Build Coastguard Worker           mSamplerUniforms(samplerUniforms),
397*8975f5c5SAndroid Build Coastguard Worker           mImageUniforms(imageUniforms),
398*8975f5c5SAndroid Build Coastguard Worker           mAtomicCounterUniforms(atomicCounterUniforms),
399*8975f5c5SAndroid Build Coastguard Worker           mInputAttachmentUniforms(inputAttachmentUniforms),
400*8975f5c5SAndroid Build Coastguard Worker           mUnusedUniforms(unusedUniforms)
401*8975f5c5SAndroid Build Coastguard Worker     {}
402*8975f5c5SAndroid Build Coastguard Worker 
visitNamedOpaqueObject(const sh::ShaderVariable & variable,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)403*8975f5c5SAndroid Build Coastguard Worker     void visitNamedOpaqueObject(const sh::ShaderVariable &variable,
404*8975f5c5SAndroid Build Coastguard Worker                                 const std::string &name,
405*8975f5c5SAndroid Build Coastguard Worker                                 const std::string &mappedName,
406*8975f5c5SAndroid Build Coastguard Worker                                 const std::vector<unsigned int> &arraySizes) override
407*8975f5c5SAndroid Build Coastguard Worker     {
408*8975f5c5SAndroid Build Coastguard Worker         visitNamedVariable(variable, false, name, mappedName, arraySizes);
409*8975f5c5SAndroid Build Coastguard Worker     }
410*8975f5c5SAndroid Build Coastguard Worker 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)411*8975f5c5SAndroid Build Coastguard Worker     void visitNamedVariable(const sh::ShaderVariable &variable,
412*8975f5c5SAndroid Build Coastguard Worker                             bool isRowMajor,
413*8975f5c5SAndroid Build Coastguard Worker                             const std::string &name,
414*8975f5c5SAndroid Build Coastguard Worker                             const std::string &mappedName,
415*8975f5c5SAndroid Build Coastguard Worker                             const std::vector<unsigned int> &arraySizes) override
416*8975f5c5SAndroid Build Coastguard Worker     {
417*8975f5c5SAndroid Build Coastguard Worker         bool isSampler                        = IsSamplerType(variable.type);
418*8975f5c5SAndroid Build Coastguard Worker         bool isImage                          = IsImageType(variable.type);
419*8975f5c5SAndroid Build Coastguard Worker         bool isAtomicCounter                  = IsAtomicCounterType(variable.type);
420*8975f5c5SAndroid Build Coastguard Worker         bool isFragmentInOut                  = variable.isFragmentInOut;
421*8975f5c5SAndroid Build Coastguard Worker         std::vector<UsedUniform> *uniformList = mUniforms;
422*8975f5c5SAndroid Build Coastguard Worker         if (isSampler)
423*8975f5c5SAndroid Build Coastguard Worker         {
424*8975f5c5SAndroid Build Coastguard Worker             uniformList = mSamplerUniforms;
425*8975f5c5SAndroid Build Coastguard Worker         }
426*8975f5c5SAndroid Build Coastguard Worker         else if (isImage)
427*8975f5c5SAndroid Build Coastguard Worker         {
428*8975f5c5SAndroid Build Coastguard Worker             uniformList = mImageUniforms;
429*8975f5c5SAndroid Build Coastguard Worker         }
430*8975f5c5SAndroid Build Coastguard Worker         else if (isAtomicCounter)
431*8975f5c5SAndroid Build Coastguard Worker         {
432*8975f5c5SAndroid Build Coastguard Worker             uniformList = mAtomicCounterUniforms;
433*8975f5c5SAndroid Build Coastguard Worker         }
434*8975f5c5SAndroid Build Coastguard Worker         else if (isFragmentInOut)
435*8975f5c5SAndroid Build Coastguard Worker         {
436*8975f5c5SAndroid Build Coastguard Worker             uniformList = mInputAttachmentUniforms;
437*8975f5c5SAndroid Build Coastguard Worker         }
438*8975f5c5SAndroid Build Coastguard Worker 
439*8975f5c5SAndroid Build Coastguard Worker         std::string fullNameWithArrayIndex(name);
440*8975f5c5SAndroid Build Coastguard Worker         std::string fullMappedNameWithArrayIndex(mappedName);
441*8975f5c5SAndroid Build Coastguard Worker 
442*8975f5c5SAndroid Build Coastguard Worker         if (variable.isArray())
443*8975f5c5SAndroid Build Coastguard Worker         {
444*8975f5c5SAndroid Build Coastguard Worker             // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
445*8975f5c5SAndroid Build Coastguard Worker             // Resources and including [0] at the end of array variable names.
446*8975f5c5SAndroid Build Coastguard Worker             fullNameWithArrayIndex += "[0]";
447*8975f5c5SAndroid Build Coastguard Worker             fullMappedNameWithArrayIndex += "[0]";
448*8975f5c5SAndroid Build Coastguard Worker         }
449*8975f5c5SAndroid Build Coastguard Worker 
450*8975f5c5SAndroid Build Coastguard Worker         UsedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
451*8975f5c5SAndroid Build Coastguard Worker         if (existingUniform)
452*8975f5c5SAndroid Build Coastguard Worker         {
453*8975f5c5SAndroid Build Coastguard Worker             if (getBinding() != -1)
454*8975f5c5SAndroid Build Coastguard Worker             {
455*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->binding = getBinding();
456*8975f5c5SAndroid Build Coastguard Worker             }
457*8975f5c5SAndroid Build Coastguard Worker             if (getOffset() != -1)
458*8975f5c5SAndroid Build Coastguard Worker             {
459*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->offset = getOffset();
460*8975f5c5SAndroid Build Coastguard Worker             }
461*8975f5c5SAndroid Build Coastguard Worker             if (mLocation != -1)
462*8975f5c5SAndroid Build Coastguard Worker             {
463*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->location = mLocation;
464*8975f5c5SAndroid Build Coastguard Worker             }
465*8975f5c5SAndroid Build Coastguard Worker             if (mMarkActive)
466*8975f5c5SAndroid Build Coastguard Worker             {
467*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->active = true;
468*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->setActive(mShaderType, true, variable.id);
469*8975f5c5SAndroid Build Coastguard Worker             }
470*8975f5c5SAndroid Build Coastguard Worker             if (mMarkStaticUse)
471*8975f5c5SAndroid Build Coastguard Worker             {
472*8975f5c5SAndroid Build Coastguard Worker                 existingUniform->staticUse = true;
473*8975f5c5SAndroid Build Coastguard Worker             }
474*8975f5c5SAndroid Build Coastguard Worker         }
475*8975f5c5SAndroid Build Coastguard Worker         else
476*8975f5c5SAndroid Build Coastguard Worker         {
477*8975f5c5SAndroid Build Coastguard Worker             UsedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
478*8975f5c5SAndroid Build Coastguard Worker                                       variable.arraySizes, getBinding(), getOffset(), mLocation, -1,
479*8975f5c5SAndroid Build Coastguard Worker                                       sh::kDefaultBlockMemberInfo);
480*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.mappedName          = fullMappedNameWithArrayIndex;
481*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.active              = mMarkActive;
482*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.staticUse           = mMarkStaticUse;
483*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.outerArraySizes     = arraySizes;
484*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
485*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.id                  = variable.id;
486*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.imageUnitFormat     = variable.imageUnitFormat;
487*8975f5c5SAndroid Build Coastguard Worker             linkedUniform.isFragmentInOut     = variable.isFragmentInOut;
488*8975f5c5SAndroid Build Coastguard Worker             if (variable.hasParentArrayIndex())
489*8975f5c5SAndroid Build Coastguard Worker             {
490*8975f5c5SAndroid Build Coastguard Worker                 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
491*8975f5c5SAndroid Build Coastguard Worker             }
492*8975f5c5SAndroid Build Coastguard Worker 
493*8975f5c5SAndroid Build Coastguard Worker             std::vector<unsigned int> arrayDims = arraySizes;
494*8975f5c5SAndroid Build Coastguard Worker             ASSERT(variable.arraySizes.size() == 1 || variable.arraySizes.size() == 0);
495*8975f5c5SAndroid Build Coastguard Worker             arrayDims.push_back(variable.arraySizes.empty() ? 1 : variable.arraySizes[0]);
496*8975f5c5SAndroid Build Coastguard Worker 
497*8975f5c5SAndroid Build Coastguard Worker             size_t numDimensions = arraySizes.size();
498*8975f5c5SAndroid Build Coastguard Worker             uint32_t arrayStride = 1;
499*8975f5c5SAndroid Build Coastguard Worker             for (size_t dimension = numDimensions; dimension > 0;)
500*8975f5c5SAndroid Build Coastguard Worker             {
501*8975f5c5SAndroid Build Coastguard Worker                 --dimension;
502*8975f5c5SAndroid Build Coastguard Worker                 arrayStride *= arrayDims[dimension + 1];
503*8975f5c5SAndroid Build Coastguard Worker                 linkedUniform.outerArrayOffset += arrayStride * mArrayElementStack[dimension];
504*8975f5c5SAndroid Build Coastguard Worker             }
505*8975f5c5SAndroid Build Coastguard Worker 
506*8975f5c5SAndroid Build Coastguard Worker             if (mMarkActive)
507*8975f5c5SAndroid Build Coastguard Worker             {
508*8975f5c5SAndroid Build Coastguard Worker                 linkedUniform.setActive(mShaderType, true, variable.id);
509*8975f5c5SAndroid Build Coastguard Worker             }
510*8975f5c5SAndroid Build Coastguard Worker             else
511*8975f5c5SAndroid Build Coastguard Worker             {
512*8975f5c5SAndroid Build Coastguard Worker                 mUnusedUniforms->emplace_back(
513*8975f5c5SAndroid Build Coastguard Worker                     linkedUniform.name, linkedUniform.isSampler(), linkedUniform.isImage(),
514*8975f5c5SAndroid Build Coastguard Worker                     linkedUniform.isAtomicCounter(), linkedUniform.isFragmentInOut);
515*8975f5c5SAndroid Build Coastguard Worker             }
516*8975f5c5SAndroid Build Coastguard Worker 
517*8975f5c5SAndroid Build Coastguard Worker             uniformList->push_back(linkedUniform);
518*8975f5c5SAndroid Build Coastguard Worker         }
519*8975f5c5SAndroid Build Coastguard Worker 
520*8975f5c5SAndroid Build Coastguard Worker         unsigned int elementCount = variable.getBasicTypeElementCount();
521*8975f5c5SAndroid Build Coastguard Worker 
522*8975f5c5SAndroid Build Coastguard Worker         // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
523*8975f5c5SAndroid Build Coastguard Worker         // Likewise, don't count "real" uniforms towards opaque count.
524*8975f5c5SAndroid Build Coastguard Worker 
525*8975f5c5SAndroid Build Coastguard Worker         if (!IsOpaqueType(variable.type) && !isFragmentInOut)
526*8975f5c5SAndroid Build Coastguard Worker         {
527*8975f5c5SAndroid Build Coastguard Worker             mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
528*8975f5c5SAndroid Build Coastguard Worker         }
529*8975f5c5SAndroid Build Coastguard Worker 
530*8975f5c5SAndroid Build Coastguard Worker         mUniformCount.samplerCount += (isSampler ? elementCount : 0);
531*8975f5c5SAndroid Build Coastguard Worker         mUniformCount.imageCount += (isImage ? elementCount : 0);
532*8975f5c5SAndroid Build Coastguard Worker         mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
533*8975f5c5SAndroid Build Coastguard Worker         mUniformCount.fragmentInOutCount += (isFragmentInOut ? elementCount : 0);
534*8975f5c5SAndroid Build Coastguard Worker 
535*8975f5c5SAndroid Build Coastguard Worker         if (mLocation != -1)
536*8975f5c5SAndroid Build Coastguard Worker         {
537*8975f5c5SAndroid Build Coastguard Worker             mLocation += elementCount;
538*8975f5c5SAndroid Build Coastguard Worker         }
539*8975f5c5SAndroid Build Coastguard Worker     }
540*8975f5c5SAndroid Build Coastguard Worker 
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)541*8975f5c5SAndroid Build Coastguard Worker     void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
542*8975f5c5SAndroid Build Coastguard Worker     {
543*8975f5c5SAndroid Build Coastguard Worker         mStructStackSize++;
544*8975f5c5SAndroid Build Coastguard Worker         sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
545*8975f5c5SAndroid Build Coastguard Worker     }
546*8975f5c5SAndroid Build Coastguard Worker 
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)547*8975f5c5SAndroid Build Coastguard Worker     void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
548*8975f5c5SAndroid Build Coastguard Worker     {
549*8975f5c5SAndroid Build Coastguard Worker         mStructStackSize--;
550*8975f5c5SAndroid Build Coastguard Worker         sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
551*8975f5c5SAndroid Build Coastguard Worker     }
552*8975f5c5SAndroid Build Coastguard Worker 
enterArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)553*8975f5c5SAndroid Build Coastguard Worker     void enterArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
554*8975f5c5SAndroid Build Coastguard Worker     {
555*8975f5c5SAndroid Build Coastguard Worker         mArrayElementStack.push_back(arrayElement);
556*8975f5c5SAndroid Build Coastguard Worker         sh::VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
557*8975f5c5SAndroid Build Coastguard Worker     }
558*8975f5c5SAndroid Build Coastguard Worker 
exitArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)559*8975f5c5SAndroid Build Coastguard Worker     void exitArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
560*8975f5c5SAndroid Build Coastguard Worker     {
561*8975f5c5SAndroid Build Coastguard Worker         mArrayElementStack.pop_back();
562*8975f5c5SAndroid Build Coastguard Worker         sh::VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
563*8975f5c5SAndroid Build Coastguard Worker     }
564*8975f5c5SAndroid Build Coastguard Worker 
getCounts() const565*8975f5c5SAndroid Build Coastguard Worker     ShaderUniformCount getCounts() const { return mUniformCount; }
566*8975f5c5SAndroid Build Coastguard Worker 
567*8975f5c5SAndroid Build Coastguard Worker   private:
getBinding() const568*8975f5c5SAndroid Build Coastguard Worker     int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const569*8975f5c5SAndroid Build Coastguard Worker     int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker     ShaderType mShaderType;
572*8975f5c5SAndroid Build Coastguard Worker 
573*8975f5c5SAndroid Build Coastguard Worker     // Active and StaticUse are given separately because they are tracked at struct granularity.
574*8975f5c5SAndroid Build Coastguard Worker     bool mMarkActive;
575*8975f5c5SAndroid Build Coastguard Worker     bool mMarkStaticUse;
576*8975f5c5SAndroid Build Coastguard Worker     int mBinding;
577*8975f5c5SAndroid Build Coastguard Worker     int mOffset;
578*8975f5c5SAndroid Build Coastguard Worker     int mLocation;
579*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> *mUniforms;
580*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> *mSamplerUniforms;
581*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> *mImageUniforms;
582*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> *mAtomicCounterUniforms;
583*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> *mInputAttachmentUniforms;
584*8975f5c5SAndroid Build Coastguard Worker     std::vector<UnusedUniform> *mUnusedUniforms;
585*8975f5c5SAndroid Build Coastguard Worker     std::vector<unsigned int> mArrayElementStack;
586*8975f5c5SAndroid Build Coastguard Worker     ShaderUniformCount mUniformCount;
587*8975f5c5SAndroid Build Coastguard Worker     unsigned int mStructStackSize = 0;
588*8975f5c5SAndroid Build Coastguard Worker };
589*8975f5c5SAndroid Build Coastguard Worker 
590*8975f5c5SAndroid Build Coastguard Worker class InterfaceBlockInfo final : angle::NonCopyable
591*8975f5c5SAndroid Build Coastguard Worker {
592*8975f5c5SAndroid Build Coastguard Worker   public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)593*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
594*8975f5c5SAndroid Build Coastguard Worker         : mCustomEncoderFactory(customEncoderFactory)
595*8975f5c5SAndroid Build Coastguard Worker     {}
596*8975f5c5SAndroid Build Coastguard Worker 
597*8975f5c5SAndroid Build Coastguard Worker     void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
598*8975f5c5SAndroid Build Coastguard Worker 
599*8975f5c5SAndroid Build Coastguard Worker     bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
600*8975f5c5SAndroid Build Coastguard Worker     bool getBlockMemberInfo(const std::string &name,
601*8975f5c5SAndroid Build Coastguard Worker                             const std::string &mappedName,
602*8975f5c5SAndroid Build Coastguard Worker                             sh::BlockMemberInfo *infoOut);
603*8975f5c5SAndroid Build Coastguard Worker 
604*8975f5c5SAndroid Build Coastguard Worker   private:
605*8975f5c5SAndroid Build Coastguard Worker     size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
606*8975f5c5SAndroid Build Coastguard Worker 
607*8975f5c5SAndroid Build Coastguard Worker     std::map<std::string, size_t> mBlockSizes;
608*8975f5c5SAndroid Build Coastguard Worker     sh::BlockLayoutMap mBlockLayout;
609*8975f5c5SAndroid Build Coastguard Worker     // Based on the interface block layout, the std140 or std430 encoders are used.  On some
610*8975f5c5SAndroid Build Coastguard Worker     // platforms (currently only D3D), there could be another non-standard encoder used.
611*8975f5c5SAndroid Build Coastguard Worker     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
612*8975f5c5SAndroid Build Coastguard Worker };
613*8975f5c5SAndroid Build Coastguard Worker 
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)614*8975f5c5SAndroid Build Coastguard Worker void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
615*8975f5c5SAndroid Build Coastguard Worker {
616*8975f5c5SAndroid Build Coastguard Worker     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
617*8975f5c5SAndroid Build Coastguard Worker     {
618*8975f5c5SAndroid Build Coastguard Worker         if (!IsActiveInterfaceBlock(interfaceBlock))
619*8975f5c5SAndroid Build Coastguard Worker             continue;
620*8975f5c5SAndroid Build Coastguard Worker 
621*8975f5c5SAndroid Build Coastguard Worker         if (mBlockSizes.count(interfaceBlock.name) > 0)
622*8975f5c5SAndroid Build Coastguard Worker             continue;
623*8975f5c5SAndroid Build Coastguard Worker 
624*8975f5c5SAndroid Build Coastguard Worker         size_t dataSize                  = getBlockInfo(interfaceBlock);
625*8975f5c5SAndroid Build Coastguard Worker         mBlockSizes[interfaceBlock.name] = dataSize;
626*8975f5c5SAndroid Build Coastguard Worker     }
627*8975f5c5SAndroid Build Coastguard Worker }
628*8975f5c5SAndroid Build Coastguard Worker 
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)629*8975f5c5SAndroid Build Coastguard Worker size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
630*8975f5c5SAndroid Build Coastguard Worker {
631*8975f5c5SAndroid Build Coastguard Worker     ASSERT(IsActiveInterfaceBlock(interfaceBlock));
632*8975f5c5SAndroid Build Coastguard Worker 
633*8975f5c5SAndroid Build Coastguard Worker     // define member uniforms
634*8975f5c5SAndroid Build Coastguard Worker     sh::Std140BlockEncoder std140Encoder;
635*8975f5c5SAndroid Build Coastguard Worker     sh::Std430BlockEncoder std430Encoder;
636*8975f5c5SAndroid Build Coastguard Worker     sh::BlockLayoutEncoder *customEncoder = nullptr;
637*8975f5c5SAndroid Build Coastguard Worker     sh::BlockLayoutEncoder *encoder       = nullptr;
638*8975f5c5SAndroid Build Coastguard Worker 
639*8975f5c5SAndroid Build Coastguard Worker     if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
640*8975f5c5SAndroid Build Coastguard Worker     {
641*8975f5c5SAndroid Build Coastguard Worker         encoder = &std140Encoder;
642*8975f5c5SAndroid Build Coastguard Worker     }
643*8975f5c5SAndroid Build Coastguard Worker     else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
644*8975f5c5SAndroid Build Coastguard Worker     {
645*8975f5c5SAndroid Build Coastguard Worker         encoder = &std430Encoder;
646*8975f5c5SAndroid Build Coastguard Worker     }
647*8975f5c5SAndroid Build Coastguard Worker     else if (mCustomEncoderFactory)
648*8975f5c5SAndroid Build Coastguard Worker     {
649*8975f5c5SAndroid Build Coastguard Worker         encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
650*8975f5c5SAndroid Build Coastguard Worker     }
651*8975f5c5SAndroid Build Coastguard Worker     else
652*8975f5c5SAndroid Build Coastguard Worker     {
653*8975f5c5SAndroid Build Coastguard Worker         UNREACHABLE();
654*8975f5c5SAndroid Build Coastguard Worker         return 0;
655*8975f5c5SAndroid Build Coastguard Worker     }
656*8975f5c5SAndroid Build Coastguard Worker 
657*8975f5c5SAndroid Build Coastguard Worker     sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
658*8975f5c5SAndroid Build Coastguard Worker                               &mBlockLayout);
659*8975f5c5SAndroid Build Coastguard Worker 
660*8975f5c5SAndroid Build Coastguard Worker     size_t offset = encoder->getCurrentOffset();
661*8975f5c5SAndroid Build Coastguard Worker 
662*8975f5c5SAndroid Build Coastguard Worker     SafeDelete(customEncoder);
663*8975f5c5SAndroid Build Coastguard Worker 
664*8975f5c5SAndroid Build Coastguard Worker     return offset;
665*8975f5c5SAndroid Build Coastguard Worker }
666*8975f5c5SAndroid Build Coastguard Worker 
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)667*8975f5c5SAndroid Build Coastguard Worker bool InterfaceBlockInfo::getBlockSize(const std::string &name,
668*8975f5c5SAndroid Build Coastguard Worker                                       const std::string &mappedName,
669*8975f5c5SAndroid Build Coastguard Worker                                       size_t *sizeOut)
670*8975f5c5SAndroid Build Coastguard Worker {
671*8975f5c5SAndroid Build Coastguard Worker     size_t nameLengthWithoutArrayIndex;
672*8975f5c5SAndroid Build Coastguard Worker     ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
673*8975f5c5SAndroid Build Coastguard Worker     std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
674*8975f5c5SAndroid Build Coastguard Worker     auto sizeIter        = mBlockSizes.find(baseName);
675*8975f5c5SAndroid Build Coastguard Worker     if (sizeIter == mBlockSizes.end())
676*8975f5c5SAndroid Build Coastguard Worker     {
677*8975f5c5SAndroid Build Coastguard Worker         *sizeOut = 0;
678*8975f5c5SAndroid Build Coastguard Worker         return false;
679*8975f5c5SAndroid Build Coastguard Worker     }
680*8975f5c5SAndroid Build Coastguard Worker 
681*8975f5c5SAndroid Build Coastguard Worker     *sizeOut = sizeIter->second;
682*8975f5c5SAndroid Build Coastguard Worker     return true;
683*8975f5c5SAndroid Build Coastguard Worker }
684*8975f5c5SAndroid Build Coastguard Worker 
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)685*8975f5c5SAndroid Build Coastguard Worker bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
686*8975f5c5SAndroid Build Coastguard Worker                                             const std::string &mappedName,
687*8975f5c5SAndroid Build Coastguard Worker                                             sh::BlockMemberInfo *infoOut)
688*8975f5c5SAndroid Build Coastguard Worker {
689*8975f5c5SAndroid Build Coastguard Worker     auto infoIter = mBlockLayout.find(name);
690*8975f5c5SAndroid Build Coastguard Worker     if (infoIter == mBlockLayout.end())
691*8975f5c5SAndroid Build Coastguard Worker     {
692*8975f5c5SAndroid Build Coastguard Worker         *infoOut = sh::kDefaultBlockMemberInfo;
693*8975f5c5SAndroid Build Coastguard Worker         return false;
694*8975f5c5SAndroid Build Coastguard Worker     }
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker     *infoOut = infoIter->second;
697*8975f5c5SAndroid Build Coastguard Worker     return true;
698*8975f5c5SAndroid Build Coastguard Worker }
699*8975f5c5SAndroid Build Coastguard Worker 
GetFilteredVaryings(const std::vector<sh::ShaderVariable> & varyings,std::vector<const sh::ShaderVariable * > * filteredVaryingsOut)700*8975f5c5SAndroid Build Coastguard Worker void GetFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
701*8975f5c5SAndroid Build Coastguard Worker                          std::vector<const sh::ShaderVariable *> *filteredVaryingsOut)
702*8975f5c5SAndroid Build Coastguard Worker {
703*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &varying : varyings)
704*8975f5c5SAndroid Build Coastguard Worker     {
705*8975f5c5SAndroid Build Coastguard Worker         // Built-in varyings obey special rules
706*8975f5c5SAndroid Build Coastguard Worker         if (varying.isBuiltIn())
707*8975f5c5SAndroid Build Coastguard Worker         {
708*8975f5c5SAndroid Build Coastguard Worker             continue;
709*8975f5c5SAndroid Build Coastguard Worker         }
710*8975f5c5SAndroid Build Coastguard Worker 
711*8975f5c5SAndroid Build Coastguard Worker         filteredVaryingsOut->push_back(&varying);
712*8975f5c5SAndroid Build Coastguard Worker     }
713*8975f5c5SAndroid Build Coastguard Worker }
714*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateVaryings(const sh::ShaderVariable & outputVarying,const sh::ShaderVariable & inputVarying,int shaderVersion,ShaderType frontShaderType,ShaderType backShaderType,bool isSeparable,std::string * mismatchedStructFieldName)715*8975f5c5SAndroid Build Coastguard Worker LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
716*8975f5c5SAndroid Build Coastguard Worker                                        const sh::ShaderVariable &inputVarying,
717*8975f5c5SAndroid Build Coastguard Worker                                        int shaderVersion,
718*8975f5c5SAndroid Build Coastguard Worker                                        ShaderType frontShaderType,
719*8975f5c5SAndroid Build Coastguard Worker                                        ShaderType backShaderType,
720*8975f5c5SAndroid Build Coastguard Worker                                        bool isSeparable,
721*8975f5c5SAndroid Build Coastguard Worker                                        std::string *mismatchedStructFieldName)
722*8975f5c5SAndroid Build Coastguard Worker {
723*8975f5c5SAndroid Build Coastguard Worker     // [ES 3.2 spec] 7.4.1 Shader Interface Matching:
724*8975f5c5SAndroid Build Coastguard Worker     // Tessellation control shader per-vertex output variables and blocks and tessellation control,
725*8975f5c5SAndroid Build Coastguard Worker     // tessellation evaluation, and geometry shader per-vertex input variables and blocks are
726*8975f5c5SAndroid Build Coastguard Worker     // required to be declared as arrays, with each element representing input or output values for
727*8975f5c5SAndroid Build Coastguard Worker     // a single vertex of a multi-vertex primitive. For the purposes of interface matching, such
728*8975f5c5SAndroid Build Coastguard Worker     // variables and blocks are treated as though they were not declared as arrays.
729*8975f5c5SAndroid Build Coastguard Worker     bool treatOutputAsNonArray =
730*8975f5c5SAndroid Build Coastguard Worker         (frontShaderType == ShaderType::TessControl && !outputVarying.isPatch);
731*8975f5c5SAndroid Build Coastguard Worker     bool treatInputAsNonArray =
732*8975f5c5SAndroid Build Coastguard Worker         ((backShaderType == ShaderType::TessControl ||
733*8975f5c5SAndroid Build Coastguard Worker           backShaderType == ShaderType::TessEvaluation || backShaderType == ShaderType::Geometry) &&
734*8975f5c5SAndroid Build Coastguard Worker          !inputVarying.isPatch);
735*8975f5c5SAndroid Build Coastguard Worker 
736*8975f5c5SAndroid Build Coastguard Worker     // Skip the validation on the array sizes between a vertex output varying and a geometry input
737*8975f5c5SAndroid Build Coastguard Worker     // varying as it has been done before.
738*8975f5c5SAndroid Build Coastguard Worker     bool validatePrecision      = isSeparable && (shaderVersion > 100);
739*8975f5c5SAndroid Build Coastguard Worker     LinkMismatchError linkError = LinkValidateProgramVariables(
740*8975f5c5SAndroid Build Coastguard Worker         outputVarying, inputVarying, validatePrecision, treatOutputAsNonArray, treatInputAsNonArray,
741*8975f5c5SAndroid Build Coastguard Worker         mismatchedStructFieldName);
742*8975f5c5SAndroid Build Coastguard Worker     if (linkError != LinkMismatchError::NO_MISMATCH)
743*8975f5c5SAndroid Build Coastguard Worker     {
744*8975f5c5SAndroid Build Coastguard Worker         return linkError;
745*8975f5c5SAndroid Build Coastguard Worker     }
746*8975f5c5SAndroid Build Coastguard Worker 
747*8975f5c5SAndroid Build Coastguard Worker     // Explicit locations must match if the names match.
748*8975f5c5SAndroid Build Coastguard Worker     if (outputVarying.isSameNameAtLinkTime(inputVarying) &&
749*8975f5c5SAndroid Build Coastguard Worker         outputVarying.location != inputVarying.location)
750*8975f5c5SAndroid Build Coastguard Worker     {
751*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::LOCATION_MISMATCH;
752*8975f5c5SAndroid Build Coastguard Worker     }
753*8975f5c5SAndroid Build Coastguard Worker 
754*8975f5c5SAndroid Build Coastguard Worker     if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
755*8975f5c5SAndroid Build Coastguard Worker     {
756*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
757*8975f5c5SAndroid Build Coastguard Worker     }
758*8975f5c5SAndroid Build Coastguard Worker 
759*8975f5c5SAndroid Build Coastguard Worker     if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
760*8975f5c5SAndroid Build Coastguard Worker     {
761*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::INVARIANCE_MISMATCH;
762*8975f5c5SAndroid Build Coastguard Worker     }
763*8975f5c5SAndroid Build Coastguard Worker 
764*8975f5c5SAndroid Build Coastguard Worker     return LinkMismatchError::NO_MISMATCH;
765*8975f5c5SAndroid Build Coastguard Worker }
766*8975f5c5SAndroid Build Coastguard Worker 
DoShaderVariablesMatch(int frontShaderVersion,ShaderType frontShaderType,ShaderType backShaderType,const sh::ShaderVariable & input,const sh::ShaderVariable & output,bool isSeparable,gl::InfoLog & infoLog)767*8975f5c5SAndroid Build Coastguard Worker bool DoShaderVariablesMatch(int frontShaderVersion,
768*8975f5c5SAndroid Build Coastguard Worker                             ShaderType frontShaderType,
769*8975f5c5SAndroid Build Coastguard Worker                             ShaderType backShaderType,
770*8975f5c5SAndroid Build Coastguard Worker                             const sh::ShaderVariable &input,
771*8975f5c5SAndroid Build Coastguard Worker                             const sh::ShaderVariable &output,
772*8975f5c5SAndroid Build Coastguard Worker                             bool isSeparable,
773*8975f5c5SAndroid Build Coastguard Worker                             gl::InfoLog &infoLog)
774*8975f5c5SAndroid Build Coastguard Worker {
775*8975f5c5SAndroid Build Coastguard Worker     bool namesMatch     = input.isSameNameAtLinkTime(output);
776*8975f5c5SAndroid Build Coastguard Worker     bool locationsMatch = input.location != -1 && input.location == output.location;
777*8975f5c5SAndroid Build Coastguard Worker 
778*8975f5c5SAndroid Build Coastguard Worker     // An output block is considered to match an input block in the subsequent
779*8975f5c5SAndroid Build Coastguard Worker     // shader if the two blocks have the same block name, and the members of the
780*8975f5c5SAndroid Build Coastguard Worker     // block match exactly in name, type, qualification, and declaration order.
781*8975f5c5SAndroid Build Coastguard Worker     //
782*8975f5c5SAndroid Build Coastguard Worker     // - For the purposes of shader interface matching, the gl_PointSize
783*8975f5c5SAndroid Build Coastguard Worker     //   member of the intrinsically declared gl_PerVertex shader interface
784*8975f5c5SAndroid Build Coastguard Worker     //   block is ignored.
785*8975f5c5SAndroid Build Coastguard Worker     // - Output blocks that do not match in name, but have a location and match
786*8975f5c5SAndroid Build Coastguard Worker     //   in every other way listed above may be considered to match by some
787*8975f5c5SAndroid Build Coastguard Worker     //   implementations, but not all - so this behaviour should not be relied
788*8975f5c5SAndroid Build Coastguard Worker     //   upon.
789*8975f5c5SAndroid Build Coastguard Worker 
790*8975f5c5SAndroid Build Coastguard Worker     // An output variable is considered to match an input variable in the subsequent
791*8975f5c5SAndroid Build Coastguard Worker     // shader if:
792*8975f5c5SAndroid Build Coastguard Worker     //
793*8975f5c5SAndroid Build Coastguard Worker     // - the two variables match in name, type, and qualification; or
794*8975f5c5SAndroid Build Coastguard Worker     // - the two variables are declared with the same location qualifier and
795*8975f5c5SAndroid Build Coastguard Worker     //   match in type and qualification.
796*8975f5c5SAndroid Build Coastguard Worker 
797*8975f5c5SAndroid Build Coastguard Worker     if (namesMatch || locationsMatch)
798*8975f5c5SAndroid Build Coastguard Worker     {
799*8975f5c5SAndroid Build Coastguard Worker         std::string mismatchedStructFieldName;
800*8975f5c5SAndroid Build Coastguard Worker         LinkMismatchError linkError =
801*8975f5c5SAndroid Build Coastguard Worker             LinkValidateVaryings(output, input, frontShaderVersion, frontShaderType, backShaderType,
802*8975f5c5SAndroid Build Coastguard Worker                                  isSeparable, &mismatchedStructFieldName);
803*8975f5c5SAndroid Build Coastguard Worker         if (linkError != LinkMismatchError::NO_MISMATCH)
804*8975f5c5SAndroid Build Coastguard Worker         {
805*8975f5c5SAndroid Build Coastguard Worker             LogLinkMismatch(infoLog, input.name, "varying", linkError, mismatchedStructFieldName,
806*8975f5c5SAndroid Build Coastguard Worker                             frontShaderType, backShaderType);
807*8975f5c5SAndroid Build Coastguard Worker             return false;
808*8975f5c5SAndroid Build Coastguard Worker         }
809*8975f5c5SAndroid Build Coastguard Worker 
810*8975f5c5SAndroid Build Coastguard Worker         return true;
811*8975f5c5SAndroid Build Coastguard Worker     }
812*8975f5c5SAndroid Build Coastguard Worker 
813*8975f5c5SAndroid Build Coastguard Worker     return false;
814*8975f5c5SAndroid Build Coastguard Worker }
815*8975f5c5SAndroid Build Coastguard Worker 
GetInterfaceBlockTypeString(sh::BlockType blockType)816*8975f5c5SAndroid Build Coastguard Worker const char *GetInterfaceBlockTypeString(sh::BlockType blockType)
817*8975f5c5SAndroid Build Coastguard Worker {
818*8975f5c5SAndroid Build Coastguard Worker     switch (blockType)
819*8975f5c5SAndroid Build Coastguard Worker     {
820*8975f5c5SAndroid Build Coastguard Worker         case sh::BlockType::kBlockUniform:
821*8975f5c5SAndroid Build Coastguard Worker             return "uniform block";
822*8975f5c5SAndroid Build Coastguard Worker         case sh::BlockType::kBlockBuffer:
823*8975f5c5SAndroid Build Coastguard Worker             return "shader storage block";
824*8975f5c5SAndroid Build Coastguard Worker         default:
825*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
826*8975f5c5SAndroid Build Coastguard Worker             return "";
827*8975f5c5SAndroid Build Coastguard Worker     }
828*8975f5c5SAndroid Build Coastguard Worker }
829*8975f5c5SAndroid Build Coastguard Worker 
GetInterfaceBlockLimitName(ShaderType shaderType,sh::BlockType blockType)830*8975f5c5SAndroid Build Coastguard Worker std::string GetInterfaceBlockLimitName(ShaderType shaderType, sh::BlockType blockType)
831*8975f5c5SAndroid Build Coastguard Worker {
832*8975f5c5SAndroid Build Coastguard Worker     std::ostringstream stream;
833*8975f5c5SAndroid Build Coastguard Worker     stream << "GL_MAX_" << GetShaderTypeString(shaderType) << "_";
834*8975f5c5SAndroid Build Coastguard Worker 
835*8975f5c5SAndroid Build Coastguard Worker     switch (blockType)
836*8975f5c5SAndroid Build Coastguard Worker     {
837*8975f5c5SAndroid Build Coastguard Worker         case sh::BlockType::kBlockUniform:
838*8975f5c5SAndroid Build Coastguard Worker             stream << "UNIFORM_BUFFERS";
839*8975f5c5SAndroid Build Coastguard Worker             break;
840*8975f5c5SAndroid Build Coastguard Worker         case sh::BlockType::kBlockBuffer:
841*8975f5c5SAndroid Build Coastguard Worker             stream << "SHADER_STORAGE_BLOCKS";
842*8975f5c5SAndroid Build Coastguard Worker             break;
843*8975f5c5SAndroid Build Coastguard Worker         default:
844*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
845*8975f5c5SAndroid Build Coastguard Worker             return "";
846*8975f5c5SAndroid Build Coastguard Worker     }
847*8975f5c5SAndroid Build Coastguard Worker 
848*8975f5c5SAndroid Build Coastguard Worker     if (shaderType == ShaderType::Geometry)
849*8975f5c5SAndroid Build Coastguard Worker     {
850*8975f5c5SAndroid Build Coastguard Worker         stream << "_EXT";
851*8975f5c5SAndroid Build Coastguard Worker     }
852*8975f5c5SAndroid Build Coastguard Worker 
853*8975f5c5SAndroid Build Coastguard Worker     return stream.str();
854*8975f5c5SAndroid Build Coastguard Worker }
855*8975f5c5SAndroid Build Coastguard Worker 
LogInterfaceBlocksExceedLimit(InfoLog & infoLog,ShaderType shaderType,sh::BlockType blockType,GLuint limit)856*8975f5c5SAndroid Build Coastguard Worker void LogInterfaceBlocksExceedLimit(InfoLog &infoLog,
857*8975f5c5SAndroid Build Coastguard Worker                                    ShaderType shaderType,
858*8975f5c5SAndroid Build Coastguard Worker                                    sh::BlockType blockType,
859*8975f5c5SAndroid Build Coastguard Worker                                    GLuint limit)
860*8975f5c5SAndroid Build Coastguard Worker {
861*8975f5c5SAndroid Build Coastguard Worker     infoLog << GetShaderTypeString(shaderType) << " shader "
862*8975f5c5SAndroid Build Coastguard Worker             << GetInterfaceBlockTypeString(blockType) << " count exceeds "
863*8975f5c5SAndroid Build Coastguard Worker             << GetInterfaceBlockLimitName(shaderType, blockType) << " (" << limit << ")";
864*8975f5c5SAndroid Build Coastguard Worker }
865*8975f5c5SAndroid Build Coastguard Worker 
ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,sh::BlockType blockType,GLuint * combinedInterfaceBlocksCount,InfoLog & infoLog)866*8975f5c5SAndroid Build Coastguard Worker bool ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
867*8975f5c5SAndroid Build Coastguard Worker                                   const std::vector<sh::InterfaceBlock> &interfaceBlocks,
868*8975f5c5SAndroid Build Coastguard Worker                                   ShaderType shaderType,
869*8975f5c5SAndroid Build Coastguard Worker                                   sh::BlockType blockType,
870*8975f5c5SAndroid Build Coastguard Worker                                   GLuint *combinedInterfaceBlocksCount,
871*8975f5c5SAndroid Build Coastguard Worker                                   InfoLog &infoLog)
872*8975f5c5SAndroid Build Coastguard Worker {
873*8975f5c5SAndroid Build Coastguard Worker     GLuint blockCount = 0;
874*8975f5c5SAndroid Build Coastguard Worker     for (const sh::InterfaceBlock &block : interfaceBlocks)
875*8975f5c5SAndroid Build Coastguard Worker     {
876*8975f5c5SAndroid Build Coastguard Worker         if (IsActiveInterfaceBlock(block))
877*8975f5c5SAndroid Build Coastguard Worker         {
878*8975f5c5SAndroid Build Coastguard Worker             blockCount += std::max(block.arraySize, 1u);
879*8975f5c5SAndroid Build Coastguard Worker             if (blockCount > maxInterfaceBlocks)
880*8975f5c5SAndroid Build Coastguard Worker             {
881*8975f5c5SAndroid Build Coastguard Worker                 LogInterfaceBlocksExceedLimit(infoLog, shaderType, blockType, maxInterfaceBlocks);
882*8975f5c5SAndroid Build Coastguard Worker                 return false;
883*8975f5c5SAndroid Build Coastguard Worker             }
884*8975f5c5SAndroid Build Coastguard Worker         }
885*8975f5c5SAndroid Build Coastguard Worker     }
886*8975f5c5SAndroid Build Coastguard Worker 
887*8975f5c5SAndroid Build Coastguard Worker     // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
888*8975f5c5SAndroid Build Coastguard Worker     // If a uniform block is used by multiple shader stages, each such use counts separately
889*8975f5c5SAndroid Build Coastguard Worker     // against this combined limit.
890*8975f5c5SAndroid Build Coastguard Worker     // [OpenGL ES 3.1] Chapter 7.8 Page 111:
891*8975f5c5SAndroid Build Coastguard Worker     // If a shader storage block in a program is referenced by multiple shaders, each such
892*8975f5c5SAndroid Build Coastguard Worker     // reference counts separately against this combined limit.
893*8975f5c5SAndroid Build Coastguard Worker     if (combinedInterfaceBlocksCount)
894*8975f5c5SAndroid Build Coastguard Worker     {
895*8975f5c5SAndroid Build Coastguard Worker         *combinedInterfaceBlocksCount += blockCount;
896*8975f5c5SAndroid Build Coastguard Worker     }
897*8975f5c5SAndroid Build Coastguard Worker 
898*8975f5c5SAndroid Build Coastguard Worker     return true;
899*8975f5c5SAndroid Build Coastguard Worker }
900*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
901*8975f5c5SAndroid Build Coastguard Worker 
902*8975f5c5SAndroid Build Coastguard Worker // UsedUniform implementation
UsedUniform()903*8975f5c5SAndroid Build Coastguard Worker UsedUniform::UsedUniform() {}
904*8975f5c5SAndroid Build Coastguard Worker 
UsedUniform(GLenum typeIn,GLenum precisionIn,const std::string & nameIn,const std::vector<unsigned int> & arraySizesIn,const int bindingIn,const int offsetIn,const int locationIn,const int bufferIndexIn,const sh::BlockMemberInfo & blockInfoIn)905*8975f5c5SAndroid Build Coastguard Worker UsedUniform::UsedUniform(GLenum typeIn,
906*8975f5c5SAndroid Build Coastguard Worker                          GLenum precisionIn,
907*8975f5c5SAndroid Build Coastguard Worker                          const std::string &nameIn,
908*8975f5c5SAndroid Build Coastguard Worker                          const std::vector<unsigned int> &arraySizesIn,
909*8975f5c5SAndroid Build Coastguard Worker                          const int bindingIn,
910*8975f5c5SAndroid Build Coastguard Worker                          const int offsetIn,
911*8975f5c5SAndroid Build Coastguard Worker                          const int locationIn,
912*8975f5c5SAndroid Build Coastguard Worker                          const int bufferIndexIn,
913*8975f5c5SAndroid Build Coastguard Worker                          const sh::BlockMemberInfo &blockInfoIn)
914*8975f5c5SAndroid Build Coastguard Worker     : typeInfo(&GetUniformTypeInfo(typeIn)),
915*8975f5c5SAndroid Build Coastguard Worker       bufferIndex(bufferIndexIn),
916*8975f5c5SAndroid Build Coastguard Worker       blockInfo(blockInfoIn),
917*8975f5c5SAndroid Build Coastguard Worker       outerArrayOffset(0)
918*8975f5c5SAndroid Build Coastguard Worker {
919*8975f5c5SAndroid Build Coastguard Worker     type       = typeIn;
920*8975f5c5SAndroid Build Coastguard Worker     precision  = precisionIn;
921*8975f5c5SAndroid Build Coastguard Worker     name       = nameIn;
922*8975f5c5SAndroid Build Coastguard Worker     arraySizes = arraySizesIn;
923*8975f5c5SAndroid Build Coastguard Worker     binding    = bindingIn;
924*8975f5c5SAndroid Build Coastguard Worker     offset     = offsetIn;
925*8975f5c5SAndroid Build Coastguard Worker     location   = locationIn;
926*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isArrayOfArrays());
927*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isArray() || !isStruct());
928*8975f5c5SAndroid Build Coastguard Worker }
929*8975f5c5SAndroid Build Coastguard Worker 
UsedUniform(const UsedUniform & other)930*8975f5c5SAndroid Build Coastguard Worker UsedUniform::UsedUniform(const UsedUniform &other)
931*8975f5c5SAndroid Build Coastguard Worker {
932*8975f5c5SAndroid Build Coastguard Worker     *this = other;
933*8975f5c5SAndroid Build Coastguard Worker }
934*8975f5c5SAndroid Build Coastguard Worker 
operator =(const UsedUniform & other)935*8975f5c5SAndroid Build Coastguard Worker UsedUniform &UsedUniform::operator=(const UsedUniform &other)
936*8975f5c5SAndroid Build Coastguard Worker {
937*8975f5c5SAndroid Build Coastguard Worker     if (this != &other)
938*8975f5c5SAndroid Build Coastguard Worker     {
939*8975f5c5SAndroid Build Coastguard Worker         sh::ShaderVariable::operator=(other);
940*8975f5c5SAndroid Build Coastguard Worker         activeVariable = other.activeVariable;
941*8975f5c5SAndroid Build Coastguard Worker 
942*8975f5c5SAndroid Build Coastguard Worker         typeInfo         = other.typeInfo;
943*8975f5c5SAndroid Build Coastguard Worker         bufferIndex      = other.bufferIndex;
944*8975f5c5SAndroid Build Coastguard Worker         blockInfo        = other.blockInfo;
945*8975f5c5SAndroid Build Coastguard Worker         outerArraySizes  = other.outerArraySizes;
946*8975f5c5SAndroid Build Coastguard Worker         outerArrayOffset = other.outerArrayOffset;
947*8975f5c5SAndroid Build Coastguard Worker     }
948*8975f5c5SAndroid Build Coastguard Worker     return *this;
949*8975f5c5SAndroid Build Coastguard Worker }
950*8975f5c5SAndroid Build Coastguard Worker 
~UsedUniform()951*8975f5c5SAndroid Build Coastguard Worker UsedUniform::~UsedUniform() {}
952*8975f5c5SAndroid Build Coastguard Worker 
953*8975f5c5SAndroid Build Coastguard Worker // UniformLinker implementation
UniformLinker(const ShaderBitSet & activeShaderStages,const ShaderMap<std::vector<sh::ShaderVariable>> & shaderUniforms)954*8975f5c5SAndroid Build Coastguard Worker UniformLinker::UniformLinker(const ShaderBitSet &activeShaderStages,
955*8975f5c5SAndroid Build Coastguard Worker                              const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms)
956*8975f5c5SAndroid Build Coastguard Worker     : mActiveShaderStages(activeShaderStages), mShaderUniforms(shaderUniforms)
957*8975f5c5SAndroid Build Coastguard Worker {}
958*8975f5c5SAndroid Build Coastguard Worker 
959*8975f5c5SAndroid Build Coastguard Worker UniformLinker::~UniformLinker() = default;
960*8975f5c5SAndroid Build Coastguard Worker 
getResults(std::vector<LinkedUniform> * uniforms,std::vector<std::string> * uniformNames,std::vector<std::string> * uniformMappedNames,std::vector<UnusedUniform> * unusedUniformsOutOrNull,std::vector<VariableLocation> * uniformLocationsOutOrNull)961*8975f5c5SAndroid Build Coastguard Worker void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
962*8975f5c5SAndroid Build Coastguard Worker                                std::vector<std::string> *uniformNames,
963*8975f5c5SAndroid Build Coastguard Worker                                std::vector<std::string> *uniformMappedNames,
964*8975f5c5SAndroid Build Coastguard Worker                                std::vector<UnusedUniform> *unusedUniformsOutOrNull,
965*8975f5c5SAndroid Build Coastguard Worker                                std::vector<VariableLocation> *uniformLocationsOutOrNull)
966*8975f5c5SAndroid Build Coastguard Worker {
967*8975f5c5SAndroid Build Coastguard Worker     uniforms->reserve(mUniforms.size());
968*8975f5c5SAndroid Build Coastguard Worker     uniformNames->reserve(mUniforms.size());
969*8975f5c5SAndroid Build Coastguard Worker     uniformMappedNames->reserve(mUniforms.size());
970*8975f5c5SAndroid Build Coastguard Worker     for (const UsedUniform &usedUniform : mUniforms)
971*8975f5c5SAndroid Build Coastguard Worker     {
972*8975f5c5SAndroid Build Coastguard Worker         uniforms->emplace_back(usedUniform);
973*8975f5c5SAndroid Build Coastguard Worker         uniformNames->emplace_back(usedUniform.name);
974*8975f5c5SAndroid Build Coastguard Worker         uniformMappedNames->emplace_back(usedUniform.mappedName);
975*8975f5c5SAndroid Build Coastguard Worker     }
976*8975f5c5SAndroid Build Coastguard Worker 
977*8975f5c5SAndroid Build Coastguard Worker     if (unusedUniformsOutOrNull)
978*8975f5c5SAndroid Build Coastguard Worker     {
979*8975f5c5SAndroid Build Coastguard Worker         unusedUniformsOutOrNull->swap(mUnusedUniforms);
980*8975f5c5SAndroid Build Coastguard Worker     }
981*8975f5c5SAndroid Build Coastguard Worker 
982*8975f5c5SAndroid Build Coastguard Worker     if (uniformLocationsOutOrNull)
983*8975f5c5SAndroid Build Coastguard Worker     {
984*8975f5c5SAndroid Build Coastguard Worker         uniformLocationsOutOrNull->swap(mUniformLocations);
985*8975f5c5SAndroid Build Coastguard Worker     }
986*8975f5c5SAndroid Build Coastguard Worker }
987*8975f5c5SAndroid Build Coastguard Worker 
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)988*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::link(const Caps &caps,
989*8975f5c5SAndroid Build Coastguard Worker                          InfoLog &infoLog,
990*8975f5c5SAndroid Build Coastguard Worker                          const ProgramAliasedBindings &uniformLocationBindings)
991*8975f5c5SAndroid Build Coastguard Worker {
992*8975f5c5SAndroid Build Coastguard Worker     if (mActiveShaderStages[ShaderType::Vertex] && mActiveShaderStages[ShaderType::Fragment])
993*8975f5c5SAndroid Build Coastguard Worker     {
994*8975f5c5SAndroid Build Coastguard Worker         if (!validateGraphicsUniforms(infoLog))
995*8975f5c5SAndroid Build Coastguard Worker         {
996*8975f5c5SAndroid Build Coastguard Worker             return false;
997*8975f5c5SAndroid Build Coastguard Worker         }
998*8975f5c5SAndroid Build Coastguard Worker     }
999*8975f5c5SAndroid Build Coastguard Worker 
1000*8975f5c5SAndroid Build Coastguard Worker     // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1001*8975f5c5SAndroid Build Coastguard Worker     // Also check the maximum uniform vector and sampler counts.
1002*8975f5c5SAndroid Build Coastguard Worker     if (!flattenUniformsAndCheckCaps(caps, infoLog))
1003*8975f5c5SAndroid Build Coastguard Worker     {
1004*8975f5c5SAndroid Build Coastguard Worker         return false;
1005*8975f5c5SAndroid Build Coastguard Worker     }
1006*8975f5c5SAndroid Build Coastguard Worker 
1007*8975f5c5SAndroid Build Coastguard Worker     if (!checkMaxCombinedAtomicCounters(caps, infoLog))
1008*8975f5c5SAndroid Build Coastguard Worker     {
1009*8975f5c5SAndroid Build Coastguard Worker         return false;
1010*8975f5c5SAndroid Build Coastguard Worker     }
1011*8975f5c5SAndroid Build Coastguard Worker 
1012*8975f5c5SAndroid Build Coastguard Worker     if (!indexUniforms(infoLog, uniformLocationBindings))
1013*8975f5c5SAndroid Build Coastguard Worker     {
1014*8975f5c5SAndroid Build Coastguard Worker         return false;
1015*8975f5c5SAndroid Build Coastguard Worker     }
1016*8975f5c5SAndroid Build Coastguard Worker 
1017*8975f5c5SAndroid Build Coastguard Worker     return true;
1018*8975f5c5SAndroid Build Coastguard Worker }
1019*8975f5c5SAndroid Build Coastguard Worker 
validateGraphicsUniforms(InfoLog & infoLog) const1020*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
1021*8975f5c5SAndroid Build Coastguard Worker {
1022*8975f5c5SAndroid Build Coastguard Worker     // Check that uniforms defined in the graphics shaders are identical
1023*8975f5c5SAndroid Build Coastguard Worker     std::map<std::string, ShaderUniform> linkedUniforms;
1024*8975f5c5SAndroid Build Coastguard Worker 
1025*8975f5c5SAndroid Build Coastguard Worker     for (const ShaderType shaderType : mActiveShaderStages)
1026*8975f5c5SAndroid Build Coastguard Worker     {
1027*8975f5c5SAndroid Build Coastguard Worker         if (shaderType == ShaderType::Vertex)
1028*8975f5c5SAndroid Build Coastguard Worker         {
1029*8975f5c5SAndroid Build Coastguard Worker             for (const sh::ShaderVariable &vertexUniform : mShaderUniforms[ShaderType::Vertex])
1030*8975f5c5SAndroid Build Coastguard Worker             {
1031*8975f5c5SAndroid Build Coastguard Worker                 linkedUniforms[vertexUniform.name] =
1032*8975f5c5SAndroid Build Coastguard Worker                     std::make_pair(ShaderType::Vertex, &vertexUniform);
1033*8975f5c5SAndroid Build Coastguard Worker             }
1034*8975f5c5SAndroid Build Coastguard Worker         }
1035*8975f5c5SAndroid Build Coastguard Worker         else
1036*8975f5c5SAndroid Build Coastguard Worker         {
1037*8975f5c5SAndroid Build Coastguard Worker             bool isLastShader = (shaderType == ShaderType::Fragment);
1038*8975f5c5SAndroid Build Coastguard Worker             if (!validateGraphicsUniformsPerShader(shaderType, !isLastShader, &linkedUniforms,
1039*8975f5c5SAndroid Build Coastguard Worker                                                    infoLog))
1040*8975f5c5SAndroid Build Coastguard Worker             {
1041*8975f5c5SAndroid Build Coastguard Worker                 return false;
1042*8975f5c5SAndroid Build Coastguard Worker             }
1043*8975f5c5SAndroid Build Coastguard Worker         }
1044*8975f5c5SAndroid Build Coastguard Worker     }
1045*8975f5c5SAndroid Build Coastguard Worker 
1046*8975f5c5SAndroid Build Coastguard Worker     return true;
1047*8975f5c5SAndroid Build Coastguard Worker }
1048*8975f5c5SAndroid Build Coastguard Worker 
validateGraphicsUniformsPerShader(ShaderType shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog) const1049*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::validateGraphicsUniformsPerShader(
1050*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderToLink,
1051*8975f5c5SAndroid Build Coastguard Worker     bool extendLinkedUniforms,
1052*8975f5c5SAndroid Build Coastguard Worker     std::map<std::string, ShaderUniform> *linkedUniforms,
1053*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog) const
1054*8975f5c5SAndroid Build Coastguard Worker {
1055*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mActiveShaderStages[shaderToLink] && linkedUniforms);
1056*8975f5c5SAndroid Build Coastguard Worker 
1057*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderToLink])
1058*8975f5c5SAndroid Build Coastguard Worker     {
1059*8975f5c5SAndroid Build Coastguard Worker         const auto &entry = linkedUniforms->find(uniform.name);
1060*8975f5c5SAndroid Build Coastguard Worker         if (entry != linkedUniforms->end())
1061*8975f5c5SAndroid Build Coastguard Worker         {
1062*8975f5c5SAndroid Build Coastguard Worker             const sh::ShaderVariable &linkedUniform = *(entry->second.second);
1063*8975f5c5SAndroid Build Coastguard Worker             std::string mismatchedStructFieldName;
1064*8975f5c5SAndroid Build Coastguard Worker             LinkMismatchError linkError =
1065*8975f5c5SAndroid Build Coastguard Worker                 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
1066*8975f5c5SAndroid Build Coastguard Worker             if (linkError != LinkMismatchError::NO_MISMATCH)
1067*8975f5c5SAndroid Build Coastguard Worker             {
1068*8975f5c5SAndroid Build Coastguard Worker                 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
1069*8975f5c5SAndroid Build Coastguard Worker                                 mismatchedStructFieldName, entry->second.first, shaderToLink);
1070*8975f5c5SAndroid Build Coastguard Worker                 return false;
1071*8975f5c5SAndroid Build Coastguard Worker             }
1072*8975f5c5SAndroid Build Coastguard Worker         }
1073*8975f5c5SAndroid Build Coastguard Worker         else if (extendLinkedUniforms)
1074*8975f5c5SAndroid Build Coastguard Worker         {
1075*8975f5c5SAndroid Build Coastguard Worker             (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink, &uniform);
1076*8975f5c5SAndroid Build Coastguard Worker         }
1077*8975f5c5SAndroid Build Coastguard Worker     }
1078*8975f5c5SAndroid Build Coastguard Worker 
1079*8975f5c5SAndroid Build Coastguard Worker     return true;
1080*8975f5c5SAndroid Build Coastguard Worker }
1081*8975f5c5SAndroid Build Coastguard Worker 
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)1082*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::indexUniforms(InfoLog &infoLog,
1083*8975f5c5SAndroid Build Coastguard Worker                                   const ProgramAliasedBindings &uniformLocationBindings)
1084*8975f5c5SAndroid Build Coastguard Worker {
1085*8975f5c5SAndroid Build Coastguard Worker     // Locations which have been allocated for an unused uniform.
1086*8975f5c5SAndroid Build Coastguard Worker     std::set<GLuint> ignoredLocations;
1087*8975f5c5SAndroid Build Coastguard Worker 
1088*8975f5c5SAndroid Build Coastguard Worker     int maxUniformLocation = -1;
1089*8975f5c5SAndroid Build Coastguard Worker 
1090*8975f5c5SAndroid Build Coastguard Worker     // Gather uniform locations that have been set either using the bindUniformLocationCHROMIUM API
1091*8975f5c5SAndroid Build Coastguard Worker     // or by using a location layout qualifier and check conflicts between them.
1092*8975f5c5SAndroid Build Coastguard Worker     if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
1093*8975f5c5SAndroid Build Coastguard Worker                                                  &ignoredLocations, &maxUniformLocation))
1094*8975f5c5SAndroid Build Coastguard Worker     {
1095*8975f5c5SAndroid Build Coastguard Worker         return false;
1096*8975f5c5SAndroid Build Coastguard Worker     }
1097*8975f5c5SAndroid Build Coastguard Worker 
1098*8975f5c5SAndroid Build Coastguard Worker     // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
1099*8975f5c5SAndroid Build Coastguard Worker     // the line relies on only having statically used uniforms in mUniforms.
1100*8975f5c5SAndroid Build Coastguard Worker     pruneUnusedUniforms();
1101*8975f5c5SAndroid Build Coastguard Worker 
1102*8975f5c5SAndroid Build Coastguard Worker     // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
1103*8975f5c5SAndroid Build Coastguard Worker     std::vector<VariableLocation> unlocatedUniforms;
1104*8975f5c5SAndroid Build Coastguard Worker     std::map<GLuint, VariableLocation> preLocatedUniforms;
1105*8975f5c5SAndroid Build Coastguard Worker 
1106*8975f5c5SAndroid Build Coastguard Worker     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1107*8975f5c5SAndroid Build Coastguard Worker     {
1108*8975f5c5SAndroid Build Coastguard Worker         const UsedUniform &uniform = mUniforms[uniformIndex];
1109*8975f5c5SAndroid Build Coastguard Worker 
1110*8975f5c5SAndroid Build Coastguard Worker         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
1111*8975f5c5SAndroid Build Coastguard Worker             IsAtomicCounterType(uniform.type) || uniform.isFragmentInOut)
1112*8975f5c5SAndroid Build Coastguard Worker         {
1113*8975f5c5SAndroid Build Coastguard Worker             continue;
1114*8975f5c5SAndroid Build Coastguard Worker         }
1115*8975f5c5SAndroid Build Coastguard Worker 
1116*8975f5c5SAndroid Build Coastguard Worker         int preSetLocation = uniformLocationBindings.getBinding(uniform);
1117*8975f5c5SAndroid Build Coastguard Worker         int shaderLocation = uniform.location;
1118*8975f5c5SAndroid Build Coastguard Worker 
1119*8975f5c5SAndroid Build Coastguard Worker         if (shaderLocation != -1)
1120*8975f5c5SAndroid Build Coastguard Worker         {
1121*8975f5c5SAndroid Build Coastguard Worker             preSetLocation = shaderLocation;
1122*8975f5c5SAndroid Build Coastguard Worker         }
1123*8975f5c5SAndroid Build Coastguard Worker 
1124*8975f5c5SAndroid Build Coastguard Worker         unsigned int elementCount = uniform.getBasicTypeElementCount();
1125*8975f5c5SAndroid Build Coastguard Worker         for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1126*8975f5c5SAndroid Build Coastguard Worker         {
1127*8975f5c5SAndroid Build Coastguard Worker             VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
1128*8975f5c5SAndroid Build Coastguard Worker 
1129*8975f5c5SAndroid Build Coastguard Worker             if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
1130*8975f5c5SAndroid Build Coastguard Worker             {
1131*8975f5c5SAndroid Build Coastguard Worker                 int elementLocation                 = preSetLocation + arrayIndex;
1132*8975f5c5SAndroid Build Coastguard Worker                 preLocatedUniforms[elementLocation] = location;
1133*8975f5c5SAndroid Build Coastguard Worker             }
1134*8975f5c5SAndroid Build Coastguard Worker             else
1135*8975f5c5SAndroid Build Coastguard Worker             {
1136*8975f5c5SAndroid Build Coastguard Worker                 unlocatedUniforms.push_back(location);
1137*8975f5c5SAndroid Build Coastguard Worker             }
1138*8975f5c5SAndroid Build Coastguard Worker         }
1139*8975f5c5SAndroid Build Coastguard Worker     }
1140*8975f5c5SAndroid Build Coastguard Worker 
1141*8975f5c5SAndroid Build Coastguard Worker     // Make enough space for all uniforms, with pre-set locations or not.
1142*8975f5c5SAndroid Build Coastguard Worker     mUniformLocations.resize(
1143*8975f5c5SAndroid Build Coastguard Worker         std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
1144*8975f5c5SAndroid Build Coastguard Worker                  static_cast<size_t>(maxUniformLocation + 1)));
1145*8975f5c5SAndroid Build Coastguard Worker 
1146*8975f5c5SAndroid Build Coastguard Worker     // Assign uniforms with pre-set locations
1147*8975f5c5SAndroid Build Coastguard Worker     for (const auto &uniform : preLocatedUniforms)
1148*8975f5c5SAndroid Build Coastguard Worker     {
1149*8975f5c5SAndroid Build Coastguard Worker         mUniformLocations[uniform.first] = uniform.second;
1150*8975f5c5SAndroid Build Coastguard Worker     }
1151*8975f5c5SAndroid Build Coastguard Worker 
1152*8975f5c5SAndroid Build Coastguard Worker     // Assign ignored uniforms
1153*8975f5c5SAndroid Build Coastguard Worker     for (const auto &ignoredLocation : ignoredLocations)
1154*8975f5c5SAndroid Build Coastguard Worker     {
1155*8975f5c5SAndroid Build Coastguard Worker         mUniformLocations[ignoredLocation].markIgnored();
1156*8975f5c5SAndroid Build Coastguard Worker     }
1157*8975f5c5SAndroid Build Coastguard Worker 
1158*8975f5c5SAndroid Build Coastguard Worker     // Automatically assign locations for the rest of the uniforms
1159*8975f5c5SAndroid Build Coastguard Worker     size_t nextUniformLocation = 0;
1160*8975f5c5SAndroid Build Coastguard Worker     for (const auto &unlocatedUniform : unlocatedUniforms)
1161*8975f5c5SAndroid Build Coastguard Worker     {
1162*8975f5c5SAndroid Build Coastguard Worker         while (mUniformLocations[nextUniformLocation].used() ||
1163*8975f5c5SAndroid Build Coastguard Worker                mUniformLocations[nextUniformLocation].ignored)
1164*8975f5c5SAndroid Build Coastguard Worker         {
1165*8975f5c5SAndroid Build Coastguard Worker             nextUniformLocation++;
1166*8975f5c5SAndroid Build Coastguard Worker         }
1167*8975f5c5SAndroid Build Coastguard Worker 
1168*8975f5c5SAndroid Build Coastguard Worker         ASSERT(nextUniformLocation < mUniformLocations.size());
1169*8975f5c5SAndroid Build Coastguard Worker         mUniformLocations[nextUniformLocation] = unlocatedUniform;
1170*8975f5c5SAndroid Build Coastguard Worker         nextUniformLocation++;
1171*8975f5c5SAndroid Build Coastguard Worker     }
1172*8975f5c5SAndroid Build Coastguard Worker 
1173*8975f5c5SAndroid Build Coastguard Worker     return true;
1174*8975f5c5SAndroid Build Coastguard Worker }
1175*8975f5c5SAndroid Build Coastguard Worker 
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)1176*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
1177*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog,
1178*8975f5c5SAndroid Build Coastguard Worker     const ProgramAliasedBindings &uniformLocationBindings,
1179*8975f5c5SAndroid Build Coastguard Worker     std::set<GLuint> *ignoredLocations,
1180*8975f5c5SAndroid Build Coastguard Worker     int *maxUniformLocation)
1181*8975f5c5SAndroid Build Coastguard Worker {
1182*8975f5c5SAndroid Build Coastguard Worker     // All the locations where another uniform can't be located.
1183*8975f5c5SAndroid Build Coastguard Worker     std::set<GLuint> reservedLocations;
1184*8975f5c5SAndroid Build Coastguard Worker 
1185*8975f5c5SAndroid Build Coastguard Worker     for (const UsedUniform &uniform : mUniforms)
1186*8975f5c5SAndroid Build Coastguard Worker     {
1187*8975f5c5SAndroid Build Coastguard Worker         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) || uniform.isFragmentInOut)
1188*8975f5c5SAndroid Build Coastguard Worker         {
1189*8975f5c5SAndroid Build Coastguard Worker             // The uniform of the fragment inout is not a normal uniform type. So, in the case of
1190*8975f5c5SAndroid Build Coastguard Worker             // the fragment inout, this routine should be skipped.
1191*8975f5c5SAndroid Build Coastguard Worker             continue;
1192*8975f5c5SAndroid Build Coastguard Worker         }
1193*8975f5c5SAndroid Build Coastguard Worker 
1194*8975f5c5SAndroid Build Coastguard Worker         int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
1195*8975f5c5SAndroid Build Coastguard Worker         int shaderLocation   = uniform.location;
1196*8975f5c5SAndroid Build Coastguard Worker 
1197*8975f5c5SAndroid Build Coastguard Worker         if (shaderLocation != -1)
1198*8975f5c5SAndroid Build Coastguard Worker         {
1199*8975f5c5SAndroid Build Coastguard Worker             unsigned int elementCount = uniform.getBasicTypeElementCount();
1200*8975f5c5SAndroid Build Coastguard Worker 
1201*8975f5c5SAndroid Build Coastguard Worker             for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1202*8975f5c5SAndroid Build Coastguard Worker             {
1203*8975f5c5SAndroid Build Coastguard Worker                 // GLSL ES 3.10 section 4.4.3
1204*8975f5c5SAndroid Build Coastguard Worker                 int elementLocation = shaderLocation + arrayIndex;
1205*8975f5c5SAndroid Build Coastguard Worker                 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
1206*8975f5c5SAndroid Build Coastguard Worker                 if (reservedLocations.find(elementLocation) != reservedLocations.end())
1207*8975f5c5SAndroid Build Coastguard Worker                 {
1208*8975f5c5SAndroid Build Coastguard Worker                     infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
1209*8975f5c5SAndroid Build Coastguard Worker                     return false;
1210*8975f5c5SAndroid Build Coastguard Worker                 }
1211*8975f5c5SAndroid Build Coastguard Worker                 reservedLocations.insert(elementLocation);
1212*8975f5c5SAndroid Build Coastguard Worker                 if (!uniform.active)
1213*8975f5c5SAndroid Build Coastguard Worker                 {
1214*8975f5c5SAndroid Build Coastguard Worker                     ignoredLocations->insert(elementLocation);
1215*8975f5c5SAndroid Build Coastguard Worker                 }
1216*8975f5c5SAndroid Build Coastguard Worker             }
1217*8975f5c5SAndroid Build Coastguard Worker         }
1218*8975f5c5SAndroid Build Coastguard Worker         else if (apiBoundLocation != -1 && uniform.staticUse)
1219*8975f5c5SAndroid Build Coastguard Worker         {
1220*8975f5c5SAndroid Build Coastguard Worker             // Only the first location is reserved even if the uniform is an array.
1221*8975f5c5SAndroid Build Coastguard Worker             *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
1222*8975f5c5SAndroid Build Coastguard Worker             if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
1223*8975f5c5SAndroid Build Coastguard Worker             {
1224*8975f5c5SAndroid Build Coastguard Worker                 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
1225*8975f5c5SAndroid Build Coastguard Worker                 return false;
1226*8975f5c5SAndroid Build Coastguard Worker             }
1227*8975f5c5SAndroid Build Coastguard Worker             reservedLocations.insert(apiBoundLocation);
1228*8975f5c5SAndroid Build Coastguard Worker             if (!uniform.active)
1229*8975f5c5SAndroid Build Coastguard Worker             {
1230*8975f5c5SAndroid Build Coastguard Worker                 ignoredLocations->insert(apiBoundLocation);
1231*8975f5c5SAndroid Build Coastguard Worker             }
1232*8975f5c5SAndroid Build Coastguard Worker         }
1233*8975f5c5SAndroid Build Coastguard Worker     }
1234*8975f5c5SAndroid Build Coastguard Worker 
1235*8975f5c5SAndroid Build Coastguard Worker     // Record the uniform locations that were bound using the API for uniforms that were not found
1236*8975f5c5SAndroid Build Coastguard Worker     // from the shader. Other uniforms should not be assigned to those locations.
1237*8975f5c5SAndroid Build Coastguard Worker     for (const auto &locationBinding : uniformLocationBindings)
1238*8975f5c5SAndroid Build Coastguard Worker     {
1239*8975f5c5SAndroid Build Coastguard Worker         GLuint location = locationBinding.second.location;
1240*8975f5c5SAndroid Build Coastguard Worker         if (reservedLocations.find(location) == reservedLocations.end())
1241*8975f5c5SAndroid Build Coastguard Worker         {
1242*8975f5c5SAndroid Build Coastguard Worker             ignoredLocations->insert(location);
1243*8975f5c5SAndroid Build Coastguard Worker             *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
1244*8975f5c5SAndroid Build Coastguard Worker         }
1245*8975f5c5SAndroid Build Coastguard Worker     }
1246*8975f5c5SAndroid Build Coastguard Worker 
1247*8975f5c5SAndroid Build Coastguard Worker     return true;
1248*8975f5c5SAndroid Build Coastguard Worker }
1249*8975f5c5SAndroid Build Coastguard Worker 
pruneUnusedUniforms()1250*8975f5c5SAndroid Build Coastguard Worker void UniformLinker::pruneUnusedUniforms()
1251*8975f5c5SAndroid Build Coastguard Worker {
1252*8975f5c5SAndroid Build Coastguard Worker     auto uniformIter = mUniforms.begin();
1253*8975f5c5SAndroid Build Coastguard Worker     while (uniformIter != mUniforms.end())
1254*8975f5c5SAndroid Build Coastguard Worker     {
1255*8975f5c5SAndroid Build Coastguard Worker         if (uniformIter->active)
1256*8975f5c5SAndroid Build Coastguard Worker         {
1257*8975f5c5SAndroid Build Coastguard Worker             ++uniformIter;
1258*8975f5c5SAndroid Build Coastguard Worker         }
1259*8975f5c5SAndroid Build Coastguard Worker         else
1260*8975f5c5SAndroid Build Coastguard Worker         {
1261*8975f5c5SAndroid Build Coastguard Worker             mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
1262*8975f5c5SAndroid Build Coastguard Worker                                          uniformIter->isImage(), uniformIter->isAtomicCounter(),
1263*8975f5c5SAndroid Build Coastguard Worker                                          uniformIter->isFragmentInOut);
1264*8975f5c5SAndroid Build Coastguard Worker             uniformIter = mUniforms.erase(uniformIter);
1265*8975f5c5SAndroid Build Coastguard Worker         }
1266*8975f5c5SAndroid Build Coastguard Worker     }
1267*8975f5c5SAndroid Build Coastguard Worker }
1268*8975f5c5SAndroid Build Coastguard Worker 
flattenUniformsAndCheckCapsForShader(ShaderType shaderType,const Caps & caps,std::vector<UsedUniform> & samplerUniforms,std::vector<UsedUniform> & imageUniforms,std::vector<UsedUniform> & atomicCounterUniforms,std::vector<UsedUniform> & inputAttachmentUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)1269*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::flattenUniformsAndCheckCapsForShader(
1270*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderType,
1271*8975f5c5SAndroid Build Coastguard Worker     const Caps &caps,
1272*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> &samplerUniforms,
1273*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> &imageUniforms,
1274*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> &atomicCounterUniforms,
1275*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> &inputAttachmentUniforms,
1276*8975f5c5SAndroid Build Coastguard Worker     std::vector<UnusedUniform> &unusedUniforms,
1277*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog)
1278*8975f5c5SAndroid Build Coastguard Worker {
1279*8975f5c5SAndroid Build Coastguard Worker     ShaderUniformCount shaderUniformCount;
1280*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderType])
1281*8975f5c5SAndroid Build Coastguard Worker     {
1282*8975f5c5SAndroid Build Coastguard Worker         FlattenUniformVisitor flattener(shaderType, uniform, &mUniforms, &samplerUniforms,
1283*8975f5c5SAndroid Build Coastguard Worker                                         &imageUniforms, &atomicCounterUniforms,
1284*8975f5c5SAndroid Build Coastguard Worker                                         &inputAttachmentUniforms, &unusedUniforms);
1285*8975f5c5SAndroid Build Coastguard Worker         sh::TraverseShaderVariable(uniform, false, &flattener);
1286*8975f5c5SAndroid Build Coastguard Worker 
1287*8975f5c5SAndroid Build Coastguard Worker         if (uniform.active)
1288*8975f5c5SAndroid Build Coastguard Worker         {
1289*8975f5c5SAndroid Build Coastguard Worker             shaderUniformCount += flattener.getCounts();
1290*8975f5c5SAndroid Build Coastguard Worker         }
1291*8975f5c5SAndroid Build Coastguard Worker         else
1292*8975f5c5SAndroid Build Coastguard Worker         {
1293*8975f5c5SAndroid Build Coastguard Worker             unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
1294*8975f5c5SAndroid Build Coastguard Worker                                         IsImageType(uniform.type),
1295*8975f5c5SAndroid Build Coastguard Worker                                         IsAtomicCounterType(uniform.type), uniform.isFragmentInOut);
1296*8975f5c5SAndroid Build Coastguard Worker         }
1297*8975f5c5SAndroid Build Coastguard Worker     }
1298*8975f5c5SAndroid Build Coastguard Worker 
1299*8975f5c5SAndroid Build Coastguard Worker     // This code does not do fine-grained component counting.
1300*8975f5c5SAndroid Build Coastguard Worker     GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
1301*8975f5c5SAndroid Build Coastguard Worker     if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
1302*8975f5c5SAndroid Build Coastguard Worker     {
1303*8975f5c5SAndroid Build Coastguard Worker         GLuint maxUniforms = 0u;
1304*8975f5c5SAndroid Build Coastguard Worker 
1305*8975f5c5SAndroid Build Coastguard Worker         // See comments in GetUniformResourceLimitName()
1306*8975f5c5SAndroid Build Coastguard Worker         if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
1307*8975f5c5SAndroid Build Coastguard Worker         {
1308*8975f5c5SAndroid Build Coastguard Worker             maxUniforms = maxUniformVectorsCount;
1309*8975f5c5SAndroid Build Coastguard Worker         }
1310*8975f5c5SAndroid Build Coastguard Worker         else
1311*8975f5c5SAndroid Build Coastguard Worker         {
1312*8975f5c5SAndroid Build Coastguard Worker             maxUniforms = maxUniformVectorsCount * 4;
1313*8975f5c5SAndroid Build Coastguard Worker         }
1314*8975f5c5SAndroid Build Coastguard Worker 
1315*8975f5c5SAndroid Build Coastguard Worker         LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
1316*8975f5c5SAndroid Build Coastguard Worker         return false;
1317*8975f5c5SAndroid Build Coastguard Worker     }
1318*8975f5c5SAndroid Build Coastguard Worker 
1319*8975f5c5SAndroid Build Coastguard Worker     if (shaderUniformCount.samplerCount >
1320*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
1321*8975f5c5SAndroid Build Coastguard Worker     {
1322*8975f5c5SAndroid Build Coastguard Worker         LogUniformsExceedLimit(shaderType, UniformType::Sampler,
1323*8975f5c5SAndroid Build Coastguard Worker                                caps.maxShaderTextureImageUnits[shaderType], infoLog);
1324*8975f5c5SAndroid Build Coastguard Worker         return false;
1325*8975f5c5SAndroid Build Coastguard Worker     }
1326*8975f5c5SAndroid Build Coastguard Worker 
1327*8975f5c5SAndroid Build Coastguard Worker     if (shaderUniformCount.imageCount >
1328*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
1329*8975f5c5SAndroid Build Coastguard Worker     {
1330*8975f5c5SAndroid Build Coastguard Worker         LogUniformsExceedLimit(shaderType, UniformType::Image,
1331*8975f5c5SAndroid Build Coastguard Worker                                caps.maxShaderImageUniforms[shaderType], infoLog);
1332*8975f5c5SAndroid Build Coastguard Worker         return false;
1333*8975f5c5SAndroid Build Coastguard Worker     }
1334*8975f5c5SAndroid Build Coastguard Worker 
1335*8975f5c5SAndroid Build Coastguard Worker     if (shaderUniformCount.atomicCounterCount >
1336*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
1337*8975f5c5SAndroid Build Coastguard Worker     {
1338*8975f5c5SAndroid Build Coastguard Worker         LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
1339*8975f5c5SAndroid Build Coastguard Worker                                caps.maxShaderAtomicCounters[shaderType], infoLog);
1340*8975f5c5SAndroid Build Coastguard Worker         return false;
1341*8975f5c5SAndroid Build Coastguard Worker     }
1342*8975f5c5SAndroid Build Coastguard Worker 
1343*8975f5c5SAndroid Build Coastguard Worker     return true;
1344*8975f5c5SAndroid Build Coastguard Worker }
1345*8975f5c5SAndroid Build Coastguard Worker 
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1346*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1347*8975f5c5SAndroid Build Coastguard Worker {
1348*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> samplerUniforms;
1349*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> imageUniforms;
1350*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> atomicCounterUniforms;
1351*8975f5c5SAndroid Build Coastguard Worker     std::vector<UsedUniform> inputAttachmentUniforms;
1352*8975f5c5SAndroid Build Coastguard Worker     std::vector<UnusedUniform> unusedUniforms;
1353*8975f5c5SAndroid Build Coastguard Worker 
1354*8975f5c5SAndroid Build Coastguard Worker     for (const ShaderType shaderType : mActiveShaderStages)
1355*8975f5c5SAndroid Build Coastguard Worker     {
1356*8975f5c5SAndroid Build Coastguard Worker         if (!flattenUniformsAndCheckCapsForShader(shaderType, caps, samplerUniforms, imageUniforms,
1357*8975f5c5SAndroid Build Coastguard Worker                                                   atomicCounterUniforms, inputAttachmentUniforms,
1358*8975f5c5SAndroid Build Coastguard Worker                                                   unusedUniforms, infoLog))
1359*8975f5c5SAndroid Build Coastguard Worker         {
1360*8975f5c5SAndroid Build Coastguard Worker             return false;
1361*8975f5c5SAndroid Build Coastguard Worker         }
1362*8975f5c5SAndroid Build Coastguard Worker     }
1363*8975f5c5SAndroid Build Coastguard Worker 
1364*8975f5c5SAndroid Build Coastguard Worker     mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1365*8975f5c5SAndroid Build Coastguard Worker     mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1366*8975f5c5SAndroid Build Coastguard Worker     mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1367*8975f5c5SAndroid Build Coastguard Worker     mUniforms.insert(mUniforms.end(), inputAttachmentUniforms.begin(),
1368*8975f5c5SAndroid Build Coastguard Worker                      inputAttachmentUniforms.end());
1369*8975f5c5SAndroid Build Coastguard Worker     mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1370*8975f5c5SAndroid Build Coastguard Worker     return true;
1371*8975f5c5SAndroid Build Coastguard Worker }
1372*8975f5c5SAndroid Build Coastguard Worker 
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1373*8975f5c5SAndroid Build Coastguard Worker bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1374*8975f5c5SAndroid Build Coastguard Worker {
1375*8975f5c5SAndroid Build Coastguard Worker     unsigned int atomicCounterCount = 0;
1376*8975f5c5SAndroid Build Coastguard Worker     for (const auto &uniform : mUniforms)
1377*8975f5c5SAndroid Build Coastguard Worker     {
1378*8975f5c5SAndroid Build Coastguard Worker         if (IsAtomicCounterType(uniform.type) && uniform.active)
1379*8975f5c5SAndroid Build Coastguard Worker         {
1380*8975f5c5SAndroid Build Coastguard Worker             atomicCounterCount += uniform.getBasicTypeElementCount();
1381*8975f5c5SAndroid Build Coastguard Worker             if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1382*8975f5c5SAndroid Build Coastguard Worker             {
1383*8975f5c5SAndroid Build Coastguard Worker                 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1384*8975f5c5SAndroid Build Coastguard Worker                         << caps.maxCombinedAtomicCounters << ").";
1385*8975f5c5SAndroid Build Coastguard Worker                 return false;
1386*8975f5c5SAndroid Build Coastguard Worker             }
1387*8975f5c5SAndroid Build Coastguard Worker         }
1388*8975f5c5SAndroid Build Coastguard Worker     }
1389*8975f5c5SAndroid Build Coastguard Worker     return true;
1390*8975f5c5SAndroid Build Coastguard Worker }
1391*8975f5c5SAndroid Build Coastguard Worker 
1392*8975f5c5SAndroid Build Coastguard Worker // InterfaceBlockLinker implementation.
1393*8975f5c5SAndroid Build Coastguard Worker InterfaceBlockLinker::InterfaceBlockLinker() = default;
1394*8975f5c5SAndroid Build Coastguard Worker 
1395*8975f5c5SAndroid Build Coastguard Worker InterfaceBlockLinker::~InterfaceBlockLinker() = default;
1396*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1397*8975f5c5SAndroid Build Coastguard Worker void InterfaceBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1398*8975f5c5SAndroid Build Coastguard Worker                                 std::vector<std::string> *unusedInterfaceBlocksOut)
1399*8975f5c5SAndroid Build Coastguard Worker {
1400*8975f5c5SAndroid Build Coastguard Worker     mBlocksOut                = blocksOut;
1401*8975f5c5SAndroid Build Coastguard Worker     mUnusedInterfaceBlocksOut = unusedInterfaceBlocksOut;
1402*8975f5c5SAndroid Build Coastguard Worker }
1403*8975f5c5SAndroid Build Coastguard Worker 
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1404*8975f5c5SAndroid Build Coastguard Worker void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1405*8975f5c5SAndroid Build Coastguard Worker                                            const std::vector<sh::InterfaceBlock> *blocks)
1406*8975f5c5SAndroid Build Coastguard Worker {
1407*8975f5c5SAndroid Build Coastguard Worker     mShaderBlocks[shaderType] = blocks;
1408*8975f5c5SAndroid Build Coastguard Worker }
1409*8975f5c5SAndroid Build Coastguard Worker 
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1410*8975f5c5SAndroid Build Coastguard Worker void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1411*8975f5c5SAndroid Build Coastguard Worker                                       const GetBlockMemberInfoFunc &getMemberInfo) const
1412*8975f5c5SAndroid Build Coastguard Worker {
1413*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBlocksOut->empty());
1414*8975f5c5SAndroid Build Coastguard Worker 
1415*8975f5c5SAndroid Build Coastguard Worker     std::set<std::string> visitedList;
1416*8975f5c5SAndroid Build Coastguard Worker 
1417*8975f5c5SAndroid Build Coastguard Worker     for (const ShaderType shaderType : AllShaderTypes())
1418*8975f5c5SAndroid Build Coastguard Worker     {
1419*8975f5c5SAndroid Build Coastguard Worker         if (!mShaderBlocks[shaderType])
1420*8975f5c5SAndroid Build Coastguard Worker         {
1421*8975f5c5SAndroid Build Coastguard Worker             continue;
1422*8975f5c5SAndroid Build Coastguard Worker         }
1423*8975f5c5SAndroid Build Coastguard Worker 
1424*8975f5c5SAndroid Build Coastguard Worker         for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1425*8975f5c5SAndroid Build Coastguard Worker         {
1426*8975f5c5SAndroid Build Coastguard Worker             if (!IsActiveInterfaceBlock(block))
1427*8975f5c5SAndroid Build Coastguard Worker             {
1428*8975f5c5SAndroid Build Coastguard Worker                 mUnusedInterfaceBlocksOut->push_back(block.name);
1429*8975f5c5SAndroid Build Coastguard Worker                 continue;
1430*8975f5c5SAndroid Build Coastguard Worker             }
1431*8975f5c5SAndroid Build Coastguard Worker 
1432*8975f5c5SAndroid Build Coastguard Worker             if (visitedList.count(block.name) == 0)
1433*8975f5c5SAndroid Build Coastguard Worker             {
1434*8975f5c5SAndroid Build Coastguard Worker                 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1435*8975f5c5SAndroid Build Coastguard Worker                 visitedList.insert(block.name);
1436*8975f5c5SAndroid Build Coastguard Worker                 continue;
1437*8975f5c5SAndroid Build Coastguard Worker             }
1438*8975f5c5SAndroid Build Coastguard Worker 
1439*8975f5c5SAndroid Build Coastguard Worker             if (!block.active)
1440*8975f5c5SAndroid Build Coastguard Worker             {
1441*8975f5c5SAndroid Build Coastguard Worker                 mUnusedInterfaceBlocksOut->push_back(block.name);
1442*8975f5c5SAndroid Build Coastguard Worker                 continue;
1443*8975f5c5SAndroid Build Coastguard Worker             }
1444*8975f5c5SAndroid Build Coastguard Worker 
1445*8975f5c5SAndroid Build Coastguard Worker             for (InterfaceBlock &priorBlock : *mBlocksOut)
1446*8975f5c5SAndroid Build Coastguard Worker             {
1447*8975f5c5SAndroid Build Coastguard Worker                 if (block.name == priorBlock.name)
1448*8975f5c5SAndroid Build Coastguard Worker                 {
1449*8975f5c5SAndroid Build Coastguard Worker                     priorBlock.setActive(shaderType, true, block.id);
1450*8975f5c5SAndroid Build Coastguard Worker 
1451*8975f5c5SAndroid Build Coastguard Worker                     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1452*8975f5c5SAndroid Build Coastguard Worker                         getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1453*8975f5c5SAndroid Build Coastguard Worker                                    shaderType, -1));
1454*8975f5c5SAndroid Build Coastguard Worker 
1455*8975f5c5SAndroid Build Coastguard Worker                     sh::TraverseShaderVariables(block.fields, false, visitor.get());
1456*8975f5c5SAndroid Build Coastguard Worker                 }
1457*8975f5c5SAndroid Build Coastguard Worker             }
1458*8975f5c5SAndroid Build Coastguard Worker         }
1459*8975f5c5SAndroid Build Coastguard Worker     }
1460*8975f5c5SAndroid Build Coastguard Worker }
1461*8975f5c5SAndroid Build Coastguard Worker 
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1462*8975f5c5SAndroid Build Coastguard Worker void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1463*8975f5c5SAndroid Build Coastguard Worker                                                 const GetBlockMemberInfoFunc &getMemberInfo,
1464*8975f5c5SAndroid Build Coastguard Worker                                                 const sh::InterfaceBlock &interfaceBlock,
1465*8975f5c5SAndroid Build Coastguard Worker                                                 ShaderType shaderType) const
1466*8975f5c5SAndroid Build Coastguard Worker {
1467*8975f5c5SAndroid Build Coastguard Worker     size_t blockSize = 0;
1468*8975f5c5SAndroid Build Coastguard Worker     std::vector<unsigned int> blockIndexes;
1469*8975f5c5SAndroid Build Coastguard Worker 
1470*8975f5c5SAndroid Build Coastguard Worker     const int blockIndex = static_cast<int>(mBlocksOut->size());
1471*8975f5c5SAndroid Build Coastguard Worker     // Track the first and last block member index to determine the range of active block members in
1472*8975f5c5SAndroid Build Coastguard Worker     // the block.
1473*8975f5c5SAndroid Build Coastguard Worker     const size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1474*8975f5c5SAndroid Build Coastguard Worker 
1475*8975f5c5SAndroid Build Coastguard Worker     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1476*8975f5c5SAndroid Build Coastguard Worker         getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1477*8975f5c5SAndroid Build Coastguard Worker                    shaderType, blockIndex));
1478*8975f5c5SAndroid Build Coastguard Worker     sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1479*8975f5c5SAndroid Build Coastguard Worker 
1480*8975f5c5SAndroid Build Coastguard Worker     const size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1481*8975f5c5SAndroid Build Coastguard Worker 
1482*8975f5c5SAndroid Build Coastguard Worker     for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1483*8975f5c5SAndroid Build Coastguard Worker          ++blockMemberIndex)
1484*8975f5c5SAndroid Build Coastguard Worker     {
1485*8975f5c5SAndroid Build Coastguard Worker         blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1486*8975f5c5SAndroid Build Coastguard Worker     }
1487*8975f5c5SAndroid Build Coastguard Worker 
1488*8975f5c5SAndroid Build Coastguard Worker     const unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1489*8975f5c5SAndroid Build Coastguard Worker 
1490*8975f5c5SAndroid Build Coastguard Worker     for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1491*8975f5c5SAndroid Build Coastguard Worker          ++arrayElement)
1492*8975f5c5SAndroid Build Coastguard Worker     {
1493*8975f5c5SAndroid Build Coastguard Worker         std::string blockArrayName       = interfaceBlock.name;
1494*8975f5c5SAndroid Build Coastguard Worker         std::string blockMappedArrayName = interfaceBlock.mappedName;
1495*8975f5c5SAndroid Build Coastguard Worker         if (interfaceBlock.isArray())
1496*8975f5c5SAndroid Build Coastguard Worker         {
1497*8975f5c5SAndroid Build Coastguard Worker             blockArrayName += ArrayString(arrayElement);
1498*8975f5c5SAndroid Build Coastguard Worker             blockMappedArrayName += ArrayString(arrayElement);
1499*8975f5c5SAndroid Build Coastguard Worker         }
1500*8975f5c5SAndroid Build Coastguard Worker 
1501*8975f5c5SAndroid Build Coastguard Worker         // Don't define this block at all if it's not active in the implementation.
1502*8975f5c5SAndroid Build Coastguard Worker         if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1503*8975f5c5SAndroid Build Coastguard Worker         {
1504*8975f5c5SAndroid Build Coastguard Worker             continue;
1505*8975f5c5SAndroid Build Coastguard Worker         }
1506*8975f5c5SAndroid Build Coastguard Worker 
1507*8975f5c5SAndroid Build Coastguard Worker         // ESSL 3.10 section 4.4.4 page 58:
1508*8975f5c5SAndroid Build Coastguard Worker         // Any uniform or shader storage block declared without a binding qualifier is initially
1509*8975f5c5SAndroid Build Coastguard Worker         // assigned to block binding point zero.
1510*8975f5c5SAndroid Build Coastguard Worker         const int blockBinding =
1511*8975f5c5SAndroid Build Coastguard Worker             (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1512*8975f5c5SAndroid Build Coastguard Worker         InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1513*8975f5c5SAndroid Build Coastguard Worker                              interfaceBlock.isArray(), interfaceBlock.isReadOnly, arrayElement,
1514*8975f5c5SAndroid Build Coastguard Worker                              firstFieldArraySize, blockBinding);
1515*8975f5c5SAndroid Build Coastguard Worker         block.memberIndexes = blockIndexes;
1516*8975f5c5SAndroid Build Coastguard Worker         block.setActive(shaderType, interfaceBlock.active, interfaceBlock.id);
1517*8975f5c5SAndroid Build Coastguard Worker 
1518*8975f5c5SAndroid Build Coastguard Worker         // Since all block elements in an array share the same active interface blocks, they
1519*8975f5c5SAndroid Build Coastguard Worker         // will all be active once any block member is used. So, since interfaceBlock.name[0]
1520*8975f5c5SAndroid Build Coastguard Worker         // was active, here we will add every block element in the array.
1521*8975f5c5SAndroid Build Coastguard Worker         block.pod.dataSize = static_cast<unsigned int>(blockSize);
1522*8975f5c5SAndroid Build Coastguard Worker         mBlocksOut->push_back(block);
1523*8975f5c5SAndroid Build Coastguard Worker     }
1524*8975f5c5SAndroid Build Coastguard Worker }
1525*8975f5c5SAndroid Build Coastguard Worker 
1526*8975f5c5SAndroid Build Coastguard Worker // UniformBlockLinker implementation.
1527*8975f5c5SAndroid Build Coastguard Worker UniformBlockLinker::UniformBlockLinker() = default;
1528*8975f5c5SAndroid Build Coastguard Worker 
~UniformBlockLinker()1529*8975f5c5SAndroid Build Coastguard Worker UniformBlockLinker::~UniformBlockLinker() {}
1530*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1531*8975f5c5SAndroid Build Coastguard Worker void UniformBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1532*8975f5c5SAndroid Build Coastguard Worker                               std::vector<LinkedUniform> *uniformsOut,
1533*8975f5c5SAndroid Build Coastguard Worker                               std::vector<std::string> *uniformNamesOut,
1534*8975f5c5SAndroid Build Coastguard Worker                               std::vector<std::string> *uniformMappedNamesOut,
1535*8975f5c5SAndroid Build Coastguard Worker                               std::vector<std::string> *unusedInterfaceBlocksOut)
1536*8975f5c5SAndroid Build Coastguard Worker {
1537*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1538*8975f5c5SAndroid Build Coastguard Worker     mUniformsOut           = uniformsOut;
1539*8975f5c5SAndroid Build Coastguard Worker     mUniformNamesOut       = uniformNamesOut;
1540*8975f5c5SAndroid Build Coastguard Worker     mUniformMappedNamesOut = uniformMappedNamesOut;
1541*8975f5c5SAndroid Build Coastguard Worker }
1542*8975f5c5SAndroid Build Coastguard Worker 
getCurrentBlockMemberIndex() const1543*8975f5c5SAndroid Build Coastguard Worker size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1544*8975f5c5SAndroid Build Coastguard Worker {
1545*8975f5c5SAndroid Build Coastguard Worker     return mUniformsOut->size();
1546*8975f5c5SAndroid Build Coastguard Worker }
1547*8975f5c5SAndroid Build Coastguard Worker 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1548*8975f5c5SAndroid Build Coastguard Worker sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1549*8975f5c5SAndroid Build Coastguard Worker     const GetBlockMemberInfoFunc &getMemberInfo,
1550*8975f5c5SAndroid Build Coastguard Worker     const std::string &namePrefix,
1551*8975f5c5SAndroid Build Coastguard Worker     const std::string &mappedNamePrefix,
1552*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderType,
1553*8975f5c5SAndroid Build Coastguard Worker     int blockIndex) const
1554*8975f5c5SAndroid Build Coastguard Worker {
1555*8975f5c5SAndroid Build Coastguard Worker     return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1556*8975f5c5SAndroid Build Coastguard Worker                                            mUniformsOut, mUniformNamesOut, mUniformMappedNamesOut,
1557*8975f5c5SAndroid Build Coastguard Worker                                            shaderType, blockIndex);
1558*8975f5c5SAndroid Build Coastguard Worker }
1559*8975f5c5SAndroid Build Coastguard Worker 
1560*8975f5c5SAndroid Build Coastguard Worker // ShaderStorageBlockLinker implementation.
1561*8975f5c5SAndroid Build Coastguard Worker ShaderStorageBlockLinker::ShaderStorageBlockLinker() = default;
1562*8975f5c5SAndroid Build Coastguard Worker 
1563*8975f5c5SAndroid Build Coastguard Worker ShaderStorageBlockLinker::~ShaderStorageBlockLinker() = default;
1564*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1565*8975f5c5SAndroid Build Coastguard Worker void ShaderStorageBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1566*8975f5c5SAndroid Build Coastguard Worker                                     std::vector<BufferVariable> *bufferVariablesOut,
1567*8975f5c5SAndroid Build Coastguard Worker                                     std::vector<std::string> *unusedInterfaceBlocksOut)
1568*8975f5c5SAndroid Build Coastguard Worker {
1569*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1570*8975f5c5SAndroid Build Coastguard Worker     mBufferVariablesOut = bufferVariablesOut;
1571*8975f5c5SAndroid Build Coastguard Worker }
1572*8975f5c5SAndroid Build Coastguard Worker 
getCurrentBlockMemberIndex() const1573*8975f5c5SAndroid Build Coastguard Worker size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1574*8975f5c5SAndroid Build Coastguard Worker {
1575*8975f5c5SAndroid Build Coastguard Worker     return mBufferVariablesOut->size();
1576*8975f5c5SAndroid Build Coastguard Worker }
1577*8975f5c5SAndroid Build Coastguard Worker 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1578*8975f5c5SAndroid Build Coastguard Worker sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1579*8975f5c5SAndroid Build Coastguard Worker     const GetBlockMemberInfoFunc &getMemberInfo,
1580*8975f5c5SAndroid Build Coastguard Worker     const std::string &namePrefix,
1581*8975f5c5SAndroid Build Coastguard Worker     const std::string &mappedNamePrefix,
1582*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderType,
1583*8975f5c5SAndroid Build Coastguard Worker     int blockIndex) const
1584*8975f5c5SAndroid Build Coastguard Worker {
1585*8975f5c5SAndroid Build Coastguard Worker     return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1586*8975f5c5SAndroid Build Coastguard Worker                                          mBufferVariablesOut, shaderType, blockIndex);
1587*8975f5c5SAndroid Build Coastguard Worker }
1588*8975f5c5SAndroid Build Coastguard Worker 
1589*8975f5c5SAndroid Build Coastguard Worker // AtomicCounterBufferLinker implementation.
1590*8975f5c5SAndroid Build Coastguard Worker AtomicCounterBufferLinker::AtomicCounterBufferLinker() = default;
1591*8975f5c5SAndroid Build Coastguard Worker 
1592*8975f5c5SAndroid Build Coastguard Worker AtomicCounterBufferLinker::~AtomicCounterBufferLinker() = default;
1593*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1594*8975f5c5SAndroid Build Coastguard Worker void AtomicCounterBufferLinker::init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1595*8975f5c5SAndroid Build Coastguard Worker {
1596*8975f5c5SAndroid Build Coastguard Worker     mAtomicCounterBuffersOut = atomicCounterBuffersOut;
1597*8975f5c5SAndroid Build Coastguard Worker }
1598*8975f5c5SAndroid Build Coastguard Worker 
link(const std::map<int,unsigned int> & sizeMap) const1599*8975f5c5SAndroid Build Coastguard Worker void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1600*8975f5c5SAndroid Build Coastguard Worker {
1601*8975f5c5SAndroid Build Coastguard Worker     for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1602*8975f5c5SAndroid Build Coastguard Worker     {
1603*8975f5c5SAndroid Build Coastguard Worker         auto bufferSize = sizeMap.find(atomicCounterBuffer.pod.inShaderBinding);
1604*8975f5c5SAndroid Build Coastguard Worker         ASSERT(bufferSize != sizeMap.end());
1605*8975f5c5SAndroid Build Coastguard Worker         atomicCounterBuffer.pod.dataSize = bufferSize->second;
1606*8975f5c5SAndroid Build Coastguard Worker     }
1607*8975f5c5SAndroid Build Coastguard Worker }
1608*8975f5c5SAndroid Build Coastguard Worker 
1609*8975f5c5SAndroid Build Coastguard Worker PixelLocalStorageLinker::PixelLocalStorageLinker() = default;
1610*8975f5c5SAndroid Build Coastguard Worker 
1611*8975f5c5SAndroid Build Coastguard Worker PixelLocalStorageLinker::~PixelLocalStorageLinker() = default;
1612*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<ShPixelLocalStorageFormat> * pixelLocalStorageFormatsOut)1613*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorageLinker::init(
1614*8975f5c5SAndroid Build Coastguard Worker     std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut)
1615*8975f5c5SAndroid Build Coastguard Worker {
1616*8975f5c5SAndroid Build Coastguard Worker     mPixelLocalStorageFormatsOut = pixelLocalStorageFormatsOut;
1617*8975f5c5SAndroid Build Coastguard Worker }
1618*8975f5c5SAndroid Build Coastguard Worker 
link(const std::vector<ShPixelLocalStorageFormat> & pixelLocalStorageFormats) const1619*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorageLinker::link(
1620*8975f5c5SAndroid Build Coastguard Worker     const std::vector<ShPixelLocalStorageFormat> &pixelLocalStorageFormats) const
1621*8975f5c5SAndroid Build Coastguard Worker {
1622*8975f5c5SAndroid Build Coastguard Worker     *mPixelLocalStorageFormatsOut = pixelLocalStorageFormats;
1623*8975f5c5SAndroid Build Coastguard Worker }
1624*8975f5c5SAndroid Build Coastguard Worker 
1625*8975f5c5SAndroid Build Coastguard Worker LinkingVariables::LinkingVariables()  = default;
1626*8975f5c5SAndroid Build Coastguard Worker LinkingVariables::~LinkingVariables() = default;
1627*8975f5c5SAndroid Build Coastguard Worker 
initForProgram(const ProgramState & state)1628*8975f5c5SAndroid Build Coastguard Worker void LinkingVariables::initForProgram(const ProgramState &state)
1629*8975f5c5SAndroid Build Coastguard Worker {
1630*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1631*8975f5c5SAndroid Build Coastguard Worker     {
1632*8975f5c5SAndroid Build Coastguard Worker         const SharedCompiledShaderState &shader = state.getAttachedShader(shaderType);
1633*8975f5c5SAndroid Build Coastguard Worker         if (shader)
1634*8975f5c5SAndroid Build Coastguard Worker         {
1635*8975f5c5SAndroid Build Coastguard Worker             outputVaryings[shaderType] = shader->outputVaryings;
1636*8975f5c5SAndroid Build Coastguard Worker             inputVaryings[shaderType]  = shader->inputVaryings;
1637*8975f5c5SAndroid Build Coastguard Worker             uniforms[shaderType]       = shader->uniforms;
1638*8975f5c5SAndroid Build Coastguard Worker             uniformBlocks[shaderType]  = shader->uniformBlocks;
1639*8975f5c5SAndroid Build Coastguard Worker             isShaderStageUsedBitset.set(shaderType);
1640*8975f5c5SAndroid Build Coastguard Worker         }
1641*8975f5c5SAndroid Build Coastguard Worker     }
1642*8975f5c5SAndroid Build Coastguard Worker }
1643*8975f5c5SAndroid Build Coastguard Worker 
initForProgramPipeline(const ProgramPipelineState & state)1644*8975f5c5SAndroid Build Coastguard Worker void LinkingVariables::initForProgramPipeline(const ProgramPipelineState &state)
1645*8975f5c5SAndroid Build Coastguard Worker {
1646*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : state.getExecutable().getLinkedShaderStages())
1647*8975f5c5SAndroid Build Coastguard Worker     {
1648*8975f5c5SAndroid Build Coastguard Worker         const SharedProgramExecutable &executable = state.getShaderProgramExecutable(shaderType);
1649*8975f5c5SAndroid Build Coastguard Worker         ASSERT(executable);
1650*8975f5c5SAndroid Build Coastguard Worker         outputVaryings[shaderType] = executable->getLinkedOutputVaryings(shaderType);
1651*8975f5c5SAndroid Build Coastguard Worker         inputVaryings[shaderType]  = executable->getLinkedInputVaryings(shaderType);
1652*8975f5c5SAndroid Build Coastguard Worker         uniforms[shaderType]       = executable->getLinkedUniforms(shaderType);
1653*8975f5c5SAndroid Build Coastguard Worker         uniformBlocks[shaderType]  = executable->getLinkedUniformBlocks(shaderType);
1654*8975f5c5SAndroid Build Coastguard Worker         isShaderStageUsedBitset.set(shaderType);
1655*8975f5c5SAndroid Build Coastguard Worker     }
1656*8975f5c5SAndroid Build Coastguard Worker }
1657*8975f5c5SAndroid Build Coastguard Worker 
1658*8975f5c5SAndroid Build Coastguard Worker ProgramLinkedResources::ProgramLinkedResources()  = default;
1659*8975f5c5SAndroid Build Coastguard Worker ProgramLinkedResources::~ProgramLinkedResources() = default;
1660*8975f5c5SAndroid Build Coastguard Worker 
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut,std::vector<ShPixelLocalStorageFormat> * pixelLocalStorageFormatsOut)1661*8975f5c5SAndroid Build Coastguard Worker void ProgramLinkedResources::init(
1662*8975f5c5SAndroid Build Coastguard Worker     std::vector<InterfaceBlock> *uniformBlocksOut,
1663*8975f5c5SAndroid Build Coastguard Worker     std::vector<LinkedUniform> *uniformsOut,
1664*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> *uniformNamesOut,
1665*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::string> *uniformMappedNamesOut,
1666*8975f5c5SAndroid Build Coastguard Worker     std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1667*8975f5c5SAndroid Build Coastguard Worker     std::vector<BufferVariable> *bufferVariablesOut,
1668*8975f5c5SAndroid Build Coastguard Worker     std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut,
1669*8975f5c5SAndroid Build Coastguard Worker     std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut)
1670*8975f5c5SAndroid Build Coastguard Worker {
1671*8975f5c5SAndroid Build Coastguard Worker     uniformBlockLinker.init(uniformBlocksOut, uniformsOut, uniformNamesOut, uniformMappedNamesOut,
1672*8975f5c5SAndroid Build Coastguard Worker                             &unusedInterfaceBlocks);
1673*8975f5c5SAndroid Build Coastguard Worker     shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1674*8975f5c5SAndroid Build Coastguard Worker                                   &unusedInterfaceBlocks);
1675*8975f5c5SAndroid Build Coastguard Worker     atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1676*8975f5c5SAndroid Build Coastguard Worker     pixelLocalStorageLinker.init(pixelLocalStorageFormatsOut);
1677*8975f5c5SAndroid Build Coastguard Worker }
1678*8975f5c5SAndroid Build Coastguard Worker 
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1679*8975f5c5SAndroid Build Coastguard Worker void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1680*8975f5c5SAndroid Build Coastguard Worker                                                  const ProgramLinkedResources &resources) const
1681*8975f5c5SAndroid Build Coastguard Worker {
1682*8975f5c5SAndroid Build Coastguard Worker     // Gather uniform interface block info.
1683*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1684*8975f5c5SAndroid Build Coastguard Worker     for (const ShaderType shaderType : AllShaderTypes())
1685*8975f5c5SAndroid Build Coastguard Worker     {
1686*8975f5c5SAndroid Build Coastguard Worker         const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1687*8975f5c5SAndroid Build Coastguard Worker         if (shader)
1688*8975f5c5SAndroid Build Coastguard Worker         {
1689*8975f5c5SAndroid Build Coastguard Worker             uniformBlockInfo.getShaderBlockInfo(shader->uniformBlocks);
1690*8975f5c5SAndroid Build Coastguard Worker         }
1691*8975f5c5SAndroid Build Coastguard Worker     }
1692*8975f5c5SAndroid Build Coastguard Worker 
1693*8975f5c5SAndroid Build Coastguard Worker     auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1694*8975f5c5SAndroid Build Coastguard Worker                                                    const std::string &mappedName, size_t *sizeOut) {
1695*8975f5c5SAndroid Build Coastguard Worker         return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1696*8975f5c5SAndroid Build Coastguard Worker     };
1697*8975f5c5SAndroid Build Coastguard Worker 
1698*8975f5c5SAndroid Build Coastguard Worker     auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1699*8975f5c5SAndroid Build Coastguard Worker                                                          const std::string &mappedName,
1700*8975f5c5SAndroid Build Coastguard Worker                                                          sh::BlockMemberInfo *infoOut) {
1701*8975f5c5SAndroid Build Coastguard Worker         return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1702*8975f5c5SAndroid Build Coastguard Worker     };
1703*8975f5c5SAndroid Build Coastguard Worker 
1704*8975f5c5SAndroid Build Coastguard Worker     // Link uniform interface blocks.
1705*8975f5c5SAndroid Build Coastguard Worker     resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1706*8975f5c5SAndroid Build Coastguard Worker 
1707*8975f5c5SAndroid Build Coastguard Worker     // Gather storage buffer interface block info.
1708*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1709*8975f5c5SAndroid Build Coastguard Worker     for (const ShaderType shaderType : AllShaderTypes())
1710*8975f5c5SAndroid Build Coastguard Worker     {
1711*8975f5c5SAndroid Build Coastguard Worker         const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1712*8975f5c5SAndroid Build Coastguard Worker         if (shader)
1713*8975f5c5SAndroid Build Coastguard Worker         {
1714*8975f5c5SAndroid Build Coastguard Worker             shaderStorageBlockInfo.getShaderBlockInfo(shader->shaderStorageBlocks);
1715*8975f5c5SAndroid Build Coastguard Worker         }
1716*8975f5c5SAndroid Build Coastguard Worker     }
1717*8975f5c5SAndroid Build Coastguard Worker     auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1718*8975f5c5SAndroid Build Coastguard Worker                                                                const std::string &mappedName,
1719*8975f5c5SAndroid Build Coastguard Worker                                                                size_t *sizeOut) {
1720*8975f5c5SAndroid Build Coastguard Worker         return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1721*8975f5c5SAndroid Build Coastguard Worker     };
1722*8975f5c5SAndroid Build Coastguard Worker 
1723*8975f5c5SAndroid Build Coastguard Worker     auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1724*8975f5c5SAndroid Build Coastguard Worker                                                                      const std::string &mappedName,
1725*8975f5c5SAndroid Build Coastguard Worker                                                                      sh::BlockMemberInfo *infoOut) {
1726*8975f5c5SAndroid Build Coastguard Worker         return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1727*8975f5c5SAndroid Build Coastguard Worker     };
1728*8975f5c5SAndroid Build Coastguard Worker 
1729*8975f5c5SAndroid Build Coastguard Worker     // Link storage buffer interface blocks.
1730*8975f5c5SAndroid Build Coastguard Worker     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1731*8975f5c5SAndroid Build Coastguard Worker                                                   getShaderStorageBlockMemberInfo);
1732*8975f5c5SAndroid Build Coastguard Worker 
1733*8975f5c5SAndroid Build Coastguard Worker     // Gather and link atomic counter buffer interface blocks.
1734*8975f5c5SAndroid Build Coastguard Worker     std::map<int, unsigned int> sizeMap;
1735*8975f5c5SAndroid Build Coastguard Worker     getAtomicCounterBufferSizeMap(programState.getExecutable(), sizeMap);
1736*8975f5c5SAndroid Build Coastguard Worker     resources.atomicCounterBufferLinker.link(sizeMap);
1737*8975f5c5SAndroid Build Coastguard Worker 
1738*8975f5c5SAndroid Build Coastguard Worker     const gl::SharedCompiledShaderState &fragmentShader =
1739*8975f5c5SAndroid Build Coastguard Worker         programState.getAttachedShader(gl::ShaderType::Fragment);
1740*8975f5c5SAndroid Build Coastguard Worker     if (fragmentShader != nullptr)
1741*8975f5c5SAndroid Build Coastguard Worker     {
1742*8975f5c5SAndroid Build Coastguard Worker         resources.pixelLocalStorageLinker.link(fragmentShader->pixelLocalStorageFormats);
1743*8975f5c5SAndroid Build Coastguard Worker     }
1744*8975f5c5SAndroid Build Coastguard Worker }
1745*8975f5c5SAndroid Build Coastguard Worker 
getAtomicCounterBufferSizeMap(const ProgramExecutable & executable,std::map<int,unsigned int> & sizeMapOut) const1746*8975f5c5SAndroid Build Coastguard Worker void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1747*8975f5c5SAndroid Build Coastguard Worker     const ProgramExecutable &executable,
1748*8975f5c5SAndroid Build Coastguard Worker     std::map<int, unsigned int> &sizeMapOut) const
1749*8975f5c5SAndroid Build Coastguard Worker {
1750*8975f5c5SAndroid Build Coastguard Worker     for (unsigned int index : executable.getAtomicCounterUniformRange())
1751*8975f5c5SAndroid Build Coastguard Worker     {
1752*8975f5c5SAndroid Build Coastguard Worker         const LinkedUniform &glUniform = executable.getUniforms()[index];
1753*8975f5c5SAndroid Build Coastguard Worker 
1754*8975f5c5SAndroid Build Coastguard Worker         auto &bufferDataSize = sizeMapOut[glUniform.getBinding()];
1755*8975f5c5SAndroid Build Coastguard Worker 
1756*8975f5c5SAndroid Build Coastguard Worker         // Calculate the size of the buffer by finding the end of the last uniform with the same
1757*8975f5c5SAndroid Build Coastguard Worker         // binding. The end of the uniform is calculated by finding the initial offset of the
1758*8975f5c5SAndroid Build Coastguard Worker         // uniform and adding size of the uniform. For arrays, the size is the number of elements
1759*8975f5c5SAndroid Build Coastguard Worker         // times the element size (should always by 4 for atomic_units).
1760*8975f5c5SAndroid Build Coastguard Worker         unsigned dataOffset =
1761*8975f5c5SAndroid Build Coastguard Worker             glUniform.getOffset() + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1762*8975f5c5SAndroid Build Coastguard Worker                                                               glUniform.getElementSize());
1763*8975f5c5SAndroid Build Coastguard Worker         if (dataOffset > bufferDataSize)
1764*8975f5c5SAndroid Build Coastguard Worker         {
1765*8975f5c5SAndroid Build Coastguard Worker             bufferDataSize = dataOffset;
1766*8975f5c5SAndroid Build Coastguard Worker         }
1767*8975f5c5SAndroid Build Coastguard Worker     }
1768*8975f5c5SAndroid Build Coastguard Worker }
1769*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateProgramGlobalNames(InfoLog & infoLog,const ProgramExecutable & executable,const LinkingVariables & linkingVariables)1770*8975f5c5SAndroid Build Coastguard Worker bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
1771*8975f5c5SAndroid Build Coastguard Worker                                     const ProgramExecutable &executable,
1772*8975f5c5SAndroid Build Coastguard Worker                                     const LinkingVariables &linkingVariables)
1773*8975f5c5SAndroid Build Coastguard Worker {
1774*8975f5c5SAndroid Build Coastguard Worker     angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1775*8975f5c5SAndroid Build Coastguard Worker     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1776*8975f5c5SAndroid Build Coastguard Worker     angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1777*8975f5c5SAndroid Build Coastguard Worker 
1778*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1779*8975f5c5SAndroid Build Coastguard Worker     {
1780*8975f5c5SAndroid Build Coastguard Worker         if (!linkingVariables.isShaderStageUsedBitset[shaderType])
1781*8975f5c5SAndroid Build Coastguard Worker         {
1782*8975f5c5SAndroid Build Coastguard Worker             continue;
1783*8975f5c5SAndroid Build Coastguard Worker         }
1784*8975f5c5SAndroid Build Coastguard Worker 
1785*8975f5c5SAndroid Build Coastguard Worker         // Build a map of Uniforms
1786*8975f5c5SAndroid Build Coastguard Worker         const std::vector<sh::ShaderVariable> &uniforms = linkingVariables.uniforms[shaderType];
1787*8975f5c5SAndroid Build Coastguard Worker         for (const auto &uniform : uniforms)
1788*8975f5c5SAndroid Build Coastguard Worker         {
1789*8975f5c5SAndroid Build Coastguard Worker             uniformMap[uniform.name] = &uniform;
1790*8975f5c5SAndroid Build Coastguard Worker         }
1791*8975f5c5SAndroid Build Coastguard Worker 
1792*8975f5c5SAndroid Build Coastguard Worker         // Build a map of Uniform Blocks
1793*8975f5c5SAndroid Build Coastguard Worker         // This will also detect any field name conflicts between Uniform Blocks without instance
1794*8975f5c5SAndroid Build Coastguard Worker         // names
1795*8975f5c5SAndroid Build Coastguard Worker         const std::vector<sh::InterfaceBlock> &uniformBlocks =
1796*8975f5c5SAndroid Build Coastguard Worker             linkingVariables.uniformBlocks[shaderType];
1797*8975f5c5SAndroid Build Coastguard Worker 
1798*8975f5c5SAndroid Build Coastguard Worker         for (const auto &uniformBlock : uniformBlocks)
1799*8975f5c5SAndroid Build Coastguard Worker         {
1800*8975f5c5SAndroid Build Coastguard Worker             // Only uniform blocks without an instance name can create a conflict with their field
1801*8975f5c5SAndroid Build Coastguard Worker             // names
1802*8975f5c5SAndroid Build Coastguard Worker             if (!uniformBlock.instanceName.empty())
1803*8975f5c5SAndroid Build Coastguard Worker             {
1804*8975f5c5SAndroid Build Coastguard Worker                 continue;
1805*8975f5c5SAndroid Build Coastguard Worker             }
1806*8975f5c5SAndroid Build Coastguard Worker 
1807*8975f5c5SAndroid Build Coastguard Worker             for (const auto &field : uniformBlock.fields)
1808*8975f5c5SAndroid Build Coastguard Worker             {
1809*8975f5c5SAndroid Build Coastguard Worker                 if (!uniformBlockFieldMap.count(field.name))
1810*8975f5c5SAndroid Build Coastguard Worker                 {
1811*8975f5c5SAndroid Build Coastguard Worker                     // First time we've seen this uniform block field name, so add the
1812*8975f5c5SAndroid Build Coastguard Worker                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1813*8975f5c5SAndroid Build Coastguard Worker                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1814*8975f5c5SAndroid Build Coastguard Worker                     std::vector<BlockAndFieldPair> newUniformBlockList;
1815*8975f5c5SAndroid Build Coastguard Worker                     newUniformBlockList.push_back(blockAndFieldPair);
1816*8975f5c5SAndroid Build Coastguard Worker                     uniformBlockFieldMap[field.name] = newUniformBlockList;
1817*8975f5c5SAndroid Build Coastguard Worker                     continue;
1818*8975f5c5SAndroid Build Coastguard Worker                 }
1819*8975f5c5SAndroid Build Coastguard Worker 
1820*8975f5c5SAndroid Build Coastguard Worker                 // We've seen this name before.
1821*8975f5c5SAndroid Build Coastguard Worker                 // We need to check each of the uniform blocks that contain a field with this name
1822*8975f5c5SAndroid Build Coastguard Worker                 // to see if there's a conflict or not.
1823*8975f5c5SAndroid Build Coastguard Worker                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1824*8975f5c5SAndroid Build Coastguard Worker                     uniformBlockFieldMap[field.name];
1825*8975f5c5SAndroid Build Coastguard Worker                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1826*8975f5c5SAndroid Build Coastguard Worker                 {
1827*8975f5c5SAndroid Build Coastguard Worker                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
1828*8975f5c5SAndroid Build Coastguard Worker                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1829*8975f5c5SAndroid Build Coastguard Worker 
1830*8975f5c5SAndroid Build Coastguard Worker                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1831*8975f5c5SAndroid Build Coastguard Worker                     {
1832*8975f5c5SAndroid Build Coastguard Worker                         // The same uniform block should, by definition, contain the same field name
1833*8975f5c5SAndroid Build Coastguard Worker                         continue;
1834*8975f5c5SAndroid Build Coastguard Worker                     }
1835*8975f5c5SAndroid Build Coastguard Worker 
1836*8975f5c5SAndroid Build Coastguard Worker                     // The uniform blocks don't match, so check if the necessary field properties
1837*8975f5c5SAndroid Build Coastguard Worker                     // also match
1838*8975f5c5SAndroid Build Coastguard Worker                     if ((field.name == prevUniformBlockField->name) &&
1839*8975f5c5SAndroid Build Coastguard Worker                         (field.type == prevUniformBlockField->type) &&
1840*8975f5c5SAndroid Build Coastguard Worker                         (field.precision == prevUniformBlockField->precision))
1841*8975f5c5SAndroid Build Coastguard Worker                     {
1842*8975f5c5SAndroid Build Coastguard Worker                         infoLog << "Name conflicts between uniform block field names: "
1843*8975f5c5SAndroid Build Coastguard Worker                                 << field.name;
1844*8975f5c5SAndroid Build Coastguard Worker                         return false;
1845*8975f5c5SAndroid Build Coastguard Worker                     }
1846*8975f5c5SAndroid Build Coastguard Worker                 }
1847*8975f5c5SAndroid Build Coastguard Worker 
1848*8975f5c5SAndroid Build Coastguard Worker                 // No conflict, so record this pair
1849*8975f5c5SAndroid Build Coastguard Worker                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1850*8975f5c5SAndroid Build Coastguard Worker                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1851*8975f5c5SAndroid Build Coastguard Worker             }
1852*8975f5c5SAndroid Build Coastguard Worker         }
1853*8975f5c5SAndroid Build Coastguard Worker     }
1854*8975f5c5SAndroid Build Coastguard Worker 
1855*8975f5c5SAndroid Build Coastguard Worker     // Validate no uniform names conflict with attribute names
1856*8975f5c5SAndroid Build Coastguard Worker     if (linkingVariables.isShaderStageUsedBitset[ShaderType::Vertex])
1857*8975f5c5SAndroid Build Coastguard Worker     {
1858*8975f5c5SAndroid Build Coastguard Worker         // ESSL 3.00.6 section 4.3.5:
1859*8975f5c5SAndroid Build Coastguard Worker         // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1860*8975f5c5SAndroid Build Coastguard Worker         // but not in another (e.g., a fragment shader), then that name is still
1861*8975f5c5SAndroid Build Coastguard Worker         // available in the other stage for a different use.
1862*8975f5c5SAndroid Build Coastguard Worker         std::unordered_set<std::string> uniforms;
1863*8975f5c5SAndroid Build Coastguard Worker         for (const sh::ShaderVariable &uniform : linkingVariables.uniforms[ShaderType::Vertex])
1864*8975f5c5SAndroid Build Coastguard Worker         {
1865*8975f5c5SAndroid Build Coastguard Worker             uniforms.insert(uniform.name);
1866*8975f5c5SAndroid Build Coastguard Worker         }
1867*8975f5c5SAndroid Build Coastguard Worker         for (const auto &attrib : executable.getProgramInputs())
1868*8975f5c5SAndroid Build Coastguard Worker         {
1869*8975f5c5SAndroid Build Coastguard Worker             if (uniforms.count(attrib.name))
1870*8975f5c5SAndroid Build Coastguard Worker             {
1871*8975f5c5SAndroid Build Coastguard Worker                 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1872*8975f5c5SAndroid Build Coastguard Worker                 return false;
1873*8975f5c5SAndroid Build Coastguard Worker             }
1874*8975f5c5SAndroid Build Coastguard Worker         }
1875*8975f5c5SAndroid Build Coastguard Worker     }
1876*8975f5c5SAndroid Build Coastguard Worker 
1877*8975f5c5SAndroid Build Coastguard Worker     // Validate no Uniform Block fields conflict with other Uniforms
1878*8975f5c5SAndroid Build Coastguard Worker     for (const auto &uniformBlockField : uniformBlockFieldMap)
1879*8975f5c5SAndroid Build Coastguard Worker     {
1880*8975f5c5SAndroid Build Coastguard Worker         const std::string &fieldName = uniformBlockField.first;
1881*8975f5c5SAndroid Build Coastguard Worker         if (uniformMap.count(fieldName))
1882*8975f5c5SAndroid Build Coastguard Worker         {
1883*8975f5c5SAndroid Build Coastguard Worker             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1884*8975f5c5SAndroid Build Coastguard Worker             return false;
1885*8975f5c5SAndroid Build Coastguard Worker         }
1886*8975f5c5SAndroid Build Coastguard Worker     }
1887*8975f5c5SAndroid Build Coastguard Worker 
1888*8975f5c5SAndroid Build Coastguard Worker     return true;
1889*8975f5c5SAndroid Build Coastguard Worker }
1890*8975f5c5SAndroid Build Coastguard Worker 
1891*8975f5c5SAndroid Build Coastguard Worker // [OpenGL ES 3.2] Chapter 7.4.1 "Shader Interface Matching"
LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType frontShaderType,ShaderType backShaderType,int frontShaderVersion,int backShaderVersion,bool isSeparable,gl::InfoLog & infoLog)1892*8975f5c5SAndroid Build Coastguard Worker bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1893*8975f5c5SAndroid Build Coastguard Worker                                          const std::vector<sh::ShaderVariable> &inputVaryings,
1894*8975f5c5SAndroid Build Coastguard Worker                                          ShaderType frontShaderType,
1895*8975f5c5SAndroid Build Coastguard Worker                                          ShaderType backShaderType,
1896*8975f5c5SAndroid Build Coastguard Worker                                          int frontShaderVersion,
1897*8975f5c5SAndroid Build Coastguard Worker                                          int backShaderVersion,
1898*8975f5c5SAndroid Build Coastguard Worker                                          bool isSeparable,
1899*8975f5c5SAndroid Build Coastguard Worker                                          gl::InfoLog &infoLog)
1900*8975f5c5SAndroid Build Coastguard Worker {
1901*8975f5c5SAndroid Build Coastguard Worker     ASSERT(frontShaderVersion == backShaderVersion);
1902*8975f5c5SAndroid Build Coastguard Worker 
1903*8975f5c5SAndroid Build Coastguard Worker     std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1904*8975f5c5SAndroid Build Coastguard Worker     std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1905*8975f5c5SAndroid Build Coastguard Worker 
1906*8975f5c5SAndroid Build Coastguard Worker     GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1907*8975f5c5SAndroid Build Coastguard Worker     GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1908*8975f5c5SAndroid Build Coastguard Worker 
1909*8975f5c5SAndroid Build Coastguard Worker     // Separable programs require the number of inputs and outputs match
1910*8975f5c5SAndroid Build Coastguard Worker     if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1911*8975f5c5SAndroid Build Coastguard Worker     {
1912*8975f5c5SAndroid Build Coastguard Worker         infoLog << GetShaderTypeString(backShaderType)
1913*8975f5c5SAndroid Build Coastguard Worker                 << " does not consume all varyings generated by "
1914*8975f5c5SAndroid Build Coastguard Worker                 << GetShaderTypeString(frontShaderType);
1915*8975f5c5SAndroid Build Coastguard Worker         return false;
1916*8975f5c5SAndroid Build Coastguard Worker     }
1917*8975f5c5SAndroid Build Coastguard Worker     if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1918*8975f5c5SAndroid Build Coastguard Worker     {
1919*8975f5c5SAndroid Build Coastguard Worker         infoLog << GetShaderTypeString(frontShaderType)
1920*8975f5c5SAndroid Build Coastguard Worker                 << " does not generate all varyings consumed by "
1921*8975f5c5SAndroid Build Coastguard Worker                 << GetShaderTypeString(backShaderType);
1922*8975f5c5SAndroid Build Coastguard Worker         return false;
1923*8975f5c5SAndroid Build Coastguard Worker     }
1924*8975f5c5SAndroid Build Coastguard Worker 
1925*8975f5c5SAndroid Build Coastguard Worker     // All inputs must match all outputs
1926*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable *input : filteredInputVaryings)
1927*8975f5c5SAndroid Build Coastguard Worker     {
1928*8975f5c5SAndroid Build Coastguard Worker         bool match = false;
1929*8975f5c5SAndroid Build Coastguard Worker         for (const sh::ShaderVariable *output : filteredOutputVaryings)
1930*8975f5c5SAndroid Build Coastguard Worker         {
1931*8975f5c5SAndroid Build Coastguard Worker             if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1932*8975f5c5SAndroid Build Coastguard Worker                                        *output, isSeparable, infoLog))
1933*8975f5c5SAndroid Build Coastguard Worker             {
1934*8975f5c5SAndroid Build Coastguard Worker                 match = true;
1935*8975f5c5SAndroid Build Coastguard Worker                 break;
1936*8975f5c5SAndroid Build Coastguard Worker             }
1937*8975f5c5SAndroid Build Coastguard Worker         }
1938*8975f5c5SAndroid Build Coastguard Worker 
1939*8975f5c5SAndroid Build Coastguard Worker         // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1940*8975f5c5SAndroid Build Coastguard Worker         // whether the input is statically used - a statically used input should fail this test even
1941*8975f5c5SAndroid Build Coastguard Worker         // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1942*8975f5c5SAndroid Build Coastguard Worker         if (!match && input->staticUse)
1943*8975f5c5SAndroid Build Coastguard Worker         {
1944*8975f5c5SAndroid Build Coastguard Worker             const std::string &name =
1945*8975f5c5SAndroid Build Coastguard Worker                 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1946*8975f5c5SAndroid Build Coastguard Worker             infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1947*8975f5c5SAndroid Build Coastguard Worker                     << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1948*8975f5c5SAndroid Build Coastguard Worker             return false;
1949*8975f5c5SAndroid Build Coastguard Worker         }
1950*8975f5c5SAndroid Build Coastguard Worker     }
1951*8975f5c5SAndroid Build Coastguard Worker 
1952*8975f5c5SAndroid Build Coastguard Worker     return true;
1953*8975f5c5SAndroid Build Coastguard Worker }
1954*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1955*8975f5c5SAndroid Build Coastguard Worker LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1956*8975f5c5SAndroid Build Coastguard Worker                                                const sh::ShaderVariable &variable2,
1957*8975f5c5SAndroid Build Coastguard Worker                                                bool validatePrecision,
1958*8975f5c5SAndroid Build Coastguard Worker                                                bool treatVariable1AsNonArray,
1959*8975f5c5SAndroid Build Coastguard Worker                                                bool treatVariable2AsNonArray,
1960*8975f5c5SAndroid Build Coastguard Worker                                                std::string *mismatchedStructOrBlockMemberName)
1961*8975f5c5SAndroid Build Coastguard Worker {
1962*8975f5c5SAndroid Build Coastguard Worker     if (variable1.type != variable2.type)
1963*8975f5c5SAndroid Build Coastguard Worker     {
1964*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::TYPE_MISMATCH;
1965*8975f5c5SAndroid Build Coastguard Worker     }
1966*8975f5c5SAndroid Build Coastguard Worker 
1967*8975f5c5SAndroid Build Coastguard Worker     bool variable1IsArray = variable1.isArray();
1968*8975f5c5SAndroid Build Coastguard Worker     bool variable2IsArray = variable2.isArray();
1969*8975f5c5SAndroid Build Coastguard Worker     if (treatVariable1AsNonArray)
1970*8975f5c5SAndroid Build Coastguard Worker     {
1971*8975f5c5SAndroid Build Coastguard Worker         ASSERT(variable1IsArray);
1972*8975f5c5SAndroid Build Coastguard Worker         variable1IsArray = false;
1973*8975f5c5SAndroid Build Coastguard Worker     }
1974*8975f5c5SAndroid Build Coastguard Worker     if (treatVariable2AsNonArray)
1975*8975f5c5SAndroid Build Coastguard Worker     {
1976*8975f5c5SAndroid Build Coastguard Worker         ASSERT(variable2IsArray);
1977*8975f5c5SAndroid Build Coastguard Worker         variable2IsArray = false;
1978*8975f5c5SAndroid Build Coastguard Worker     }
1979*8975f5c5SAndroid Build Coastguard Worker     // TODO(anglebug.com/42264094): Investigate interactions with arrays-of-arrays.
1980*8975f5c5SAndroid Build Coastguard Worker     if (variable1IsArray != variable2IsArray)
1981*8975f5c5SAndroid Build Coastguard Worker     {
1982*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::ARRAYNESS_MISMATCH;
1983*8975f5c5SAndroid Build Coastguard Worker     }
1984*8975f5c5SAndroid Build Coastguard Worker     if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1985*8975f5c5SAndroid Build Coastguard Worker         variable1.arraySizes != variable2.arraySizes)
1986*8975f5c5SAndroid Build Coastguard Worker     {
1987*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1988*8975f5c5SAndroid Build Coastguard Worker     }
1989*8975f5c5SAndroid Build Coastguard Worker     if (validatePrecision && variable1.precision != variable2.precision)
1990*8975f5c5SAndroid Build Coastguard Worker     {
1991*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::PRECISION_MISMATCH;
1992*8975f5c5SAndroid Build Coastguard Worker     }
1993*8975f5c5SAndroid Build Coastguard Worker     if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1994*8975f5c5SAndroid Build Coastguard Worker         variable1.structOrBlockName != variable2.structOrBlockName)
1995*8975f5c5SAndroid Build Coastguard Worker     {
1996*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::STRUCT_NAME_MISMATCH;
1997*8975f5c5SAndroid Build Coastguard Worker     }
1998*8975f5c5SAndroid Build Coastguard Worker     if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1999*8975f5c5SAndroid Build Coastguard Worker     {
2000*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::FORMAT_MISMATCH;
2001*8975f5c5SAndroid Build Coastguard Worker     }
2002*8975f5c5SAndroid Build Coastguard Worker 
2003*8975f5c5SAndroid Build Coastguard Worker     if (variable1.fields.size() != variable2.fields.size())
2004*8975f5c5SAndroid Build Coastguard Worker     {
2005*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
2006*8975f5c5SAndroid Build Coastguard Worker     }
2007*8975f5c5SAndroid Build Coastguard Worker     const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
2008*8975f5c5SAndroid Build Coastguard Worker     for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2009*8975f5c5SAndroid Build Coastguard Worker     {
2010*8975f5c5SAndroid Build Coastguard Worker         const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2011*8975f5c5SAndroid Build Coastguard Worker         const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
2012*8975f5c5SAndroid Build Coastguard Worker 
2013*8975f5c5SAndroid Build Coastguard Worker         if (member1.name != member2.name)
2014*8975f5c5SAndroid Build Coastguard Worker         {
2015*8975f5c5SAndroid Build Coastguard Worker             return LinkMismatchError::FIELD_NAME_MISMATCH;
2016*8975f5c5SAndroid Build Coastguard Worker         }
2017*8975f5c5SAndroid Build Coastguard Worker 
2018*8975f5c5SAndroid Build Coastguard Worker         if (member1.interpolation != member2.interpolation)
2019*8975f5c5SAndroid Build Coastguard Worker         {
2020*8975f5c5SAndroid Build Coastguard Worker             return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
2021*8975f5c5SAndroid Build Coastguard Worker         }
2022*8975f5c5SAndroid Build Coastguard Worker 
2023*8975f5c5SAndroid Build Coastguard Worker         if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
2024*8975f5c5SAndroid Build Coastguard Worker         {
2025*8975f5c5SAndroid Build Coastguard Worker             if (member1.location != member2.location)
2026*8975f5c5SAndroid Build Coastguard Worker             {
2027*8975f5c5SAndroid Build Coastguard Worker                 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
2028*8975f5c5SAndroid Build Coastguard Worker             }
2029*8975f5c5SAndroid Build Coastguard Worker 
2030*8975f5c5SAndroid Build Coastguard Worker             if (member1.structOrBlockName != member2.structOrBlockName)
2031*8975f5c5SAndroid Build Coastguard Worker             {
2032*8975f5c5SAndroid Build Coastguard Worker                 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
2033*8975f5c5SAndroid Build Coastguard Worker             }
2034*8975f5c5SAndroid Build Coastguard Worker         }
2035*8975f5c5SAndroid Build Coastguard Worker 
2036*8975f5c5SAndroid Build Coastguard Worker         LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
2037*8975f5c5SAndroid Build Coastguard Worker             member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
2038*8975f5c5SAndroid Build Coastguard Worker         if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
2039*8975f5c5SAndroid Build Coastguard Worker         {
2040*8975f5c5SAndroid Build Coastguard Worker             AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2041*8975f5c5SAndroid Build Coastguard Worker             return linkErrorOnField;
2042*8975f5c5SAndroid Build Coastguard Worker         }
2043*8975f5c5SAndroid Build Coastguard Worker     }
2044*8975f5c5SAndroid Build Coastguard Worker 
2045*8975f5c5SAndroid Build Coastguard Worker     return LinkMismatchError::NO_MISMATCH;
2046*8975f5c5SAndroid Build Coastguard Worker }
2047*8975f5c5SAndroid Build Coastguard Worker 
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)2048*8975f5c5SAndroid Build Coastguard Worker void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
2049*8975f5c5SAndroid Build Coastguard Worker {
2050*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mismatchedFieldName);
2051*8975f5c5SAndroid Build Coastguard Worker     if (mismatchedFieldName->empty())
2052*8975f5c5SAndroid Build Coastguard Worker     {
2053*8975f5c5SAndroid Build Coastguard Worker         *mismatchedFieldName = parentName;
2054*8975f5c5SAndroid Build Coastguard Worker     }
2055*8975f5c5SAndroid Build Coastguard Worker     else
2056*8975f5c5SAndroid Build Coastguard Worker     {
2057*8975f5c5SAndroid Build Coastguard Worker         std::ostringstream stream;
2058*8975f5c5SAndroid Build Coastguard Worker         stream << parentName << "." << *mismatchedFieldName;
2059*8975f5c5SAndroid Build Coastguard Worker         *mismatchedFieldName = stream.str();
2060*8975f5c5SAndroid Build Coastguard Worker     }
2061*8975f5c5SAndroid Build Coastguard Worker }
2062*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)2063*8975f5c5SAndroid Build Coastguard Worker bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
2064*8975f5c5SAndroid Build Coastguard Worker                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
2065*8975f5c5SAndroid Build Coastguard Worker                                           int vertexShaderVersion,
2066*8975f5c5SAndroid Build Coastguard Worker                                           InfoLog &infoLog)
2067*8975f5c5SAndroid Build Coastguard Worker {
2068*8975f5c5SAndroid Build Coastguard Worker     bool glPositionIsInvariant   = false;
2069*8975f5c5SAndroid Build Coastguard Worker     bool glPointSizeIsInvariant  = false;
2070*8975f5c5SAndroid Build Coastguard Worker     bool glFragCoordIsInvariant  = false;
2071*8975f5c5SAndroid Build Coastguard Worker     bool glPointCoordIsInvariant = false;
2072*8975f5c5SAndroid Build Coastguard Worker 
2073*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &varying : vertexVaryings)
2074*8975f5c5SAndroid Build Coastguard Worker     {
2075*8975f5c5SAndroid Build Coastguard Worker         if (!varying.isBuiltIn())
2076*8975f5c5SAndroid Build Coastguard Worker         {
2077*8975f5c5SAndroid Build Coastguard Worker             continue;
2078*8975f5c5SAndroid Build Coastguard Worker         }
2079*8975f5c5SAndroid Build Coastguard Worker         if (varying.name.compare("gl_Position") == 0)
2080*8975f5c5SAndroid Build Coastguard Worker         {
2081*8975f5c5SAndroid Build Coastguard Worker             glPositionIsInvariant = varying.isInvariant;
2082*8975f5c5SAndroid Build Coastguard Worker         }
2083*8975f5c5SAndroid Build Coastguard Worker         else if (varying.name.compare("gl_PointSize") == 0)
2084*8975f5c5SAndroid Build Coastguard Worker         {
2085*8975f5c5SAndroid Build Coastguard Worker             glPointSizeIsInvariant = varying.isInvariant;
2086*8975f5c5SAndroid Build Coastguard Worker         }
2087*8975f5c5SAndroid Build Coastguard Worker     }
2088*8975f5c5SAndroid Build Coastguard Worker 
2089*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &varying : fragmentVaryings)
2090*8975f5c5SAndroid Build Coastguard Worker     {
2091*8975f5c5SAndroid Build Coastguard Worker         if (!varying.isBuiltIn())
2092*8975f5c5SAndroid Build Coastguard Worker         {
2093*8975f5c5SAndroid Build Coastguard Worker             continue;
2094*8975f5c5SAndroid Build Coastguard Worker         }
2095*8975f5c5SAndroid Build Coastguard Worker         if (varying.name.compare("gl_FragCoord") == 0)
2096*8975f5c5SAndroid Build Coastguard Worker         {
2097*8975f5c5SAndroid Build Coastguard Worker             glFragCoordIsInvariant = varying.isInvariant;
2098*8975f5c5SAndroid Build Coastguard Worker         }
2099*8975f5c5SAndroid Build Coastguard Worker         else if (varying.name.compare("gl_PointCoord") == 0)
2100*8975f5c5SAndroid Build Coastguard Worker         {
2101*8975f5c5SAndroid Build Coastguard Worker             glPointCoordIsInvariant = varying.isInvariant;
2102*8975f5c5SAndroid Build Coastguard Worker         }
2103*8975f5c5SAndroid Build Coastguard Worker     }
2104*8975f5c5SAndroid Build Coastguard Worker 
2105*8975f5c5SAndroid Build Coastguard Worker     // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2106*8975f5c5SAndroid Build Coastguard Worker     // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2107*8975f5c5SAndroid Build Coastguard Worker     // Not requiring invariance to match is supported by:
2108*8975f5c5SAndroid Build Coastguard Worker     // dEQP, WebGL CTS, Nexus 5X GLES
2109*8975f5c5SAndroid Build Coastguard Worker     if (glFragCoordIsInvariant && !glPositionIsInvariant)
2110*8975f5c5SAndroid Build Coastguard Worker     {
2111*8975f5c5SAndroid Build Coastguard Worker         infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2112*8975f5c5SAndroid Build Coastguard Worker                    "declared invariant.";
2113*8975f5c5SAndroid Build Coastguard Worker         return false;
2114*8975f5c5SAndroid Build Coastguard Worker     }
2115*8975f5c5SAndroid Build Coastguard Worker     if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2116*8975f5c5SAndroid Build Coastguard Worker     {
2117*8975f5c5SAndroid Build Coastguard Worker         infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2118*8975f5c5SAndroid Build Coastguard Worker                    "declared invariant.";
2119*8975f5c5SAndroid Build Coastguard Worker         return false;
2120*8975f5c5SAndroid Build Coastguard Worker     }
2121*8975f5c5SAndroid Build Coastguard Worker 
2122*8975f5c5SAndroid Build Coastguard Worker     return true;
2123*8975f5c5SAndroid Build Coastguard Worker }
2124*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)2125*8975f5c5SAndroid Build Coastguard Worker bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
2126*8975f5c5SAndroid Build Coastguard Worker                                  const std::vector<sh::ShaderVariable> &inputVaryings,
2127*8975f5c5SAndroid Build Coastguard Worker                                  ShaderType outputShaderType,
2128*8975f5c5SAndroid Build Coastguard Worker                                  ShaderType inputShaderType,
2129*8975f5c5SAndroid Build Coastguard Worker                                  int outputShaderVersion,
2130*8975f5c5SAndroid Build Coastguard Worker                                  int inputShaderVersion,
2131*8975f5c5SAndroid Build Coastguard Worker                                  InfoLog &infoLog)
2132*8975f5c5SAndroid Build Coastguard Worker {
2133*8975f5c5SAndroid Build Coastguard Worker     ASSERT(outputShaderVersion == inputShaderVersion);
2134*8975f5c5SAndroid Build Coastguard Worker 
2135*8975f5c5SAndroid Build Coastguard Worker     // Only ESSL 1.0 has restrictions on matching input and output invariance
2136*8975f5c5SAndroid Build Coastguard Worker     if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
2137*8975f5c5SAndroid Build Coastguard Worker         inputShaderType == ShaderType::Fragment)
2138*8975f5c5SAndroid Build Coastguard Worker     {
2139*8975f5c5SAndroid Build Coastguard Worker         return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
2140*8975f5c5SAndroid Build Coastguard Worker                                                     outputShaderVersion, infoLog);
2141*8975f5c5SAndroid Build Coastguard Worker     }
2142*8975f5c5SAndroid Build Coastguard Worker 
2143*8975f5c5SAndroid Build Coastguard Worker     uint32_t sizeClipDistance = 0;
2144*8975f5c5SAndroid Build Coastguard Worker     uint32_t sizeCullDistance = 0;
2145*8975f5c5SAndroid Build Coastguard Worker 
2146*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &varying : outputVaryings)
2147*8975f5c5SAndroid Build Coastguard Worker     {
2148*8975f5c5SAndroid Build Coastguard Worker         if (!varying.isBuiltIn())
2149*8975f5c5SAndroid Build Coastguard Worker         {
2150*8975f5c5SAndroid Build Coastguard Worker             continue;
2151*8975f5c5SAndroid Build Coastguard Worker         }
2152*8975f5c5SAndroid Build Coastguard Worker         if (varying.name.compare("gl_ClipDistance") == 0)
2153*8975f5c5SAndroid Build Coastguard Worker         {
2154*8975f5c5SAndroid Build Coastguard Worker             sizeClipDistance = varying.getOutermostArraySize();
2155*8975f5c5SAndroid Build Coastguard Worker         }
2156*8975f5c5SAndroid Build Coastguard Worker         else if (varying.name.compare("gl_CullDistance") == 0)
2157*8975f5c5SAndroid Build Coastguard Worker         {
2158*8975f5c5SAndroid Build Coastguard Worker             sizeCullDistance = varying.getOutermostArraySize();
2159*8975f5c5SAndroid Build Coastguard Worker         }
2160*8975f5c5SAndroid Build Coastguard Worker     }
2161*8975f5c5SAndroid Build Coastguard Worker 
2162*8975f5c5SAndroid Build Coastguard Worker     for (const sh::ShaderVariable &varying : inputVaryings)
2163*8975f5c5SAndroid Build Coastguard Worker     {
2164*8975f5c5SAndroid Build Coastguard Worker         if (!varying.isBuiltIn())
2165*8975f5c5SAndroid Build Coastguard Worker         {
2166*8975f5c5SAndroid Build Coastguard Worker             continue;
2167*8975f5c5SAndroid Build Coastguard Worker         }
2168*8975f5c5SAndroid Build Coastguard Worker         if (varying.name.compare("gl_ClipDistance") == 0)
2169*8975f5c5SAndroid Build Coastguard Worker         {
2170*8975f5c5SAndroid Build Coastguard Worker             if (sizeClipDistance != varying.getOutermostArraySize())
2171*8975f5c5SAndroid Build Coastguard Worker             {
2172*8975f5c5SAndroid Build Coastguard Worker                 infoLog
2173*8975f5c5SAndroid Build Coastguard Worker                     << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2174*8975f5c5SAndroid Build Coastguard Worker                        "the array must have the same size as in the previous shader stage. "
2175*8975f5c5SAndroid Build Coastguard Worker                     << "Output size " << sizeClipDistance << ", input size "
2176*8975f5c5SAndroid Build Coastguard Worker                     << varying.getOutermostArraySize() << ".";
2177*8975f5c5SAndroid Build Coastguard Worker                 return false;
2178*8975f5c5SAndroid Build Coastguard Worker             }
2179*8975f5c5SAndroid Build Coastguard Worker         }
2180*8975f5c5SAndroid Build Coastguard Worker         else if (varying.name.compare("gl_CullDistance") == 0)
2181*8975f5c5SAndroid Build Coastguard Worker         {
2182*8975f5c5SAndroid Build Coastguard Worker             if (sizeCullDistance != varying.getOutermostArraySize())
2183*8975f5c5SAndroid Build Coastguard Worker             {
2184*8975f5c5SAndroid Build Coastguard Worker                 infoLog
2185*8975f5c5SAndroid Build Coastguard Worker                     << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2186*8975f5c5SAndroid Build Coastguard Worker                        "the array must have the same size as in the previous shader stage. "
2187*8975f5c5SAndroid Build Coastguard Worker                     << "Output size " << sizeCullDistance << ", input size "
2188*8975f5c5SAndroid Build Coastguard Worker                     << varying.getOutermostArraySize() << ".";
2189*8975f5c5SAndroid Build Coastguard Worker 
2190*8975f5c5SAndroid Build Coastguard Worker                 return false;
2191*8975f5c5SAndroid Build Coastguard Worker             }
2192*8975f5c5SAndroid Build Coastguard Worker         }
2193*8975f5c5SAndroid Build Coastguard Worker     }
2194*8975f5c5SAndroid Build Coastguard Worker     return true;
2195*8975f5c5SAndroid Build Coastguard Worker }
2196*8975f5c5SAndroid Build Coastguard Worker 
LogAmbiguousFieldLinkMismatch(InfoLog & infoLog,const std::string & blockName1,const std::string & blockName2,const std::string & fieldName,ShaderType shaderType1,ShaderType shaderType2)2197*8975f5c5SAndroid Build Coastguard Worker void LogAmbiguousFieldLinkMismatch(InfoLog &infoLog,
2198*8975f5c5SAndroid Build Coastguard Worker                                    const std::string &blockName1,
2199*8975f5c5SAndroid Build Coastguard Worker                                    const std::string &blockName2,
2200*8975f5c5SAndroid Build Coastguard Worker                                    const std::string &fieldName,
2201*8975f5c5SAndroid Build Coastguard Worker                                    ShaderType shaderType1,
2202*8975f5c5SAndroid Build Coastguard Worker                                    ShaderType shaderType2)
2203*8975f5c5SAndroid Build Coastguard Worker {
2204*8975f5c5SAndroid Build Coastguard Worker     infoLog << "Ambiguous field '" << fieldName << "' in blocks '" << blockName1 << "' ("
2205*8975f5c5SAndroid Build Coastguard Worker             << GetShaderTypeString(shaderType1) << " shader) and '" << blockName2 << "' ("
2206*8975f5c5SAndroid Build Coastguard Worker             << GetShaderTypeString(shaderType2) << " shader) which don't have instance names.";
2207*8975f5c5SAndroid Build Coastguard Worker }
2208*8975f5c5SAndroid Build Coastguard Worker 
ValidateInstancelessGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * instancelessBlocksFields,InfoLog & infoLog)2209*8975f5c5SAndroid Build Coastguard Worker bool ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2210*8975f5c5SAndroid Build Coastguard Worker     const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2211*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderType,
2212*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockMap *instancelessBlocksFields,
2213*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog)
2214*8975f5c5SAndroid Build Coastguard Worker {
2215*8975f5c5SAndroid Build Coastguard Worker     ASSERT(instancelessBlocksFields);
2216*8975f5c5SAndroid Build Coastguard Worker 
2217*8975f5c5SAndroid Build Coastguard Worker     for (const sh::InterfaceBlock &block : interfaceBlocks)
2218*8975f5c5SAndroid Build Coastguard Worker     {
2219*8975f5c5SAndroid Build Coastguard Worker         if (!block.instanceName.empty())
2220*8975f5c5SAndroid Build Coastguard Worker         {
2221*8975f5c5SAndroid Build Coastguard Worker             continue;
2222*8975f5c5SAndroid Build Coastguard Worker         }
2223*8975f5c5SAndroid Build Coastguard Worker 
2224*8975f5c5SAndroid Build Coastguard Worker         for (const sh::ShaderVariable &field : block.fields)
2225*8975f5c5SAndroid Build Coastguard Worker         {
2226*8975f5c5SAndroid Build Coastguard Worker             const auto &entry = instancelessBlocksFields->find(field.name);
2227*8975f5c5SAndroid Build Coastguard Worker             if (entry != instancelessBlocksFields->end())
2228*8975f5c5SAndroid Build Coastguard Worker             {
2229*8975f5c5SAndroid Build Coastguard Worker                 const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2230*8975f5c5SAndroid Build Coastguard Worker                 if (block.name != linkedBlock.name)
2231*8975f5c5SAndroid Build Coastguard Worker                 {
2232*8975f5c5SAndroid Build Coastguard Worker                     LogAmbiguousFieldLinkMismatch(infoLog, block.name, linkedBlock.name, field.name,
2233*8975f5c5SAndroid Build Coastguard Worker                                                   entry->second.first, shaderType);
2234*8975f5c5SAndroid Build Coastguard Worker                     return false;
2235*8975f5c5SAndroid Build Coastguard Worker                 }
2236*8975f5c5SAndroid Build Coastguard Worker             }
2237*8975f5c5SAndroid Build Coastguard Worker             else
2238*8975f5c5SAndroid Build Coastguard Worker             {
2239*8975f5c5SAndroid Build Coastguard Worker                 (*instancelessBlocksFields)[field.name] = std::make_pair(shaderType, &block);
2240*8975f5c5SAndroid Build Coastguard Worker             }
2241*8975f5c5SAndroid Build Coastguard Worker         }
2242*8975f5c5SAndroid Build Coastguard Worker     }
2243*8975f5c5SAndroid Build Coastguard Worker 
2244*8975f5c5SAndroid Build Coastguard Worker     return true;
2245*8975f5c5SAndroid Build Coastguard Worker }
2246*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateInterfaceBlockFields(const sh::ShaderVariable & blockField1,const sh::ShaderVariable & blockField2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2247*8975f5c5SAndroid Build Coastguard Worker LinkMismatchError LinkValidateInterfaceBlockFields(const sh::ShaderVariable &blockField1,
2248*8975f5c5SAndroid Build Coastguard Worker                                                    const sh::ShaderVariable &blockField2,
2249*8975f5c5SAndroid Build Coastguard Worker                                                    bool webglCompatibility,
2250*8975f5c5SAndroid Build Coastguard Worker                                                    std::string *mismatchedBlockFieldName)
2251*8975f5c5SAndroid Build Coastguard Worker {
2252*8975f5c5SAndroid Build Coastguard Worker     if (blockField1.name != blockField2.name)
2253*8975f5c5SAndroid Build Coastguard Worker     {
2254*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::FIELD_NAME_MISMATCH;
2255*8975f5c5SAndroid Build Coastguard Worker     }
2256*8975f5c5SAndroid Build Coastguard Worker 
2257*8975f5c5SAndroid Build Coastguard Worker     // If webgl, validate precision of UBO fields, otherwise don't.  See Khronos bug 10287.
2258*8975f5c5SAndroid Build Coastguard Worker     LinkMismatchError linkError = LinkValidateProgramVariables(
2259*8975f5c5SAndroid Build Coastguard Worker         blockField1, blockField2, webglCompatibility, false, false, mismatchedBlockFieldName);
2260*8975f5c5SAndroid Build Coastguard Worker     if (linkError != LinkMismatchError::NO_MISMATCH)
2261*8975f5c5SAndroid Build Coastguard Worker     {
2262*8975f5c5SAndroid Build Coastguard Worker         AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2263*8975f5c5SAndroid Build Coastguard Worker         return linkError;
2264*8975f5c5SAndroid Build Coastguard Worker     }
2265*8975f5c5SAndroid Build Coastguard Worker 
2266*8975f5c5SAndroid Build Coastguard Worker     if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
2267*8975f5c5SAndroid Build Coastguard Worker     {
2268*8975f5c5SAndroid Build Coastguard Worker         AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2269*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::MATRIX_PACKING_MISMATCH;
2270*8975f5c5SAndroid Build Coastguard Worker     }
2271*8975f5c5SAndroid Build Coastguard Worker 
2272*8975f5c5SAndroid Build Coastguard Worker     return LinkMismatchError::NO_MISMATCH;
2273*8975f5c5SAndroid Build Coastguard Worker }
2274*8975f5c5SAndroid Build Coastguard Worker 
AreMatchingInterfaceBlocks(const sh::InterfaceBlock & interfaceBlock1,const sh::InterfaceBlock & interfaceBlock2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2275*8975f5c5SAndroid Build Coastguard Worker LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2276*8975f5c5SAndroid Build Coastguard Worker                                              const sh::InterfaceBlock &interfaceBlock2,
2277*8975f5c5SAndroid Build Coastguard Worker                                              bool webglCompatibility,
2278*8975f5c5SAndroid Build Coastguard Worker                                              std::string *mismatchedBlockFieldName)
2279*8975f5c5SAndroid Build Coastguard Worker {
2280*8975f5c5SAndroid Build Coastguard Worker     // validate blocks for the same member types
2281*8975f5c5SAndroid Build Coastguard Worker     if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
2282*8975f5c5SAndroid Build Coastguard Worker     {
2283*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
2284*8975f5c5SAndroid Build Coastguard Worker     }
2285*8975f5c5SAndroid Build Coastguard Worker     if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
2286*8975f5c5SAndroid Build Coastguard Worker     {
2287*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2288*8975f5c5SAndroid Build Coastguard Worker     }
2289*8975f5c5SAndroid Build Coastguard Worker     if (interfaceBlock1.layout != interfaceBlock2.layout ||
2290*8975f5c5SAndroid Build Coastguard Worker         interfaceBlock1.binding != interfaceBlock2.binding)
2291*8975f5c5SAndroid Build Coastguard Worker     {
2292*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
2293*8975f5c5SAndroid Build Coastguard Worker     }
2294*8975f5c5SAndroid Build Coastguard Worker     if (interfaceBlock1.instanceName.empty() != interfaceBlock2.instanceName.empty())
2295*8975f5c5SAndroid Build Coastguard Worker     {
2296*8975f5c5SAndroid Build Coastguard Worker         return LinkMismatchError::INSTANCE_NAME_MISMATCH;
2297*8975f5c5SAndroid Build Coastguard Worker     }
2298*8975f5c5SAndroid Build Coastguard Worker     const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
2299*8975f5c5SAndroid Build Coastguard Worker     for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2300*8975f5c5SAndroid Build Coastguard Worker     {
2301*8975f5c5SAndroid Build Coastguard Worker         const sh::ShaderVariable &member1 = interfaceBlock1.fields[blockMemberIndex];
2302*8975f5c5SAndroid Build Coastguard Worker         const sh::ShaderVariable &member2 = interfaceBlock2.fields[blockMemberIndex];
2303*8975f5c5SAndroid Build Coastguard Worker 
2304*8975f5c5SAndroid Build Coastguard Worker         LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2305*8975f5c5SAndroid Build Coastguard Worker             member1, member2, webglCompatibility, mismatchedBlockFieldName);
2306*8975f5c5SAndroid Build Coastguard Worker         if (linkError != LinkMismatchError::NO_MISMATCH)
2307*8975f5c5SAndroid Build Coastguard Worker         {
2308*8975f5c5SAndroid Build Coastguard Worker             return linkError;
2309*8975f5c5SAndroid Build Coastguard Worker         }
2310*8975f5c5SAndroid Build Coastguard Worker     }
2311*8975f5c5SAndroid Build Coastguard Worker     return LinkMismatchError::NO_MISMATCH;
2312*8975f5c5SAndroid Build Coastguard Worker }
2313*8975f5c5SAndroid Build Coastguard Worker 
InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * linkedInterfaceBlocks)2314*8975f5c5SAndroid Build Coastguard Worker void InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2315*8975f5c5SAndroid Build Coastguard Worker                                  ShaderType shaderType,
2316*8975f5c5SAndroid Build Coastguard Worker                                  InterfaceBlockMap *linkedInterfaceBlocks)
2317*8975f5c5SAndroid Build Coastguard Worker {
2318*8975f5c5SAndroid Build Coastguard Worker     ASSERT(linkedInterfaceBlocks);
2319*8975f5c5SAndroid Build Coastguard Worker 
2320*8975f5c5SAndroid Build Coastguard Worker     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
2321*8975f5c5SAndroid Build Coastguard Worker     {
2322*8975f5c5SAndroid Build Coastguard Worker         (*linkedInterfaceBlocks)[interfaceBlock.name] = std::make_pair(shaderType, &interfaceBlock);
2323*8975f5c5SAndroid Build Coastguard Worker     }
2324*8975f5c5SAndroid Build Coastguard Worker }
2325*8975f5c5SAndroid Build Coastguard Worker 
ValidateGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocksToLink,ShaderType shaderType,bool webglCompatibility,InterfaceBlockMap * linkedBlocks,InfoLog & infoLog)2326*8975f5c5SAndroid Build Coastguard Worker bool ValidateGraphicsInterfaceBlocksPerShader(
2327*8975f5c5SAndroid Build Coastguard Worker     const std::vector<sh::InterfaceBlock> &interfaceBlocksToLink,
2328*8975f5c5SAndroid Build Coastguard Worker     ShaderType shaderType,
2329*8975f5c5SAndroid Build Coastguard Worker     bool webglCompatibility,
2330*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockMap *linkedBlocks,
2331*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog)
2332*8975f5c5SAndroid Build Coastguard Worker {
2333*8975f5c5SAndroid Build Coastguard Worker     ASSERT(linkedBlocks);
2334*8975f5c5SAndroid Build Coastguard Worker 
2335*8975f5c5SAndroid Build Coastguard Worker     for (const sh::InterfaceBlock &block : interfaceBlocksToLink)
2336*8975f5c5SAndroid Build Coastguard Worker     {
2337*8975f5c5SAndroid Build Coastguard Worker         const auto &entry = linkedBlocks->find(block.name);
2338*8975f5c5SAndroid Build Coastguard Worker         if (entry != linkedBlocks->end())
2339*8975f5c5SAndroid Build Coastguard Worker         {
2340*8975f5c5SAndroid Build Coastguard Worker             const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2341*8975f5c5SAndroid Build Coastguard Worker             std::string mismatchedStructFieldName;
2342*8975f5c5SAndroid Build Coastguard Worker             LinkMismatchError linkError = AreMatchingInterfaceBlocks(
2343*8975f5c5SAndroid Build Coastguard Worker                 block, linkedBlock, webglCompatibility, &mismatchedStructFieldName);
2344*8975f5c5SAndroid Build Coastguard Worker             if (linkError != LinkMismatchError::NO_MISMATCH)
2345*8975f5c5SAndroid Build Coastguard Worker             {
2346*8975f5c5SAndroid Build Coastguard Worker                 LogLinkMismatch(infoLog, block.name, GetInterfaceBlockTypeString(block.blockType),
2347*8975f5c5SAndroid Build Coastguard Worker                                 linkError, mismatchedStructFieldName, entry->second.first,
2348*8975f5c5SAndroid Build Coastguard Worker                                 shaderType);
2349*8975f5c5SAndroid Build Coastguard Worker                 return false;
2350*8975f5c5SAndroid Build Coastguard Worker             }
2351*8975f5c5SAndroid Build Coastguard Worker         }
2352*8975f5c5SAndroid Build Coastguard Worker         else
2353*8975f5c5SAndroid Build Coastguard Worker         {
2354*8975f5c5SAndroid Build Coastguard Worker             (*linkedBlocks)[block.name] = std::make_pair(shaderType, &block);
2355*8975f5c5SAndroid Build Coastguard Worker         }
2356*8975f5c5SAndroid Build Coastguard Worker     }
2357*8975f5c5SAndroid Build Coastguard Worker 
2358*8975f5c5SAndroid Build Coastguard Worker     return true;
2359*8975f5c5SAndroid Build Coastguard Worker }
2360*8975f5c5SAndroid Build Coastguard Worker 
ValidateInterfaceBlocksMatch(GLuint numShadersHasInterfaceBlocks,const ShaderMap<const std::vector<sh::InterfaceBlock> * > & shaderInterfaceBlocks,InfoLog & infoLog,bool webglCompatibility,InterfaceBlockMap * instancelessInterfaceBlocksFields)2361*8975f5c5SAndroid Build Coastguard Worker bool ValidateInterfaceBlocksMatch(
2362*8975f5c5SAndroid Build Coastguard Worker     GLuint numShadersHasInterfaceBlocks,
2363*8975f5c5SAndroid Build Coastguard Worker     const ShaderMap<const std::vector<sh::InterfaceBlock> *> &shaderInterfaceBlocks,
2364*8975f5c5SAndroid Build Coastguard Worker     InfoLog &infoLog,
2365*8975f5c5SAndroid Build Coastguard Worker     bool webglCompatibility,
2366*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockMap *instancelessInterfaceBlocksFields)
2367*8975f5c5SAndroid Build Coastguard Worker {
2368*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : kAllGraphicsShaderTypes)
2369*8975f5c5SAndroid Build Coastguard Worker     {
2370*8975f5c5SAndroid Build Coastguard Worker         // Validate that instanceless blocks of different names don't have fields of the same name.
2371*8975f5c5SAndroid Build Coastguard Worker         if (shaderInterfaceBlocks[shaderType] &&
2372*8975f5c5SAndroid Build Coastguard Worker             !ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2373*8975f5c5SAndroid Build Coastguard Worker                 *shaderInterfaceBlocks[shaderType], shaderType, instancelessInterfaceBlocksFields,
2374*8975f5c5SAndroid Build Coastguard Worker                 infoLog))
2375*8975f5c5SAndroid Build Coastguard Worker         {
2376*8975f5c5SAndroid Build Coastguard Worker             return false;
2377*8975f5c5SAndroid Build Coastguard Worker         }
2378*8975f5c5SAndroid Build Coastguard Worker     }
2379*8975f5c5SAndroid Build Coastguard Worker 
2380*8975f5c5SAndroid Build Coastguard Worker     if (numShadersHasInterfaceBlocks < 2u)
2381*8975f5c5SAndroid Build Coastguard Worker     {
2382*8975f5c5SAndroid Build Coastguard Worker         return true;
2383*8975f5c5SAndroid Build Coastguard Worker     }
2384*8975f5c5SAndroid Build Coastguard Worker 
2385*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!shaderInterfaceBlocks[ShaderType::Compute]);
2386*8975f5c5SAndroid Build Coastguard Worker 
2387*8975f5c5SAndroid Build Coastguard Worker     // Check that interface blocks defined in the graphics shaders are identical
2388*8975f5c5SAndroid Build Coastguard Worker 
2389*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockMap linkedInterfaceBlocks;
2390*8975f5c5SAndroid Build Coastguard Worker 
2391*8975f5c5SAndroid Build Coastguard Worker     bool interfaceBlockMapInitialized = false;
2392*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : kAllGraphicsShaderTypes)
2393*8975f5c5SAndroid Build Coastguard Worker     {
2394*8975f5c5SAndroid Build Coastguard Worker         if (!shaderInterfaceBlocks[shaderType])
2395*8975f5c5SAndroid Build Coastguard Worker         {
2396*8975f5c5SAndroid Build Coastguard Worker             continue;
2397*8975f5c5SAndroid Build Coastguard Worker         }
2398*8975f5c5SAndroid Build Coastguard Worker 
2399*8975f5c5SAndroid Build Coastguard Worker         if (!interfaceBlockMapInitialized)
2400*8975f5c5SAndroid Build Coastguard Worker         {
2401*8975f5c5SAndroid Build Coastguard Worker             InitializeInterfaceBlockMap(*shaderInterfaceBlocks[shaderType], shaderType,
2402*8975f5c5SAndroid Build Coastguard Worker                                         &linkedInterfaceBlocks);
2403*8975f5c5SAndroid Build Coastguard Worker             interfaceBlockMapInitialized = true;
2404*8975f5c5SAndroid Build Coastguard Worker         }
2405*8975f5c5SAndroid Build Coastguard Worker         else if (!ValidateGraphicsInterfaceBlocksPerShader(*shaderInterfaceBlocks[shaderType],
2406*8975f5c5SAndroid Build Coastguard Worker                                                            shaderType, webglCompatibility,
2407*8975f5c5SAndroid Build Coastguard Worker                                                            &linkedInterfaceBlocks, infoLog))
2408*8975f5c5SAndroid Build Coastguard Worker         {
2409*8975f5c5SAndroid Build Coastguard Worker             return false;
2410*8975f5c5SAndroid Build Coastguard Worker         }
2411*8975f5c5SAndroid Build Coastguard Worker     }
2412*8975f5c5SAndroid Build Coastguard Worker 
2413*8975f5c5SAndroid Build Coastguard Worker     return true;
2414*8975f5c5SAndroid Build Coastguard Worker }
2415*8975f5c5SAndroid Build Coastguard Worker 
LinkValidateProgramInterfaceBlocks(const Caps & caps,const Version & clientVersion,bool webglCompatibility,ShaderBitSet activeProgramStages,const ProgramLinkedResources & resources,InfoLog & infoLog,GLuint * combinedShaderStorageBlocksCountOut)2416*8975f5c5SAndroid Build Coastguard Worker bool LinkValidateProgramInterfaceBlocks(const Caps &caps,
2417*8975f5c5SAndroid Build Coastguard Worker                                         const Version &clientVersion,
2418*8975f5c5SAndroid Build Coastguard Worker                                         bool webglCompatibility,
2419*8975f5c5SAndroid Build Coastguard Worker                                         ShaderBitSet activeProgramStages,
2420*8975f5c5SAndroid Build Coastguard Worker                                         const ProgramLinkedResources &resources,
2421*8975f5c5SAndroid Build Coastguard Worker                                         InfoLog &infoLog,
2422*8975f5c5SAndroid Build Coastguard Worker                                         GLuint *combinedShaderStorageBlocksCountOut)
2423*8975f5c5SAndroid Build Coastguard Worker {
2424*8975f5c5SAndroid Build Coastguard Worker     ASSERT(combinedShaderStorageBlocksCountOut);
2425*8975f5c5SAndroid Build Coastguard Worker 
2426*8975f5c5SAndroid Build Coastguard Worker     GLuint combinedUniformBlocksCount                                         = 0u;
2427*8975f5c5SAndroid Build Coastguard Worker     GLuint numShadersHasUniformBlocks                                         = 0u;
2428*8975f5c5SAndroid Build Coastguard Worker     ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderUniformBlocks = {};
2429*8975f5c5SAndroid Build Coastguard Worker     InterfaceBlockMap instancelessInterfaceBlocksFields;
2430*8975f5c5SAndroid Build Coastguard Worker 
2431*8975f5c5SAndroid Build Coastguard Worker     for (ShaderType shaderType : activeProgramStages)
2432*8975f5c5SAndroid Build Coastguard Worker     {
2433*8975f5c5SAndroid Build Coastguard Worker         const std::vector<sh::InterfaceBlock> &uniformBlocks =
2434*8975f5c5SAndroid Build Coastguard Worker             resources.uniformBlockLinker.getShaderBlocks(shaderType);
2435*8975f5c5SAndroid Build Coastguard Worker         if (!uniformBlocks.empty())
2436*8975f5c5SAndroid Build Coastguard Worker         {
2437*8975f5c5SAndroid Build Coastguard Worker             if (!ValidateInterfaceBlocksCount(
2438*8975f5c5SAndroid Build Coastguard Worker                     static_cast<GLuint>(caps.maxShaderUniformBlocks[shaderType]), uniformBlocks,
2439*8975f5c5SAndroid Build Coastguard Worker                     shaderType, sh::BlockType::kBlockUniform, &combinedUniformBlocksCount, infoLog))
2440*8975f5c5SAndroid Build Coastguard Worker             {
2441*8975f5c5SAndroid Build Coastguard Worker                 return false;
2442*8975f5c5SAndroid Build Coastguard Worker             }
2443*8975f5c5SAndroid Build Coastguard Worker 
2444*8975f5c5SAndroid Build Coastguard Worker             allShaderUniformBlocks[shaderType] = &uniformBlocks;
2445*8975f5c5SAndroid Build Coastguard Worker             ++numShadersHasUniformBlocks;
2446*8975f5c5SAndroid Build Coastguard Worker         }
2447*8975f5c5SAndroid Build Coastguard Worker     }
2448*8975f5c5SAndroid Build Coastguard Worker 
2449*8975f5c5SAndroid Build Coastguard Worker     if (combinedUniformBlocksCount > static_cast<GLuint>(caps.maxCombinedUniformBlocks))
2450*8975f5c5SAndroid Build Coastguard Worker     {
2451*8975f5c5SAndroid Build Coastguard Worker         infoLog << "The sum of the number of active uniform blocks exceeds "
2452*8975f5c5SAndroid Build Coastguard Worker                    "MAX_COMBINED_UNIFORM_BLOCKS ("
2453*8975f5c5SAndroid Build Coastguard Worker                 << caps.maxCombinedUniformBlocks << ").";
2454*8975f5c5SAndroid Build Coastguard Worker         return false;
2455*8975f5c5SAndroid Build Coastguard Worker     }
2456*8975f5c5SAndroid Build Coastguard Worker 
2457*8975f5c5SAndroid Build Coastguard Worker     if (!ValidateInterfaceBlocksMatch(numShadersHasUniformBlocks, allShaderUniformBlocks, infoLog,
2458*8975f5c5SAndroid Build Coastguard Worker                                       webglCompatibility, &instancelessInterfaceBlocksFields))
2459*8975f5c5SAndroid Build Coastguard Worker     {
2460*8975f5c5SAndroid Build Coastguard Worker         return false;
2461*8975f5c5SAndroid Build Coastguard Worker     }
2462*8975f5c5SAndroid Build Coastguard Worker 
2463*8975f5c5SAndroid Build Coastguard Worker     if (clientVersion >= Version(3, 1))
2464*8975f5c5SAndroid Build Coastguard Worker     {
2465*8975f5c5SAndroid Build Coastguard Worker         *combinedShaderStorageBlocksCountOut                                      = 0u;
2466*8975f5c5SAndroid Build Coastguard Worker         GLuint numShadersHasShaderStorageBlocks                                   = 0u;
2467*8975f5c5SAndroid Build Coastguard Worker         ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderStorageBlocks = {};
2468*8975f5c5SAndroid Build Coastguard Worker         for (ShaderType shaderType : activeProgramStages)
2469*8975f5c5SAndroid Build Coastguard Worker         {
2470*8975f5c5SAndroid Build Coastguard Worker             const std::vector<sh::InterfaceBlock> &shaderStorageBlocks =
2471*8975f5c5SAndroid Build Coastguard Worker                 resources.shaderStorageBlockLinker.getShaderBlocks(shaderType);
2472*8975f5c5SAndroid Build Coastguard Worker             if (!shaderStorageBlocks.empty())
2473*8975f5c5SAndroid Build Coastguard Worker             {
2474*8975f5c5SAndroid Build Coastguard Worker                 if (!ValidateInterfaceBlocksCount(
2475*8975f5c5SAndroid Build Coastguard Worker                         static_cast<GLuint>(caps.maxShaderStorageBlocks[shaderType]),
2476*8975f5c5SAndroid Build Coastguard Worker                         shaderStorageBlocks, shaderType, sh::BlockType::kBlockBuffer,
2477*8975f5c5SAndroid Build Coastguard Worker                         combinedShaderStorageBlocksCountOut, infoLog))
2478*8975f5c5SAndroid Build Coastguard Worker                 {
2479*8975f5c5SAndroid Build Coastguard Worker                     return false;
2480*8975f5c5SAndroid Build Coastguard Worker                 }
2481*8975f5c5SAndroid Build Coastguard Worker 
2482*8975f5c5SAndroid Build Coastguard Worker                 allShaderStorageBlocks[shaderType] = &shaderStorageBlocks;
2483*8975f5c5SAndroid Build Coastguard Worker                 ++numShadersHasShaderStorageBlocks;
2484*8975f5c5SAndroid Build Coastguard Worker             }
2485*8975f5c5SAndroid Build Coastguard Worker         }
2486*8975f5c5SAndroid Build Coastguard Worker 
2487*8975f5c5SAndroid Build Coastguard Worker         if (*combinedShaderStorageBlocksCountOut >
2488*8975f5c5SAndroid Build Coastguard Worker             static_cast<GLuint>(caps.maxCombinedShaderStorageBlocks))
2489*8975f5c5SAndroid Build Coastguard Worker         {
2490*8975f5c5SAndroid Build Coastguard Worker             infoLog << "The sum of the number of active shader storage blocks exceeds "
2491*8975f5c5SAndroid Build Coastguard Worker                        "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2492*8975f5c5SAndroid Build Coastguard Worker                     << caps.maxCombinedShaderStorageBlocks << ").";
2493*8975f5c5SAndroid Build Coastguard Worker             return false;
2494*8975f5c5SAndroid Build Coastguard Worker         }
2495*8975f5c5SAndroid Build Coastguard Worker 
2496*8975f5c5SAndroid Build Coastguard Worker         if (!ValidateInterfaceBlocksMatch(numShadersHasShaderStorageBlocks, allShaderStorageBlocks,
2497*8975f5c5SAndroid Build Coastguard Worker                                           infoLog, webglCompatibility,
2498*8975f5c5SAndroid Build Coastguard Worker                                           &instancelessInterfaceBlocksFields))
2499*8975f5c5SAndroid Build Coastguard Worker         {
2500*8975f5c5SAndroid Build Coastguard Worker             return false;
2501*8975f5c5SAndroid Build Coastguard Worker         }
2502*8975f5c5SAndroid Build Coastguard Worker     }
2503*8975f5c5SAndroid Build Coastguard Worker 
2504*8975f5c5SAndroid Build Coastguard Worker     return true;
2505*8975f5c5SAndroid Build Coastguard Worker }
2506*8975f5c5SAndroid Build Coastguard Worker 
2507*8975f5c5SAndroid Build Coastguard Worker }  // namespace gl
2508