• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "ProgramData.h"
18 #include "apigen-codec-common/glUtils.h"
19 
20 #include "base/Lookup.h"
21 #include "base/StreamSerializing.h"
22 #include "ANGLEShaderParser.h"
23 #include "GLcommon/GLutils.h"
24 #include "GLcommon/GLESmacros.h"
25 #include "GLcommon/ShareGroup.h"
26 
27 #include <GLES3/gl31.h>
28 #include <string.h>
29 #include <unordered_set>
30 
GLUniformDesc(const char * name,GLint location,GLsizei count,GLboolean transpose,GLenum type,GLsizei size,unsigned char * val)31 GLUniformDesc::GLUniformDesc(const char* name, GLint location, GLsizei count, GLboolean transpose,
32             GLenum type, GLsizei size, unsigned char* val)
33         : mCount(count), mTranspose(transpose), mType(type)
34         , mVal(val, val + size), mGuestName(name) { }
35 
GLUniformDesc(android::base::Stream * stream)36 GLUniformDesc::GLUniformDesc(android::base::Stream* stream) {
37     mCount = stream->getBe32();
38     mTranspose = stream->getByte();
39     mType = stream->getBe32();
40     loadBuffer(stream, &mVal);
41     mGuestName = stream->getString();
42 }
43 
onSave(android::base::Stream * stream) const44 void GLUniformDesc::onSave(android::base::Stream* stream) const {
45     stream->putBe32(mCount);
46     stream->putByte(mTranspose);
47     stream->putBe32(mType);
48     saveBuffer(stream, mVal);
49     stream->putString(mGuestName);
50 }
51 
s_glShaderType2ShaderType(GLenum type)52 static int s_glShaderType2ShaderType(GLenum type) {
53     switch (type) {
54     case GL_VERTEX_SHADER:
55         return ProgramData::VERTEX;
56         break;
57     case GL_FRAGMENT_SHADER:
58         return ProgramData::FRAGMENT;
59         break;
60     case GL_COMPUTE_SHADER:
61         return ProgramData::COMPUTE;
62         break;
63     default:
64         assert(0);
65         break;
66     }
67     return ProgramData::NUM_SHADER_TYPE;
68 }
69 
ProgramData(int glesMaj,int glesMin)70 ProgramData::ProgramData(int glesMaj, int glesMin)
71     : ObjectData(PROGRAM_DATA),
72       ValidateStatus(false),
73       LinkStatus(false),
74       HostLinkStatus(false),
75       IsInUse(false),
76       DeleteStatus(false),
77       mGlesMajorVersion(glesMaj),
78       mGlesMinorVersion(glesMin) {}
79 
ProgramData(android::base::Stream * stream)80 ProgramData::ProgramData(android::base::Stream* stream) :
81     ObjectData(stream) {
82     auto loadAttribLocs = [](android::base::Stream* stream) {
83                 std::string attrib = stream->getString();
84                 GLuint loc = stream->getBe32();
85                 return std::make_pair(std::move(attrib), loc);
86             };
87     loadCollection(stream, &boundAttribLocs, loadAttribLocs);
88     loadCollection(stream, &linkedAttribLocs, loadAttribLocs);
89 
90     loadCollection(stream, &uniforms, [](android::base::Stream* stream) {
91        GLuint loc = stream->getBe32();
92        GLUniformDesc desc(stream);
93        return std::make_pair(loc, std::move(desc));
94     });
95     loadCollection(stream, &mUniformBlockBinding,
96             [](android::base::Stream* stream) {
97                 GLuint block = stream->getBe32();
98                 GLuint binding = stream->getBe32();
99                 return std::make_pair(block, binding);
100     });
101     int transformFeedbackCount = stream->getBe32();
102     mTransformFeedbacks.resize(transformFeedbackCount);
103     for (auto& feedback : mTransformFeedbacks) {
104         feedback = stream->getString();
105     }
106     mTransformFeedbackBufferMode = stream->getBe32();
107 
108     for (auto& s : attachedShaders) {
109         s.localName = stream->getBe32();
110         s.linkedSource = stream->getString();
111     }
112     validationInfoLog = stream->getString();
113     infoLog = stream->getString();
114 
115     stream->getBe16(); /* padding to maintain snapshot file compatibility */
116     ValidateStatus = stream->getByte();
117     LinkStatus = stream->getByte();
118     IsInUse = stream->getByte();
119     DeleteStatus = stream->getByte();
120 
121     mGlesMajorVersion = stream->getByte();
122     mGlesMinorVersion = stream->getByte();
123     loadCollection(stream, &mUniNameToGuestLoc,
124             [](android::base::Stream* stream) {
125         std::string name = stream->getString();
126         int loc = stream->getBe32();
127         return std::make_pair(name, loc);
128     });
129 }
130 
getUniformValue(const GLchar * name,GLenum type,std::unordered_map<GLuint,GLUniformDesc> & uniformsOnSave) const131 void ProgramData::getUniformValue(const GLchar *name, GLenum type,
132         std::unordered_map<GLuint, GLUniformDesc> &uniformsOnSave) const {
133     alignas(double) unsigned char val[256];     //Large enought to hold MAT4x4
134     GLDispatch& dispatcher = GLEScontext::dispatcher();
135 
136     GLint location = dispatcher.glGetUniformLocation(ProgramName, name);
137     if (location < 0) {
138         return;
139     }
140     switch(type) {
141     case GL_FLOAT:
142     case GL_FLOAT_VEC2:
143     case GL_FLOAT_VEC3:
144     case GL_FLOAT_VEC4:
145     case GL_FLOAT_MAT2:
146     case GL_FLOAT_MAT3:
147     case GL_FLOAT_MAT4:
148     case GL_FLOAT_MAT2x3:
149     case GL_FLOAT_MAT2x4:
150     case GL_FLOAT_MAT3x2:
151     case GL_FLOAT_MAT3x4:
152     case GL_FLOAT_MAT4x2:
153     case GL_FLOAT_MAT4x3:
154         dispatcher.glGetUniformfv(ProgramName, location, (GLfloat *)val);
155         break;
156     case GL_INT:
157     case GL_INT_VEC2:
158     case GL_INT_VEC3:
159     case GL_INT_VEC4:
160     case GL_BOOL:
161     case GL_BOOL_VEC2:
162     case GL_BOOL_VEC3:
163     case GL_BOOL_VEC4:
164     case GL_SAMPLER_2D:
165     case GL_SAMPLER_3D:
166     case GL_SAMPLER_CUBE:
167     case GL_SAMPLER_2D_SHADOW:
168     case GL_SAMPLER_2D_ARRAY:
169     case GL_SAMPLER_2D_ARRAY_SHADOW:
170     case GL_SAMPLER_CUBE_SHADOW:
171     case GL_INT_SAMPLER_2D:
172     case GL_INT_SAMPLER_3D:
173     case GL_INT_SAMPLER_CUBE:
174     case GL_INT_SAMPLER_2D_ARRAY:
175     case GL_UNSIGNED_INT_SAMPLER_2D:
176     case GL_UNSIGNED_INT_SAMPLER_3D:
177     case GL_UNSIGNED_INT_SAMPLER_CUBE:
178     case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
179         dispatcher.glGetUniformiv(ProgramName, location, (GLint *)val);
180         break;
181     case GL_UNSIGNED_INT:
182     case GL_UNSIGNED_INT_VEC2:
183     case GL_UNSIGNED_INT_VEC3:
184     case GL_UNSIGNED_INT_VEC4:
185         dispatcher.glGetUniformuiv(ProgramName, location, (GLuint *)val);
186         break;
187     default:
188         fprintf(stderr, "ProgramData::gtUniformValue: warning: "
189                 "unsupported uniform type 0x%x\n", type);
190         return;
191     }
192     GLUniformDesc uniformDesc(name, location, 1, 0, /*transpose*/
193         type, glSizeof(type), val);
194 
195     if (!isGles2Gles()) {
196         uniformDesc.mGuestName = getDetranslatedName(uniformDesc.mGuestName);
197     }
198 
199     uniformsOnSave[location] = std::move(uniformDesc);
200 }
201 
getBaseName(const std::string & name)202 static std::string getBaseName(const std::string& name) {
203     std::string baseName;
204     int length = name.length();
205     if (length < 3) return name;
206     if (name.compare(length - 3, 1, "[") == 0) {
207         baseName = name.substr(0, length - 3);
208     } else {
209         baseName = name;
210     }
211     return baseName;
212 }
213 
214 // Query uniform variables from driver
collectUniformInfo() const215 std::unordered_map<GLuint, GLUniformDesc> ProgramData::collectUniformInfo() const {
216     GLint uniform_count = 0;
217     GLint nameLength = 0;
218     std::unordered_map<GLuint, GLUniformDesc> uniformsOnSave;
219     GLDispatch& dispatcher = GLEScontext::dispatcher();
220     dispatcher.glGetProgramiv(ProgramName, GL_ACTIVE_UNIFORM_MAX_LENGTH, &nameLength);
221     if (nameLength == 0) {
222         // No active uniform variables exist.
223         return uniformsOnSave;
224     }
225     dispatcher.glGetProgramiv(ProgramName, GL_ACTIVE_UNIFORMS, &uniform_count);
226     std::vector<char> name(nameLength, 0);
227     for (int i = 0; i < uniform_count; i++) {
228         GLint size;
229         GLenum type;
230         GLsizei length;
231         dispatcher.glGetActiveUniform(ProgramName, i, nameLength, &length,
232                 &size, &type, name.data());
233         if (size > 1) {
234             // Uniform array, drivers may return 'arrayName' or 'arrayName[0]'
235             // as the name of the array.
236             // Need to append '[arrayIndex]' after 'arrayName' to query the
237             // value for each array member.
238             std::string baseName = getBaseName(std::string(name.data()));
239             for (int arrayIndex = 0; arrayIndex < size; arrayIndex++) {
240                 std::ostringstream oss;
241                 oss << baseName << '[' << arrayIndex << ']';
242                 std::string toSaveName = oss.str();
243                 getUniformValue(toSaveName.c_str(), type, uniformsOnSave);
244             }
245         }
246         else {
247             getUniformValue(name.data(), type, uniformsOnSave);
248         }
249     }
250     return uniformsOnSave;
251 }
252 
collectUniformBlockInfo(GLuint pname)253 static std::unordered_map<GLuint, GLuint> collectUniformBlockInfo(GLuint pname) {
254     GLint uniformBlockCount = 0;
255     std::unordered_map<GLuint, GLuint> uniformBlocks;
256     GLDispatch& dispatcher = GLEScontext::dispatcher();
257     dispatcher.glGetProgramiv(pname, GL_ACTIVE_UNIFORM_BLOCKS,
258             &uniformBlockCount);
259     for (int i = 0; i < uniformBlockCount; i++) {
260         GLint binding = 0;
261         dispatcher.glGetActiveUniformBlockiv(pname, i, GL_UNIFORM_BLOCK_BINDING,
262                 &binding);
263         uniformBlocks.emplace(i, binding);
264     }
265     return uniformBlocks;
266 }
267 
collectTransformFeedbackInfo(GLuint pname)268 static std::vector<std::string> collectTransformFeedbackInfo(GLuint pname) {
269     GLint transformFeedbackCount = 0;
270     GLint transformFeedbakMaxLength = 0;
271     GLDispatch& dispatcher = GLEScontext::dispatcher();
272     dispatcher.glGetProgramiv(pname, GL_TRANSFORM_FEEDBACK_VARYINGS,
273             &transformFeedbackCount);
274     dispatcher.glGetProgramiv(pname, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
275             &transformFeedbakMaxLength);
276 
277     std::vector<std::string> transformFeedbacks(transformFeedbackCount);
278     std::unique_ptr<char[]> nameBuffer(new char [transformFeedbakMaxLength]);
279 
280     for (int i = 0; i < transformFeedbackCount; i++) {
281         GLsizei size;
282         GLenum type;
283 
284         dispatcher.glGetTransformFeedbackVarying(pname, i,
285                 transformFeedbakMaxLength, nullptr, &size, &type,
286                 nameBuffer.get());
287         transformFeedbacks[i] = nameBuffer.get();
288     }
289     return transformFeedbacks;
290 }
291 
onSave(android::base::Stream * stream,unsigned int globalName) const292 void ProgramData::onSave(android::base::Stream* stream, unsigned int globalName) const {
293     // The first byte is used to distinguish between program and shader object.
294     // It will be loaded outside of this class
295     stream->putByte(LOAD_PROGRAM);
296     ObjectData::onSave(stream, globalName);
297     auto saveAttribLocs = [](android::base::Stream* stream,
298             const std::pair<std::string, GLuint>& attribLoc) {
299                 stream->putString(attribLoc.first);
300                 stream->putBe32(attribLoc.second);
301             };
302     saveCollection(stream, boundAttribLocs, saveAttribLocs);
303     saveCollection(stream, linkedAttribLocs, saveAttribLocs);
304 
305     auto saveUniform = [](android::base::Stream* stream,
306                 const std::pair<const GLuint, GLUniformDesc>& uniform) {
307             stream->putBe32(uniform.first);
308             uniform.second.onSave(stream);
309         };
310     auto saveUniformBlock = [](android::base::Stream* stream,
311                 const std::pair<const GLuint, GLuint>& uniformBlock) {
312             stream->putBe32(uniformBlock.first);
313             stream->putBe32(uniformBlock.second);
314         };
315     auto saveTransformFeedbacks = [](android::base::Stream* stream,
316                 const std::vector<std::string>& transformFeedbacks) {
317             stream->putBe32((int)transformFeedbacks.size());
318             for (const auto& feedback : transformFeedbacks) {
319                 stream->putString(feedback);
320             }
321         };
322     if (needRestore()) {
323         saveCollection(stream, uniforms, saveUniform);
324         saveCollection(stream, mUniformBlockBinding, saveUniformBlock);
325         saveTransformFeedbacks(stream, mTransformFeedbacks);
326         stream->putBe32(mTransformFeedbackBufferMode);
327     } else {
328         std::unordered_map<GLuint, GLUniformDesc> uniformsOnSave =
329                 collectUniformInfo();
330         std::unordered_map<GLuint, GLuint> uniformBlocks;
331         std::vector<std::string> transformFeedbacks;
332         if (mGlesMajorVersion >= 3) {
333             uniformBlocks = collectUniformBlockInfo(ProgramName);
334             transformFeedbacks = collectTransformFeedbackInfo(ProgramName);
335             GLEScontext::dispatcher().glGetProgramiv(ProgramName,
336                     GL_TRANSFORM_FEEDBACK_BUFFER_MODE,
337                     (GLint*)&mTransformFeedbackBufferMode);
338         }
339 
340         saveCollection(stream, uniformsOnSave, saveUniform);
341         saveCollection(stream, uniformBlocks, saveUniformBlock);
342         saveTransformFeedbacks(stream, transformFeedbacks);
343         stream->putBe32(mTransformFeedbackBufferMode);
344     }
345 
346     for (const auto& s : attachedShaders) {
347         stream->putBe32(s.localName);
348         stream->putString(s.linkedSource);
349         // s.linkedInfo will be regenerated on restore
350         // This is for compatibility over different rendering backends
351     }
352     stream->putString(validationInfoLog);
353     stream->putString(infoLog);
354 
355     stream->putBe16(0 /* padding to maintain snapshot file compatibility */);
356     stream->putByte(ValidateStatus);
357     stream->putByte(LinkStatus);
358 
359     stream->putByte(IsInUse);
360     stream->putByte(DeleteStatus);
361 
362     stream->putByte(mGlesMajorVersion);
363     stream->putByte(mGlesMinorVersion);
364     saveCollection(stream, mUniNameToGuestLoc, [](android::base::Stream* stream,
365                 const std::pair<std::string, int>& uniNameLoc) {
366         stream->putString(uniNameLoc.first);
367         stream->putBe32(uniNameLoc.second);
368     });
369 }
370 
postLoad(const getObjDataPtr_t & getObjDataPtr)371 void ProgramData::postLoad(const getObjDataPtr_t& getObjDataPtr) {
372     for (auto& s : attachedShaders) {
373         if (s.localName) {
374             s.shader = (ShaderParser*)getObjDataPtr(
375                     NamedObjectType::SHADER_OR_PROGRAM, s.localName).get();
376         }
377     }
378 }
379 
restore(ObjectLocalName localName,const getGlobalName_t & getGlobalName)380 void ProgramData::restore(ObjectLocalName localName,
381            const getGlobalName_t& getGlobalName) {
382     ObjectData::restore(localName, getGlobalName);
383     int globalName = getGlobalName(NamedObjectType::SHADER_OR_PROGRAM,
384             localName);
385     assert(globalName);
386     ProgramName = globalName;
387     GLDispatch& dispatcher = GLEScontext::dispatcher();
388     mGuestLocToHostLoc.add(-1, -1);
389     bool shoudLoadLinked = LinkStatus;
390 #if defined(TOLERATE_PROGRAM_LINK_ERROR) && TOLERATE_PROGRAM_LINK_ERROR == 1
391     shoudLoadLinked = 1;
392 #endif
393     if (shoudLoadLinked) {
394         // Really, each program name corresponds to 2 programs:
395         // the one that is already linked, and the one that is not yet linked.
396         // We need to restore both.
397         GLint tmpShaders[NUM_SHADER_TYPE];
398         for (int i = 0; i < NUM_SHADER_TYPE; i++) {
399             AttachedShader& s = attachedShaders[i];
400             if (s.linkedSource.empty()) {
401                 tmpShaders[i] = 0;
402                 continue;
403             }
404             GLenum type = 0;
405             switch (i) {
406             case VERTEX:
407                 type = GL_VERTEX_SHADER;
408                 break;
409             case FRAGMENT:
410                 type = GL_FRAGMENT_SHADER;
411                 break;
412             case COMPUTE:
413                 type = GL_COMPUTE_SHADER;
414                 break;
415             default:
416                 assert(0);
417             }
418             tmpShaders[i] = dispatcher.glCreateShader(type);
419             const GLchar* src = (const GLchar *)s.linkedSource.c_str();
420             std::string parsedSrc;
421             if (!isGles2Gles()) {
422                 std::string infoLog;
423                 ANGLEShaderParser::translate(
424                             isCoreProfile(),
425                             src,
426                             type,
427                             &infoLog,
428                             &parsedSrc,
429                             &s.linkInfo);
430                 src = parsedSrc.c_str();
431             }
432             dispatcher.glShaderSource(tmpShaders[i], 1, &src, NULL);
433             dispatcher.glCompileShader(tmpShaders[i]);
434             dispatcher.glAttachShader(globalName, tmpShaders[i]);
435         }
436         for (const auto& attribLocs : linkedAttribLocs) {
437             // Prefix "gl_" is reserved, we should skip those.
438             // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glBindAttribLocation.xhtml
439             if  (strncmp(attribLocs.first.c_str(), "gl_", 3) == 0) {
440                 continue;
441             }
442             dispatcher.glBindAttribLocation(globalName, attribLocs.second,
443                     attribLocs.first.c_str());
444         }
445         if (mGlesMajorVersion >= 3) {
446             std::vector<const char*> varyings;
447             varyings.resize(mTransformFeedbacks.size());
448             for (size_t i = 0; i < mTransformFeedbacks.size(); i++) {
449                 varyings[i] = mTransformFeedbacks[i].c_str();
450             }
451             dispatcher.glTransformFeedbackVaryings(
452                     globalName, mTransformFeedbacks.size(), varyings.data(),
453                     mTransformFeedbackBufferMode);
454             mTransformFeedbacks.clear();
455         }
456         dispatcher.glLinkProgram(globalName);
457         dispatcher.glUseProgram(globalName);
458 #ifdef DEBUG
459         for (const auto& attribLocs : linkedAttribLocs) {
460             assert(dispatcher.glGetAttribLocation(globalName,
461                 attribLocs.first.c_str()) == attribLocs.second);
462         }
463 #endif // DEBUG
464         for (const auto& uniform : mUniNameToGuestLoc) {
465             GLint hostLoc = dispatcher.glGetUniformLocation(
466                     globalName, getTranslatedName(uniform.first).c_str());
467             if (hostLoc != -1) {
468                 mGuestLocToHostLoc.add(uniform.second, hostLoc);
469             }
470         }
471         for (const auto& uniformEntry : uniforms) {
472             const auto& uniform = uniformEntry.second;
473             GLint location = dispatcher.glGetUniformLocation(
474                     globalName, getTranslatedName(uniform.mGuestName).c_str());
475             if (location == -1) {
476                 // Location changed after loading from a snapshot.
477                 // likely loading from different GPU backend (and they
478                 // optimize out different stuff)
479                 continue;
480             }
481 
482             switch (uniform.mType) {
483                 case GL_FLOAT:
484                     dispatcher.glUniform1fv(location, uniform.mCount,
485                             (const GLfloat*)uniform.mVal.data());
486                     break;
487                 case GL_FLOAT_VEC2:
488                     dispatcher.glUniform2fv(location, uniform.mCount,
489                             (const GLfloat*)uniform.mVal.data());
490                     break;
491                 case GL_FLOAT_VEC3:
492                     dispatcher.glUniform3fv(location, uniform.mCount,
493                             (const GLfloat*)uniform.mVal.data());
494                     break;
495                 case GL_FLOAT_VEC4:
496                     dispatcher.glUniform4fv(location, uniform.mCount,
497                             (const GLfloat*)uniform.mVal.data());
498                     break;
499                 case GL_BOOL:
500                 case GL_INT:
501                 case GL_SAMPLER_2D:
502                 case GL_SAMPLER_3D:
503                 case GL_SAMPLER_CUBE:
504                 case GL_SAMPLER_2D_SHADOW:
505                 case GL_SAMPLER_2D_ARRAY:
506                 case GL_SAMPLER_2D_ARRAY_SHADOW:
507                 case GL_SAMPLER_CUBE_SHADOW:
508                 case GL_INT_SAMPLER_2D:
509                 case GL_INT_SAMPLER_3D:
510                 case GL_INT_SAMPLER_CUBE:
511                 case GL_INT_SAMPLER_2D_ARRAY:
512                 case GL_UNSIGNED_INT_SAMPLER_2D:
513                 case GL_UNSIGNED_INT_SAMPLER_3D:
514                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
515                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
516                     dispatcher.glUniform1iv(location, uniform.mCount,
517                             (const GLint*)uniform.mVal.data());
518                     break;
519                 case GL_BOOL_VEC2:
520                 case GL_INT_VEC2:
521                     dispatcher.glUniform2iv(location, uniform.mCount,
522                             (const GLint*)uniform.mVal.data());
523                     break;
524                 case GL_BOOL_VEC3:
525                 case GL_INT_VEC3:
526                     dispatcher.glUniform3iv(location, uniform.mCount,
527                             (const GLint*)uniform.mVal.data());
528                     break;
529                 case GL_BOOL_VEC4:
530                 case GL_INT_VEC4:
531                     dispatcher.glUniform4iv(location, uniform.mCount,
532                             (const GLint*)uniform.mVal.data());
533                     break;
534                 case GL_UNSIGNED_INT:
535                     dispatcher.glUniform1uiv(location, uniform.mCount,
536                             (const GLuint*)uniform.mVal.data());
537                     break;
538                 case GL_UNSIGNED_INT_VEC2:
539                     dispatcher.glUniform2uiv(location, uniform.mCount,
540                             (const GLuint*)uniform.mVal.data());
541                     break;
542                 case GL_UNSIGNED_INT_VEC3:
543                     dispatcher.glUniform3uiv(location, uniform.mCount,
544                             (const GLuint*)uniform.mVal.data());
545                     break;
546                 case GL_UNSIGNED_INT_VEC4:
547                     dispatcher.glUniform4uiv(location, uniform.mCount,
548                             (const GLuint*)uniform.mVal.data());
549                     break;
550                 case GL_FLOAT_MAT2:
551                     dispatcher.glUniformMatrix2fv(location,
552                             uniform.mCount, uniform.mTranspose,
553                             (const GLfloat*)uniform.mVal.data());
554                     break;
555                 case GL_FLOAT_MAT3:
556                     dispatcher.glUniformMatrix3fv(location,
557                             uniform.mCount, uniform.mTranspose,
558                             (const GLfloat*)uniform.mVal.data());
559                     break;
560                 case GL_FLOAT_MAT4:
561                     dispatcher.glUniformMatrix4fv(location,
562                             uniform.mCount, uniform.mTranspose,
563                             (const GLfloat*)uniform.mVal.data());
564                     break;
565                 case GL_FLOAT_MAT2x3:
566                     dispatcher.glUniformMatrix2x3fv(location,
567                             uniform.mCount, uniform.mTranspose,
568                             (const GLfloat*)uniform.mVal.data());
569                     break;
570                 case GL_FLOAT_MAT2x4:
571                     dispatcher.glUniformMatrix2x4fv(location,
572                             uniform.mCount, uniform.mTranspose,
573                             (const GLfloat*)uniform.mVal.data());
574                     break;
575                 case GL_FLOAT_MAT3x2:
576                     dispatcher.glUniformMatrix3x2fv(location,
577                             uniform.mCount, uniform.mTranspose,
578                             (const GLfloat*)uniform.mVal.data());
579                     break;
580                 case GL_FLOAT_MAT3x4:
581                     dispatcher.glUniformMatrix3x4fv(location,
582                             uniform.mCount, uniform.mTranspose,
583                             (const GLfloat*)uniform.mVal.data());
584                     break;
585                 case GL_FLOAT_MAT4x2:
586                     dispatcher.glUniformMatrix4x2fv(location,
587                             uniform.mCount, uniform.mTranspose,
588                             (const GLfloat*)uniform.mVal.data());
589                     break;
590                 case GL_FLOAT_MAT4x3:
591                     dispatcher.glUniformMatrix4x3fv(location,
592                             uniform.mCount, uniform.mTranspose,
593                             (const GLfloat*)uniform.mVal.data());
594                     break;
595                 default:
596                     fprintf(stderr, "ProgramData::restore: warning: "
597                             "unsupported uniform type 0x%x\n", uniform.mType);
598             }
599         }
600         for (const auto& uniformBlock : mUniformBlockBinding) {
601             dispatcher.glUniformBlockBinding(globalName, uniformBlock.first,
602                     uniformBlock.second);
603         }
604         for (auto s : tmpShaders) {
605             if (s != 0) {
606                 dispatcher.glDetachShader(globalName, s);
607                 dispatcher.glDeleteShader(s);
608             }
609         }
610     }
611     uniforms.clear();
612     mUniformBlockBinding.clear();
613     // We are done with the "linked" program, now we handle the one
614     // that is yet to compile
615     for (const auto& s : attachedShaders) {
616         if (s.localName) {
617             int shaderGlobalName = getGlobalName(
618                     NamedObjectType::SHADER_OR_PROGRAM, s.localName);
619             assert(shaderGlobalName);
620             dispatcher.glAttachShader(globalName, shaderGlobalName);
621         }
622     }
623     for (const auto& attribLocs : boundAttribLocs) {
624         dispatcher.glBindAttribLocation(globalName, attribLocs.second,
625                 attribLocs.first.c_str());
626     }
627 }
628 
getGenNameInfo() const629 GenNameInfo ProgramData::getGenNameInfo() const {
630     return GenNameInfo(ShaderProgramType::PROGRAM);
631 }
632 
setErrInfoLog()633 void ProgramData::setErrInfoLog() {
634     infoLog.clear();
635     infoLog = std::string(validationInfoLog);
636 }
637 
setInfoLog(const GLchar * log)638 void ProgramData::setInfoLog(const GLchar* log) {
639     infoLog = std::string(log);
640 }
641 
getInfoLog() const642 const GLchar* ProgramData::getInfoLog() const {
643     return infoLog.c_str();
644 }
645 
getAttachedVertexShader() const646 GLuint ProgramData::getAttachedVertexShader() const {
647     return attachedShaders[VERTEX].localName;
648 }
649 
getAttachedFragmentShader() const650 GLuint ProgramData::getAttachedFragmentShader() const {
651     return attachedShaders[FRAGMENT].localName;
652 }
653 
getAttachedComputeShader() const654 GLuint ProgramData::getAttachedComputeShader() const {
655     return attachedShaders[COMPUTE].localName;
656 }
657 
getAttachedShader(GLenum type) const658 GLuint ProgramData::getAttachedShader(GLenum type) const {
659     return attachedShaders[s_glShaderType2ShaderType(type)].localName;
660 }
661 
662 std::string
getTranslatedName(const std::string & userVarName) const663 ProgramData::getTranslatedName(const std::string& userVarName) const {
664     if (isGles2Gles()) {
665         return userVarName;
666     }
667     // TODO: translate uniform array names
668     for (int i = 0; i < NUM_SHADER_TYPE; i++) {
669         if (const auto name = android::base::find(
670                 attachedShaders[i].linkInfo.nameMap, userVarName)) {
671             return *name;
672         }
673     }
674     return userVarName;
675 }
676 
677 std::string
getDetranslatedName(const std::string & driverName) const678 ProgramData::getDetranslatedName(const std::string& driverName) const {
679     if (isGles2Gles()) {
680         return driverName;
681     }
682     // TODO: detranslate uniform array names
683     for (int i = 0; i < NUM_SHADER_TYPE; i++) {
684         if (const auto name = android::base::find(
685                 attachedShaders[i].linkInfo.nameMapReverse, driverName)) {
686             return *name;
687         }
688     }
689     return driverName;
690 }
691 
attachShader(GLuint shader,ShaderParser * shaderData,GLenum type)692 bool ProgramData::attachShader(GLuint shader, ShaderParser* shaderData,
693         GLenum type) {
694     AttachedShader& s = attachedShaders[s_glShaderType2ShaderType(type)];
695     if (s.localName == 0) {
696         s.localName = shader;
697         s.shader = shaderData;
698         return true;
699     }
700     return false;
701 }
702 
isAttached(GLuint shader) const703 bool ProgramData::isAttached(GLuint shader) const {
704     for (const auto& s : attachedShaders) {
705         if (s.localName == shader) return true;
706     }
707     return false;
708 }
709 
detachShader(GLuint shader)710 bool ProgramData::detachShader(GLuint shader) {
711     for (auto& s : attachedShaders) {
712         if (s.localName == shader) {
713             s.localName = 0;
714             s.shader = nullptr;
715             return true;
716         }
717     }
718     return false;
719 }
720 
bindAttribLocation(const std::string & var,GLuint loc)721 void ProgramData::bindAttribLocation(const std::string& var, GLuint loc) {
722     boundAttribLocs[var] = loc;
723 }
724 
linkedAttribLocation(const std::string & var,GLuint loc)725 void ProgramData::linkedAttribLocation(const std::string& var, GLuint loc) {
726     linkedAttribLocs[var] = loc;
727 }
728 
729 // Link-time validation
appendValidationErrMsg(std::ostringstream & ss)730 void ProgramData::appendValidationErrMsg(std::ostringstream& ss) {
731     validationInfoLog += "Error: " + ss.str() + "\n";
732 }
733 static bool sCheckUndecl(ProgramData* pData,
734                          const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
735                          const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo);
736 static bool sCheckLimits(ProgramData* pData,
737                          const ST_BuiltInResources& resources,
738                          const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
739                          const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo);
740 static bool sCheckVariables(ProgramData* pData,
741                             const ANGLEShaderParser::ShaderLinkInfo& a,
742                             const ANGLEShaderParser::ShaderLinkInfo& b);
743 static void sInitializeUniformLocs(ProgramData* pData,
744                                    const std::vector<ST_ShaderVariable>& uniforms);
745 
validateLink(ShaderParser * frag,ShaderParser * vert)746 bool ProgramData::validateLink(ShaderParser* frag, ShaderParser* vert) {
747     const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo =
748         frag->getShaderLinkInfo();
749     const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo =
750         vert->getShaderLinkInfo();
751 
752     bool res = true;
753 
754     res = res && sCheckUndecl(this, fragLinkInfo, vertLinkInfo);
755     res = res && sCheckLimits(this, ANGLEShaderParser::kResources,
756                               fragLinkInfo, vertLinkInfo);
757     res = res && sCheckVariables(this, fragLinkInfo, vertLinkInfo);
758 
759     return res;
760 }
761 
setHostLinkStatus(GLint status)762 void ProgramData::setHostLinkStatus(GLint status) {
763     HostLinkStatus = (status == GL_FALSE) ? false : true;
764 }
765 
setLinkStatus(GLint status)766 void ProgramData::setLinkStatus(GLint status) {
767     LinkStatus = (status == GL_FALSE) ? false : true;
768     mUniNameToGuestLoc.clear();
769     mGuestLocToHostLoc.clear();
770     mGuestLocToHostLoc.add(-1, -1);
771 #if defined(TOLERATE_PROGRAM_LINK_ERROR) && TOLERATE_PROGRAM_LINK_ERROR == 1
772     status = 1;
773 #endif
774     if (status && HostLinkStatus) {
775         std::vector<ST_ShaderVariable> allUniforms;
776         bool is310 = false;
777         for (auto& s : attachedShaders) {
778             if (s.localName) {
779                 assert(s.shader);
780                 s.linkedSource = s.shader->getOriginalSrc();
781                 s.linkInfo = s.shader->getShaderLinkInfo();
782                 is310 = is310 || (s.linkInfo.esslVersion == 310);
783                 for (const auto& var: s.linkInfo.uniforms) {
784                     allUniforms.push_back(var);
785                 }
786             }
787         }
788 
789         if (is310 || isGles2Gles()) {
790             mUseDirectDriverUniformInfo = true;
791         } else {
792             sInitializeUniformLocs(this, allUniforms);
793         }
794         for (const auto &attribLoc : boundAttribLocs) {
795             // overwrite
796             linkedAttribLocs[attribLoc.first] = attribLoc.second;
797         }
798     } else {
799         for (auto& s : attachedShaders) {
800             s.linkedSource.clear();
801         }
802     }
803 }
804 
getLinkStatus() const805 bool ProgramData::getLinkStatus() const {
806     return LinkStatus;
807 }
808 
809 static const char kDifferentPrecisionErr[] =
810     "specified with different precision in different shaders.";
811 static const char kDifferentTypeErr[] =
812     "specified with different type in different shaders.";
813 static const char kDifferentLayoutQualifierErr[] =
814     "specified with different layout qualifiers in different shaders.";
815 static const char kExceededMaxVertexAttribs[] =
816     "exceeded max vertex attribs.";
817 static const char kUsedUndeclaredErr[] =
818     "used, but not declared.";
819 static const char kUniformQualifier[] = "uniform";
820 static const char kVaryingQualifier[] = "varying";
821 static const char kUnknownQualifier[] = "[unknown qualifier]";
822 enum ValidationQualifier {
823     UNIFORM,
824     VARYING,
825 };
826 
sQualifierString(ValidationQualifier q)827 static const char* sQualifierString(ValidationQualifier q) {
828     switch (q) {
829     case ValidationQualifier::UNIFORM:
830         return kUniformQualifier;
831     case ValidationQualifier::VARYING:
832         return kVaryingQualifier;
833     }
834     return kUnknownQualifier;
835 }
836 
sVarCheck(ProgramData * pData,ValidationQualifier qualifier,const ST_ShaderVariable & a,const ST_ShaderVariable & b)837 static bool sVarCheck(ProgramData* pData,
838                       ValidationQualifier qualifier,
839                       const ST_ShaderVariable& a,
840                       const ST_ShaderVariable& b) {
841     bool res = true;
842 
843     if (qualifier == ValidationQualifier::UNIFORM &&
844         a.precision != b.precision) {
845         std::ostringstream err;
846         err << sQualifierString(qualifier) << " " << a.name << " ";
847         err << kDifferentPrecisionErr;
848         pData->appendValidationErrMsg(err);
849         res = false;
850     }
851 
852     bool aIsStruct = a.fieldsCount > 0;
853     bool bIsStruct = b.fieldsCount > 0;
854 
855     if (aIsStruct != bIsStruct ||
856         a.type != b.type) {
857         std::ostringstream err;
858         err << sQualifierString(qualifier) << " " << a.name << " ";
859         err << kDifferentTypeErr;
860         pData->appendValidationErrMsg(err);
861         res = false;
862     }
863 
864     if (aIsStruct) {
865         for (unsigned int i = 0; i < a.fieldsCount; ++i) {
866             for (unsigned int j = 0; j < b.fieldsCount; ++j) {
867                 if (strcmp(a.pFields[i].name, b.pFields[j].name)) continue;
868                 res = res && sVarCheck(pData, qualifier, a.pFields[i], b.pFields[j]);
869             }
870         }
871     }
872 
873     return res;
874 }
875 
sInterfaceBlockCheck(ProgramData * pData,const ST_InterfaceBlock & a,const ST_InterfaceBlock & b)876 static bool sInterfaceBlockCheck(ProgramData* pData,
877                                  const ST_InterfaceBlock& a,
878                                  const ST_InterfaceBlock& b) {
879     bool res = true;
880 
881     if (a.layout != b.layout ||
882         a.isRowMajorLayout != b.isRowMajorLayout) {
883         std::ostringstream err;
884         err << "interface block " << a.name << " ";
885         err << kDifferentLayoutQualifierErr;
886         pData->appendValidationErrMsg(err);
887         res = false;
888     }
889 
890     if (a.fieldsCount != b.fieldsCount) {
891         std::ostringstream err;
892         err << "interface block " << a.name << " ";
893         err << kDifferentTypeErr;
894         pData->appendValidationErrMsg(err);
895         res = false;
896     }
897 
898     for (unsigned int i = 0; i < a.fieldsCount; ++i) {
899         for (unsigned int j = 0; j < b.fieldsCount; ++j) {
900             const auto afield = a.pFields[i];
901             const auto bfield = b.pFields[j];
902 
903             if (strcmp(afield.name, bfield.name)) continue;
904             res = res && sVarCheck(pData, ValidationQualifier::VARYING,
905                     afield, bfield);
906             if (afield.isRowMajorLayout != bfield.isRowMajorLayout) {
907                 std::ostringstream err;
908                 err << "interface block field ";
909                 err << a.name << "." << afield.name << " ";
910                 err << kDifferentLayoutQualifierErr;
911                 pData->appendValidationErrMsg(err);
912                 res = false;
913             }
914         }
915     }
916 
917     return res;
918 }
919 
sIsBuiltInShaderVariable(const ST_ShaderVariable & var)920 static bool sIsBuiltInShaderVariable(const ST_ShaderVariable& var) {
921     if (!var.name || strlen(var.name) < 4) return false;
922 
923     const char* name = var.name;
924     return (name[0] == 'g' && name[1] == 'l' && name[2] == '_');
925 }
926 
sCheckUndecl(ProgramData * pData,const ANGLEShaderParser::ShaderLinkInfo & fragLinkInfo,const ANGLEShaderParser::ShaderLinkInfo & vertLinkInfo)927 static bool sCheckUndecl(
928         ProgramData* pData,
929         const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
930         const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo) {
931     bool res = true;
932     for (const auto& felt : fragLinkInfo.varyings) {
933         if (sIsBuiltInShaderVariable(felt)) continue;
934 
935         bool declaredInVertShader = false;
936         for (const auto& velt : vertLinkInfo.varyings) {
937             if (!strcmp(velt.name, felt.name)) {
938                 declaredInVertShader = true;
939                 break;
940             }
941         }
942 
943         if (!declaredInVertShader && felt.staticUse) {
944             std::ostringstream err;
945             err << "varying " << felt.name << " ";
946             err << kUsedUndeclaredErr;
947             pData->appendValidationErrMsg(err);
948             res = false;
949         }
950     }
951     return res;
952 }
953 
sCheckLimits(ProgramData * pData,const ST_BuiltInResources & resources,const ANGLEShaderParser::ShaderLinkInfo & fragShaderLinkInfo,const ANGLEShaderParser::ShaderLinkInfo & vertShaderLinkInfo)954 static bool sCheckLimits(
955         ProgramData* pData,
956         const ST_BuiltInResources& resources,
957         const ANGLEShaderParser::ShaderLinkInfo& fragShaderLinkInfo,
958         const ANGLEShaderParser::ShaderLinkInfo& vertShaderLinkInfo) {
959 
960     bool res = true;
961 
962     size_t maxAttribs = (size_t)resources.MaxVertexAttribs;
963 
964     std::unordered_set<GLuint> explicitlyBound;
965     int numImplicitlyBound = 0;
966     for (const auto& elt : vertShaderLinkInfo.attributes) {
967         if (const auto loc = android::base::find(pData->boundAttribLocs, elt.name)) {
968             explicitlyBound.insert(*loc);
969         } else {
970             numImplicitlyBound++;
971         }
972     }
973     int numExplicitlyBound = explicitlyBound.size();
974 
975     if ((int)maxAttribs - numExplicitlyBound - numImplicitlyBound < 0) {
976         std::ostringstream err;
977         err << kExceededMaxVertexAttribs;
978         err << " Wanted (from vertex shader): ";
979         err << numExplicitlyBound + numImplicitlyBound << " ";
980         err << " Limit: " << maxAttribs << " ";
981         pData->appendValidationErrMsg(err);
982         res = false;
983     }
984 
985     return res;
986 }
987 
sCheckVariables(ProgramData * pData,const ANGLEShaderParser::ShaderLinkInfo & a,const ANGLEShaderParser::ShaderLinkInfo & b)988 static bool sCheckVariables(ProgramData* pData,
989                             const ANGLEShaderParser::ShaderLinkInfo& a,
990                             const ANGLEShaderParser::ShaderLinkInfo& b) {
991     bool res = true;
992 
993     for (const auto& aelt : a.uniforms) {
994         for (const auto& belt : b.uniforms) {
995             if (strcmp(aelt.name, belt.name)) continue;
996             res = res && sVarCheck(pData, ValidationQualifier::UNIFORM, aelt, belt);
997         }
998     }
999 
1000     for (const auto& aelt : a.varyings) {
1001         for (const auto& belt : b.varyings) {
1002             if (strcmp(aelt.name, belt.name)) continue;
1003             res = res && sVarCheck(pData, ValidationQualifier::VARYING, aelt, belt);
1004         }
1005     }
1006 
1007     for (const auto& aelt : a.interfaceBlocks) {
1008         for (const auto& belt : b.interfaceBlocks) {
1009             if (strcmp(aelt.name, belt.name)) continue;
1010             res = res && sInterfaceBlockCheck(pData, aelt, belt);
1011         }
1012     }
1013 
1014     return res;
1015 }
1016 
sRecursiveLocInitalize(ProgramData * pData,const std::string & keyBase,const ST_ShaderVariable & var)1017 static void sRecursiveLocInitalize(ProgramData* pData, const std::string& keyBase, const ST_ShaderVariable& var) {
1018     // fprintf(stderr, "%s: call. name: %s\n", __func__, var.name);
1019     bool isArr = var.arraySizeCount > 0;
1020     int baseSize = isArr ? var.pArraySizes[0] : 1;
1021     bool isStruct = var.fieldsCount > 0;
1022 
1023     if (isStruct) {
1024         // fprintf(stderr, "%s: is struct\n", __func__);
1025         if (isArr) {
1026             // fprintf(stderr, "%s: is arr\n", __func__);
1027             for (int k = 0; k < var.pArraySizes[0]; k++) {
1028                 for (uint32_t i = 0; i < var.fieldsCount; ++i) {
1029                     std::vector<char> keyBuf(keyBase.length() + strlen(var.pFields[i].name) + 20, 0);
1030                     snprintf(keyBuf.data(), keyBuf.size(), "%s[%d].%s", keyBase.c_str(), k, var.pFields[i].name);
1031                     sRecursiveLocInitalize(pData, std::string(keyBuf.data()), var.pFields[i]);
1032                 }
1033             }
1034         } else {
1035             // fprintf(stderr, "%s: is plain struct\n", __func__);
1036             for (uint32_t i = 0; i < var.fieldsCount; ++i) {
1037                 std::vector<char> keyBuf(keyBase.length() + strlen(var.pFields[i].name) + 20, 0);
1038                 snprintf(keyBuf.data(), keyBuf.size(), "%s.%s", keyBase.c_str(), var.pFields[i].name);
1039                 // fprintf(stderr, "%s: keyBuf: %s\n", __func__, keyBuf.data());
1040                 sRecursiveLocInitalize(pData, std::string(keyBuf.data()), var.pFields[i]);
1041             }
1042         }
1043     } else {
1044         // fprintf(stderr, "%s: is not struct\n", __func__);
1045         for (int k = 0; k < baseSize; k++) {
1046             if (k == 0) {
1047                 std::vector<char> keyBuf(keyBase.length() + 20, 0);
1048                 std::vector<char> keyBuf2(keyBase.length() + 20, 0);
1049                 snprintf(keyBuf.data(), keyBuf.size(), "%s", keyBase.c_str());
1050                 snprintf(keyBuf2.data(), keyBuf.size(), "%s[%d]", keyBase.c_str(), k);
1051                 // fprintf(stderr, "%s: initGuestUniformLocForKey. keyBuf2 %s\n", __func__, keyBuf2.data());
1052                 pData->initGuestUniformLocForKey(keyBuf.data(), keyBuf2.data());
1053             } else {
1054                 std::vector<char> keyBuf(keyBase.length() + 20, 0);
1055                 snprintf(keyBuf.data(), keyBuf.size(), "%s[%d]", keyBase.c_str(), k);
1056                 // fprintf(stderr, "%s: initGuestUniformLocForKey. keyBu2 %s\n", __func__, keyBuf.data());
1057                 pData->initGuestUniformLocForKey(keyBuf.data());
1058             }
1059         }
1060     }
1061 }
1062 
sInitializeUniformLocs(ProgramData * pData,const std::vector<ST_ShaderVariable> & uniforms)1063 static void sInitializeUniformLocs(ProgramData* pData,
1064                                    const std::vector<ST_ShaderVariable>& uniforms) {
1065     // fprintf(stderr, "%s: call\n", __func__);
1066     // initialize in order of indices
1067     std::vector<std::string> orderedUniforms;
1068     GLint uniform_count;
1069     GLint nameLength;
1070 
1071     GLDispatch& gl = GLEScontext::dispatcher();
1072     gl.glGetProgramiv(pData->getProgramName(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &nameLength);
1073     gl.glGetProgramiv(pData->getProgramName(), GL_ACTIVE_UNIFORMS, &uniform_count);
1074 
1075     std::vector<char> name(nameLength, 0);
1076 
1077     for (int i = 0; i < uniform_count; i++) {
1078         GLint size;
1079         GLenum type;
1080         GLsizei length;
1081         gl.glGetActiveUniform(pData->getProgramName(), i, nameLength, &length,
1082                 &size, &type, name.data());
1083         // fprintf(stderr, "%s: host uniform: %s\n", __func__, name.data());
1084         orderedUniforms.push_back(pData->getDetranslatedName(name.data()));
1085         // fprintf(stderr, "%s: host uniform detranslated: %s\n", __func__, pData->getDetranslatedName(name.data()).str().c_str());
1086     }
1087 
1088     std::unordered_map<std::string, size_t> linkInfoUniformsByName;
1089 
1090     size_t i = 0;
1091     for (const auto& var : uniforms) {
1092         linkInfoUniformsByName[var.name] = i;
1093         i++;
1094     }
1095 
1096     for (const auto& str : orderedUniforms) {
1097         // fprintf(stderr, "%s: do ordered uniforms\n", __func__);
1098         if (linkInfoUniformsByName.find(str) != linkInfoUniformsByName.end()) {
1099             sRecursiveLocInitalize(pData, str, uniforms[linkInfoUniformsByName[str]]);
1100         } else {
1101             // fprintf(stderr, "%s: found in link info uniforms\n", __func__);
1102         }
1103     }
1104 
1105     for (const auto& var : uniforms) {
1106         sRecursiveLocInitalize(pData, var.name, var);
1107     }
1108 }
1109 
initGuestUniformLocForKey(const std::string & key)1110 void ProgramData::initGuestUniformLocForKey(const std::string& key) {
1111     // fprintf(stderr, "%s: for %s\n", __func__, key.str().c_str());
1112     if (mUniNameToGuestLoc.find(key) == mUniNameToGuestLoc.end()) {
1113         mUniNameToGuestLoc[key] = mCurrUniformBaseLoc;
1114         // Emplace host location beforehand to workaround Unreal bug
1115         // BUG: 120548998
1116         GLDispatch& dispatcher = GLEScontext::dispatcher();
1117         std::string translatedName = getTranslatedName(key);
1118         // fprintf(stderr, "%s: trname: %s\n", __func__, translatedName.c_str());
1119         int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1120                 translatedName.c_str());
1121         if (hostLoc != -1) {
1122             mGuestLocToHostLoc.add(mCurrUniformBaseLoc, hostLoc);
1123         }
1124 
1125         mCurrUniformBaseLoc++;
1126     }
1127 }
1128 
initGuestUniformLocForKey(const std::string & key,const std::string & key2)1129 void ProgramData::initGuestUniformLocForKey(const std::string& key, const std::string& key2) {
1130     bool newUniform = false;
1131     if (mUniNameToGuestLoc.find(key) == mUniNameToGuestLoc.end()) {
1132         mUniNameToGuestLoc[key] = mCurrUniformBaseLoc;
1133         newUniform = true;
1134     }
1135     if (mUniNameToGuestLoc.find(key2) == mUniNameToGuestLoc.end()) {
1136         mUniNameToGuestLoc[key2] = mCurrUniformBaseLoc;
1137         newUniform = true;
1138     }
1139 
1140     if (newUniform) {
1141         // Emplace host location beforehand to workaround Unreal bug
1142         // BUG: 120548998
1143         GLDispatch& dispatcher = GLEScontext::dispatcher();
1144         std::string translatedName = getTranslatedName(key);
1145         int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1146                 translatedName.c_str());
1147         if (hostLoc != -1) {
1148             mGuestLocToHostLoc.add(mCurrUniformBaseLoc, hostLoc);
1149         }
1150 
1151         mCurrUniformBaseLoc++;
1152     }
1153 }
1154 
getGuestUniformLocation(const char * uniName)1155 int ProgramData::getGuestUniformLocation(const char* uniName) {
1156     GLDispatch& dispatcher = GLEScontext::dispatcher();
1157     if (mUseUniformLocationVirtualization) {
1158         if (mUseDirectDriverUniformInfo) {
1159             int guestLoc;
1160             const auto& activeLoc = mUniNameToGuestLoc.find(uniName);
1161             // If using direct driver uniform info, don't overwrite any
1162             // previously known guest location.
1163             if (activeLoc != mUniNameToGuestLoc.end()) {
1164                 guestLoc = activeLoc->second;
1165             } else {
1166                 guestLoc =
1167                     dispatcher.glGetUniformLocation(ProgramName, uniName);
1168                 if (guestLoc == -1) {
1169                     return -1;
1170                 } else {
1171                     mUniNameToGuestLoc[uniName] = guestLoc;
1172                     mGuestLocToHostLoc.add(guestLoc, guestLoc);
1173                 }
1174             }
1175             return guestLoc;
1176         } else {
1177             int guestLoc;
1178 
1179             const auto& activeLoc = mUniNameToGuestLoc.find(uniName);
1180 
1181             if (activeLoc != mUniNameToGuestLoc.end()) {
1182                 guestLoc = activeLoc->second;
1183             } else {
1184                 guestLoc = -1;
1185             }
1186 
1187             std::string translatedName = getTranslatedName(uniName);
1188             int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1189                     translatedName.c_str());
1190             if (hostLoc == -1) {
1191                 return -1;
1192             }
1193 
1194             mGuestLocToHostLoc.add(guestLoc, hostLoc);
1195             return guestLoc;
1196         }
1197     } else {
1198         return dispatcher.glGetUniformLocation(
1199                 ProgramName, getTranslatedName(uniName).c_str());
1200     }
1201 }
1202 
getHostUniformLocation(int guestLocation)1203 int ProgramData::getHostUniformLocation(int guestLocation) {
1204     if (mUseUniformLocationVirtualization) {
1205         if (guestLocation == -1) return -1;
1206 
1207         auto locPtr = mGuestLocToHostLoc.get_const(guestLocation);
1208         if (!locPtr) return -2;
1209         return *locPtr;
1210     } else {
1211         return guestLocation;
1212     }
1213 }
1214