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 "aemu/base/containers/Lookup.h"
21 #include "aemu/base/files/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 #ifdef USE_ANGLE_SHADER_PARSER
423                 std::string infoLog;
424                 ANGLEShaderParser::translate(
425                             isCoreProfile(),
426                             src,
427                             type,
428                             &infoLog,
429                             &parsedSrc,
430                             &s.linkInfo);
431                 src = parsedSrc.c_str();
432 #endif
433             }
434             dispatcher.glShaderSource(tmpShaders[i], 1, &src, NULL);
435             dispatcher.glCompileShader(tmpShaders[i]);
436             dispatcher.glAttachShader(globalName, tmpShaders[i]);
437         }
438         for (const auto& attribLocs : linkedAttribLocs) {
439             // Prefix "gl_" is reserved, we should skip those.
440             // https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glBindAttribLocation.xhtml
441             if  (strncmp(attribLocs.first.c_str(), "gl_", 3) == 0) {
442                 continue;
443             }
444             dispatcher.glBindAttribLocation(globalName, attribLocs.second,
445                     attribLocs.first.c_str());
446         }
447         if (mGlesMajorVersion >= 3) {
448             std::vector<const char*> varyings;
449             varyings.resize(mTransformFeedbacks.size());
450             for (size_t i = 0; i < mTransformFeedbacks.size(); i++) {
451                 varyings[i] = mTransformFeedbacks[i].c_str();
452             }
453             dispatcher.glTransformFeedbackVaryings(
454                     globalName, mTransformFeedbacks.size(), varyings.data(),
455                     mTransformFeedbackBufferMode);
456             mTransformFeedbacks.clear();
457         }
458         dispatcher.glLinkProgram(globalName);
459         dispatcher.glUseProgram(globalName);
460 #ifdef DEBUG
461         for (const auto& attribLocs : linkedAttribLocs) {
462             assert(dispatcher.glGetAttribLocation(globalName,
463                 attribLocs.first.c_str()) == attribLocs.second);
464         }
465 #endif // DEBUG
466         for (const auto& uniform : mUniNameToGuestLoc) {
467             GLint hostLoc = dispatcher.glGetUniformLocation(
468                     globalName, getTranslatedName(uniform.first).c_str());
469             if (hostLoc != -1) {
470                 mGuestLocToHostLoc.add(uniform.second, hostLoc);
471             }
472         }
473         for (const auto& uniformEntry : uniforms) {
474             const auto& uniform = uniformEntry.second;
475             GLint location = dispatcher.glGetUniformLocation(
476                     globalName, getTranslatedName(uniform.mGuestName).c_str());
477             if (location == -1) {
478                 // Location changed after loading from a snapshot.
479                 // likely loading from different GPU backend (and they
480                 // optimize out different stuff)
481                 continue;
482             }
483 
484             switch (uniform.mType) {
485                 case GL_FLOAT:
486                     dispatcher.glUniform1fv(location, uniform.mCount,
487                             (const GLfloat*)uniform.mVal.data());
488                     break;
489                 case GL_FLOAT_VEC2:
490                     dispatcher.glUniform2fv(location, uniform.mCount,
491                             (const GLfloat*)uniform.mVal.data());
492                     break;
493                 case GL_FLOAT_VEC3:
494                     dispatcher.glUniform3fv(location, uniform.mCount,
495                             (const GLfloat*)uniform.mVal.data());
496                     break;
497                 case GL_FLOAT_VEC4:
498                     dispatcher.glUniform4fv(location, uniform.mCount,
499                             (const GLfloat*)uniform.mVal.data());
500                     break;
501                 case GL_BOOL:
502                 case GL_INT:
503                 case GL_SAMPLER_2D:
504                 case GL_SAMPLER_3D:
505                 case GL_SAMPLER_CUBE:
506                 case GL_SAMPLER_2D_SHADOW:
507                 case GL_SAMPLER_2D_ARRAY:
508                 case GL_SAMPLER_2D_ARRAY_SHADOW:
509                 case GL_SAMPLER_CUBE_SHADOW:
510                 case GL_INT_SAMPLER_2D:
511                 case GL_INT_SAMPLER_3D:
512                 case GL_INT_SAMPLER_CUBE:
513                 case GL_INT_SAMPLER_2D_ARRAY:
514                 case GL_UNSIGNED_INT_SAMPLER_2D:
515                 case GL_UNSIGNED_INT_SAMPLER_3D:
516                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
517                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
518                     dispatcher.glUniform1iv(location, uniform.mCount,
519                             (const GLint*)uniform.mVal.data());
520                     break;
521                 case GL_BOOL_VEC2:
522                 case GL_INT_VEC2:
523                     dispatcher.glUniform2iv(location, uniform.mCount,
524                             (const GLint*)uniform.mVal.data());
525                     break;
526                 case GL_BOOL_VEC3:
527                 case GL_INT_VEC3:
528                     dispatcher.glUniform3iv(location, uniform.mCount,
529                             (const GLint*)uniform.mVal.data());
530                     break;
531                 case GL_BOOL_VEC4:
532                 case GL_INT_VEC4:
533                     dispatcher.glUniform4iv(location, uniform.mCount,
534                             (const GLint*)uniform.mVal.data());
535                     break;
536                 case GL_UNSIGNED_INT:
537                     dispatcher.glUniform1uiv(location, uniform.mCount,
538                             (const GLuint*)uniform.mVal.data());
539                     break;
540                 case GL_UNSIGNED_INT_VEC2:
541                     dispatcher.glUniform2uiv(location, uniform.mCount,
542                             (const GLuint*)uniform.mVal.data());
543                     break;
544                 case GL_UNSIGNED_INT_VEC3:
545                     dispatcher.glUniform3uiv(location, uniform.mCount,
546                             (const GLuint*)uniform.mVal.data());
547                     break;
548                 case GL_UNSIGNED_INT_VEC4:
549                     dispatcher.glUniform4uiv(location, uniform.mCount,
550                             (const GLuint*)uniform.mVal.data());
551                     break;
552                 case GL_FLOAT_MAT2:
553                     dispatcher.glUniformMatrix2fv(location,
554                             uniform.mCount, uniform.mTranspose,
555                             (const GLfloat*)uniform.mVal.data());
556                     break;
557                 case GL_FLOAT_MAT3:
558                     dispatcher.glUniformMatrix3fv(location,
559                             uniform.mCount, uniform.mTranspose,
560                             (const GLfloat*)uniform.mVal.data());
561                     break;
562                 case GL_FLOAT_MAT4:
563                     dispatcher.glUniformMatrix4fv(location,
564                             uniform.mCount, uniform.mTranspose,
565                             (const GLfloat*)uniform.mVal.data());
566                     break;
567                 case GL_FLOAT_MAT2x3:
568                     dispatcher.glUniformMatrix2x3fv(location,
569                             uniform.mCount, uniform.mTranspose,
570                             (const GLfloat*)uniform.mVal.data());
571                     break;
572                 case GL_FLOAT_MAT2x4:
573                     dispatcher.glUniformMatrix2x4fv(location,
574                             uniform.mCount, uniform.mTranspose,
575                             (const GLfloat*)uniform.mVal.data());
576                     break;
577                 case GL_FLOAT_MAT3x2:
578                     dispatcher.glUniformMatrix3x2fv(location,
579                             uniform.mCount, uniform.mTranspose,
580                             (const GLfloat*)uniform.mVal.data());
581                     break;
582                 case GL_FLOAT_MAT3x4:
583                     dispatcher.glUniformMatrix3x4fv(location,
584                             uniform.mCount, uniform.mTranspose,
585                             (const GLfloat*)uniform.mVal.data());
586                     break;
587                 case GL_FLOAT_MAT4x2:
588                     dispatcher.glUniformMatrix4x2fv(location,
589                             uniform.mCount, uniform.mTranspose,
590                             (const GLfloat*)uniform.mVal.data());
591                     break;
592                 case GL_FLOAT_MAT4x3:
593                     dispatcher.glUniformMatrix4x3fv(location,
594                             uniform.mCount, uniform.mTranspose,
595                             (const GLfloat*)uniform.mVal.data());
596                     break;
597                 default:
598                     fprintf(stderr, "ProgramData::restore: warning: "
599                             "unsupported uniform type 0x%x\n", uniform.mType);
600             }
601         }
602         for (const auto& uniformBlock : mUniformBlockBinding) {
603             dispatcher.glUniformBlockBinding(globalName, uniformBlock.first,
604                     uniformBlock.second);
605         }
606         for (auto s : tmpShaders) {
607             if (s != 0) {
608                 dispatcher.glDetachShader(globalName, s);
609                 dispatcher.glDeleteShader(s);
610             }
611         }
612     }
613     uniforms.clear();
614     mUniformBlockBinding.clear();
615     // We are done with the "linked" program, now we handle the one
616     // that is yet to compile
617     for (const auto& s : attachedShaders) {
618         if (s.localName) {
619             int shaderGlobalName = getGlobalName(
620                     NamedObjectType::SHADER_OR_PROGRAM, s.localName);
621             assert(shaderGlobalName);
622             dispatcher.glAttachShader(globalName, shaderGlobalName);
623         }
624     }
625     for (const auto& attribLocs : boundAttribLocs) {
626         dispatcher.glBindAttribLocation(globalName, attribLocs.second,
627                 attribLocs.first.c_str());
628     }
629 }
630 
getGenNameInfo() const631 GenNameInfo ProgramData::getGenNameInfo() const {
632     return GenNameInfo(ShaderProgramType::PROGRAM);
633 }
634 
setErrInfoLog()635 void ProgramData::setErrInfoLog() {
636     infoLog.clear();
637     infoLog = std::string(validationInfoLog);
638 }
639 
setInfoLog(const GLchar * log)640 void ProgramData::setInfoLog(const GLchar* log) {
641     infoLog = std::string(log);
642 }
643 
getInfoLog() const644 const GLchar* ProgramData::getInfoLog() const {
645     return infoLog.c_str();
646 }
647 
getAttachedVertexShader() const648 GLuint ProgramData::getAttachedVertexShader() const {
649     return attachedShaders[VERTEX].localName;
650 }
651 
getAttachedFragmentShader() const652 GLuint ProgramData::getAttachedFragmentShader() const {
653     return attachedShaders[FRAGMENT].localName;
654 }
655 
getAttachedComputeShader() const656 GLuint ProgramData::getAttachedComputeShader() const {
657     return attachedShaders[COMPUTE].localName;
658 }
659 
getAttachedShader(GLenum type) const660 GLuint ProgramData::getAttachedShader(GLenum type) const {
661     return attachedShaders[s_glShaderType2ShaderType(type)].localName;
662 }
663 
664 std::string
getTranslatedName(const std::string & userVarName) const665 ProgramData::getTranslatedName(const std::string& userVarName) const {
666     if (isGles2Gles()) {
667         return userVarName;
668     }
669     // TODO: translate uniform array names
670 #ifdef USE_ANGLE_SHADER_PARSER
671     for (int i = 0; i < NUM_SHADER_TYPE; i++) {
672         if (const auto name = android::base::find(
673                 attachedShaders[i].linkInfo.nameMap, userVarName)) {
674             return *name;
675         }
676     }
677 #endif
678     return userVarName;
679 }
680 
681 std::string
getDetranslatedName(const std::string & driverName) const682 ProgramData::getDetranslatedName(const std::string& driverName) const {
683     if (isGles2Gles()) {
684         return driverName;
685     }
686 
687 #ifdef USE_ANGLE_SHADER_PARSER
688     // TODO: detranslate uniform array names
689     for (int i = 0; i < NUM_SHADER_TYPE; i++) {
690         if (const auto name = android::base::find(
691                 attachedShaders[i].linkInfo.nameMapReverse, driverName)) {
692             return *name;
693         }
694     }
695 #endif
696     return driverName;
697 }
698 
attachShader(GLuint shader,ShaderParser * shaderData,GLenum type)699 bool ProgramData::attachShader(GLuint shader, ShaderParser* shaderData,
700         GLenum type) {
701     AttachedShader& s = attachedShaders[s_glShaderType2ShaderType(type)];
702     if (s.localName == 0) {
703         s.localName = shader;
704         s.shader = shaderData;
705         return true;
706     }
707     return false;
708 }
709 
isAttached(GLuint shader) const710 bool ProgramData::isAttached(GLuint shader) const {
711     for (const auto& s : attachedShaders) {
712         if (s.localName == shader) return true;
713     }
714     return false;
715 }
716 
detachShader(GLuint shader)717 bool ProgramData::detachShader(GLuint shader) {
718     for (auto& s : attachedShaders) {
719         if (s.localName == shader) {
720             s.localName = 0;
721             s.shader = nullptr;
722             return true;
723         }
724     }
725     return false;
726 }
727 
bindAttribLocation(const std::string & var,GLuint loc)728 void ProgramData::bindAttribLocation(const std::string& var, GLuint loc) {
729     boundAttribLocs[var] = loc;
730 }
731 
linkedAttribLocation(const std::string & var,GLuint loc)732 void ProgramData::linkedAttribLocation(const std::string& var, GLuint loc) {
733     linkedAttribLocs[var] = loc;
734 }
735 
736 // Link-time validation
appendValidationErrMsg(std::ostringstream & ss)737 void ProgramData::appendValidationErrMsg(std::ostringstream& ss) {
738     validationInfoLog += "Error: " + ss.str() + "\n";
739 }
740 
741 #ifdef USE_ANGLE_SHADER_PARSER
742 static bool sCheckUndecl(ProgramData* pData,
743                          const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
744                          const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo);
745 static bool sCheckLimits(ProgramData* pData,
746                          const ST_BuiltInResources& resources,
747                          const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
748                          const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo);
749 static bool sCheckVariables(ProgramData* pData,
750                             const ANGLEShaderParser::ShaderLinkInfo& a,
751                             const ANGLEShaderParser::ShaderLinkInfo& b);
752 static void sInitializeUniformLocs(ProgramData* pData,
753                                    const std::vector<ST_ShaderVariable>& uniforms);
754 #endif
755 
validateLink(ShaderParser * frag,ShaderParser * vert)756 bool ProgramData::validateLink(ShaderParser* frag, ShaderParser* vert) {
757     bool res = true;
758 
759 #ifdef USE_ANGLE_SHADER_PARSER
760     const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo =
761         frag->getShaderLinkInfo();
762     const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo =
763         vert->getShaderLinkInfo();
764 
765 
766     res = res && sCheckUndecl(this, fragLinkInfo, vertLinkInfo);
767     res = res && sCheckLimits(this, ANGLEShaderParser::kResources,
768                               fragLinkInfo, vertLinkInfo);
769     res = res && sCheckVariables(this, fragLinkInfo, vertLinkInfo);
770 #endif
771 
772     return res;
773 }
774 
setHostLinkStatus(GLint status)775 void ProgramData::setHostLinkStatus(GLint status) {
776     HostLinkStatus = (status == GL_FALSE) ? false : true;
777 }
778 
setLinkStatus(GLint status)779 void ProgramData::setLinkStatus(GLint status) {
780     LinkStatus = (status == GL_FALSE) ? false : true;
781     mUniNameToGuestLoc.clear();
782     mGuestLocToHostLoc.clear();
783     mGuestLocToHostLoc.add(-1, -1);
784 #if defined(TOLERATE_PROGRAM_LINK_ERROR) && TOLERATE_PROGRAM_LINK_ERROR == 1
785     status = 1;
786 #endif
787     if (status && HostLinkStatus) {
788         bool is310 = false;
789 
790 #ifdef USE_ANGLE_SHADER_PARSER
791 	std::vector<ST_ShaderVariable> allUniforms;
792 #endif
793         for (auto& s : attachedShaders) {
794             if (s.localName) {
795                 assert(s.shader);
796                 s.linkedSource = s.shader->getOriginalSrc();
797 #ifdef USE_ANGLE_SHADER_PARSER
798                 s.linkInfo = s.shader->getShaderLinkInfo();
799                 is310 = is310 || (s.linkInfo.esslVersion == 310);
800                 for (const auto& var: s.linkInfo.uniforms) {
801                     allUniforms.push_back(var);
802                 }
803 #endif
804             }
805         }
806 
807         if (is310 || isGles2Gles()) {
808             mUseDirectDriverUniformInfo = true;
809         } else {
810 #ifdef USE_ANGLE_SHADER_PARSER
811             sInitializeUniformLocs(this, allUniforms);
812 #endif
813         }
814         for (const auto &attribLoc : boundAttribLocs) {
815             // overwrite
816             linkedAttribLocs[attribLoc.first] = attribLoc.second;
817         }
818     } else {
819         for (auto& s : attachedShaders) {
820             s.linkedSource.clear();
821         }
822     }
823 }
824 
getLinkStatus() const825 bool ProgramData::getLinkStatus() const {
826     return LinkStatus;
827 }
828 
829 static const char kDifferentPrecisionErr[] =
830     "specified with different precision in different shaders.";
831 static const char kDifferentTypeErr[] =
832     "specified with different type in different shaders.";
833 static const char kDifferentLayoutQualifierErr[] =
834     "specified with different layout qualifiers in different shaders.";
835 static const char kExceededMaxVertexAttribs[] =
836     "exceeded max vertex attribs.";
837 static const char kUsedUndeclaredErr[] =
838     "used, but not declared.";
839 static const char kUniformQualifier[] = "uniform";
840 static const char kVaryingQualifier[] = "varying";
841 static const char kUnknownQualifier[] = "[unknown qualifier]";
842 enum ValidationQualifier {
843     UNIFORM,
844     VARYING,
845 };
846 
sQualifierString(ValidationQualifier q)847 static const char* sQualifierString(ValidationQualifier q) {
848     switch (q) {
849     case ValidationQualifier::UNIFORM:
850         return kUniformQualifier;
851     case ValidationQualifier::VARYING:
852         return kVaryingQualifier;
853     }
854     return kUnknownQualifier;
855 }
856 
857 #ifdef USE_ANGLE_SHADER_PARSER
858 
sVarCheck(ProgramData * pData,ValidationQualifier qualifier,const ST_ShaderVariable & a,const ST_ShaderVariable & b)859 static bool sVarCheck(ProgramData* pData,
860                       ValidationQualifier qualifier,
861                       const ST_ShaderVariable& a,
862                       const ST_ShaderVariable& b) {
863     bool res = true;
864 
865     if (qualifier == ValidationQualifier::UNIFORM &&
866         a.precision != b.precision) {
867         std::ostringstream err;
868         err << sQualifierString(qualifier) << " " << a.name << " ";
869         err << kDifferentPrecisionErr;
870         pData->appendValidationErrMsg(err);
871         res = false;
872     }
873 
874     bool aIsStruct = a.fieldsCount > 0;
875     bool bIsStruct = b.fieldsCount > 0;
876 
877     if (aIsStruct != bIsStruct ||
878         a.type != b.type) {
879         std::ostringstream err;
880         err << sQualifierString(qualifier) << " " << a.name << " ";
881         err << kDifferentTypeErr;
882         pData->appendValidationErrMsg(err);
883         res = false;
884     }
885 
886     if (aIsStruct) {
887         for (unsigned int i = 0; i < a.fieldsCount; ++i) {
888             for (unsigned int j = 0; j < b.fieldsCount; ++j) {
889                 if (strcmp(a.pFields[i].name, b.pFields[j].name)) continue;
890                 res = res && sVarCheck(pData, qualifier, a.pFields[i], b.pFields[j]);
891             }
892         }
893     }
894 
895     return res;
896 }
897 
sInterfaceBlockCheck(ProgramData * pData,const ST_InterfaceBlock & a,const ST_InterfaceBlock & b)898 static bool sInterfaceBlockCheck(ProgramData* pData,
899                                  const ST_InterfaceBlock& a,
900                                  const ST_InterfaceBlock& b) {
901     bool res = true;
902 
903     if (a.layout != b.layout ||
904         a.isRowMajorLayout != b.isRowMajorLayout) {
905         std::ostringstream err;
906         err << "interface block " << a.name << " ";
907         err << kDifferentLayoutQualifierErr;
908         pData->appendValidationErrMsg(err);
909         res = false;
910     }
911 
912     if (a.fieldsCount != b.fieldsCount) {
913         std::ostringstream err;
914         err << "interface block " << a.name << " ";
915         err << kDifferentTypeErr;
916         pData->appendValidationErrMsg(err);
917         res = false;
918     }
919 
920     for (unsigned int i = 0; i < a.fieldsCount; ++i) {
921         for (unsigned int j = 0; j < b.fieldsCount; ++j) {
922             const auto afield = a.pFields[i];
923             const auto bfield = b.pFields[j];
924 
925             if (strcmp(afield.name, bfield.name)) continue;
926             res = res && sVarCheck(pData, ValidationQualifier::VARYING,
927                     afield, bfield);
928             if (afield.isRowMajorLayout != bfield.isRowMajorLayout) {
929                 std::ostringstream err;
930                 err << "interface block field ";
931                 err << a.name << "." << afield.name << " ";
932                 err << kDifferentLayoutQualifierErr;
933                 pData->appendValidationErrMsg(err);
934                 res = false;
935             }
936         }
937     }
938 
939     return res;
940 }
941 
sIsBuiltInShaderVariable(const ST_ShaderVariable & var)942 static bool sIsBuiltInShaderVariable(const ST_ShaderVariable& var) {
943     if (!var.name || strlen(var.name) < 4) return false;
944 
945     const char* name = var.name;
946     return (name[0] == 'g' && name[1] == 'l' && name[2] == '_');
947 }
948 
sCheckUndecl(ProgramData * pData,const ANGLEShaderParser::ShaderLinkInfo & fragLinkInfo,const ANGLEShaderParser::ShaderLinkInfo & vertLinkInfo)949 static bool sCheckUndecl(
950         ProgramData* pData,
951         const ANGLEShaderParser::ShaderLinkInfo& fragLinkInfo,
952         const ANGLEShaderParser::ShaderLinkInfo& vertLinkInfo) {
953     bool res = true;
954     for (const auto& felt : fragLinkInfo.varyings) {
955         if (sIsBuiltInShaderVariable(felt)) continue;
956 
957         bool declaredInVertShader = false;
958         for (const auto& velt : vertLinkInfo.varyings) {
959             if (!strcmp(velt.name, felt.name)) {
960                 declaredInVertShader = true;
961                 break;
962             }
963         }
964 
965         if (!declaredInVertShader && felt.staticUse) {
966             std::ostringstream err;
967             err << "varying " << felt.name << " ";
968             err << kUsedUndeclaredErr;
969             pData->appendValidationErrMsg(err);
970             res = false;
971         }
972     }
973     return res;
974 }
975 
sCheckLimits(ProgramData * pData,const ST_BuiltInResources & resources,const ANGLEShaderParser::ShaderLinkInfo & fragShaderLinkInfo,const ANGLEShaderParser::ShaderLinkInfo & vertShaderLinkInfo)976 static bool sCheckLimits(
977         ProgramData* pData,
978         const ST_BuiltInResources& resources,
979         const ANGLEShaderParser::ShaderLinkInfo& fragShaderLinkInfo,
980         const ANGLEShaderParser::ShaderLinkInfo& vertShaderLinkInfo) {
981 
982     bool res = true;
983 
984     size_t maxAttribs = (size_t)resources.MaxVertexAttribs;
985 
986     std::unordered_set<GLuint> explicitlyBound;
987     int numImplicitlyBound = 0;
988     for (const auto& elt : vertShaderLinkInfo.attributes) {
989         if (const auto loc = android::base::find(pData->boundAttribLocs, elt.name)) {
990             explicitlyBound.insert(*loc);
991         } else {
992             numImplicitlyBound++;
993         }
994     }
995     int numExplicitlyBound = explicitlyBound.size();
996 
997     if ((int)maxAttribs - numExplicitlyBound - numImplicitlyBound < 0) {
998         std::ostringstream err;
999         err << kExceededMaxVertexAttribs;
1000         err << " Wanted (from vertex shader): ";
1001         err << numExplicitlyBound + numImplicitlyBound << " ";
1002         err << " Limit: " << maxAttribs << " ";
1003         pData->appendValidationErrMsg(err);
1004         res = false;
1005     }
1006 
1007     return res;
1008 }
1009 
sCheckVariables(ProgramData * pData,const ANGLEShaderParser::ShaderLinkInfo & a,const ANGLEShaderParser::ShaderLinkInfo & b)1010 static bool sCheckVariables(ProgramData* pData,
1011                             const ANGLEShaderParser::ShaderLinkInfo& a,
1012                             const ANGLEShaderParser::ShaderLinkInfo& b) {
1013     bool res = true;
1014 
1015     for (const auto& aelt : a.uniforms) {
1016         for (const auto& belt : b.uniforms) {
1017             if (strcmp(aelt.name, belt.name)) continue;
1018             res = res && sVarCheck(pData, ValidationQualifier::UNIFORM, aelt, belt);
1019         }
1020     }
1021 
1022     for (const auto& aelt : a.varyings) {
1023         for (const auto& belt : b.varyings) {
1024             if (strcmp(aelt.name, belt.name)) continue;
1025             res = res && sVarCheck(pData, ValidationQualifier::VARYING, aelt, belt);
1026         }
1027     }
1028 
1029     for (const auto& aelt : a.interfaceBlocks) {
1030         for (const auto& belt : b.interfaceBlocks) {
1031             if (strcmp(aelt.name, belt.name)) continue;
1032             res = res && sInterfaceBlockCheck(pData, aelt, belt);
1033         }
1034     }
1035 
1036     return res;
1037 }
1038 
sRecursiveLocInitalize(ProgramData * pData,const std::string & keyBase,const ST_ShaderVariable & var)1039 static void sRecursiveLocInitalize(ProgramData* pData, const std::string& keyBase, const ST_ShaderVariable& var) {
1040     // fprintf(stderr, "%s: call. name: %s\n", __func__, var.name);
1041     bool isArr = var.arraySizeCount > 0;
1042     int baseSize = isArr ? var.pArraySizes[0] : 1;
1043     bool isStruct = var.fieldsCount > 0;
1044 
1045     if (isStruct) {
1046         // fprintf(stderr, "%s: is struct\n", __func__);
1047         if (isArr) {
1048             // fprintf(stderr, "%s: is arr\n", __func__);
1049             for (int k = 0; k < var.pArraySizes[0]; k++) {
1050                 for (uint32_t i = 0; i < var.fieldsCount; ++i) {
1051                     std::vector<char> keyBuf(keyBase.length() + strlen(var.pFields[i].name) + 20, 0);
1052                     snprintf(keyBuf.data(), keyBuf.size(), "%s[%d].%s", keyBase.c_str(), k, var.pFields[i].name);
1053                     sRecursiveLocInitalize(pData, std::string(keyBuf.data()), var.pFields[i]);
1054                 }
1055             }
1056         } else {
1057             // fprintf(stderr, "%s: is plain struct\n", __func__);
1058             for (uint32_t i = 0; i < var.fieldsCount; ++i) {
1059                 std::vector<char> keyBuf(keyBase.length() + strlen(var.pFields[i].name) + 20, 0);
1060                 snprintf(keyBuf.data(), keyBuf.size(), "%s.%s", keyBase.c_str(), var.pFields[i].name);
1061                 // fprintf(stderr, "%s: keyBuf: %s\n", __func__, keyBuf.data());
1062                 sRecursiveLocInitalize(pData, std::string(keyBuf.data()), var.pFields[i]);
1063             }
1064         }
1065     } else {
1066         // fprintf(stderr, "%s: is not struct\n", __func__);
1067         for (int k = 0; k < baseSize; k++) {
1068             if (k == 0) {
1069                 std::vector<char> keyBuf(keyBase.length() + 20, 0);
1070                 std::vector<char> keyBuf2(keyBase.length() + 20, 0);
1071                 snprintf(keyBuf.data(), keyBuf.size(), "%s", keyBase.c_str());
1072                 snprintf(keyBuf2.data(), keyBuf.size(), "%s[%d]", keyBase.c_str(), k);
1073                 // fprintf(stderr, "%s: initGuestUniformLocForKey. keyBuf2 %s\n", __func__, keyBuf2.data());
1074                 pData->initGuestUniformLocForKey(keyBuf.data(), keyBuf2.data());
1075             } else {
1076                 std::vector<char> keyBuf(keyBase.length() + 20, 0);
1077                 snprintf(keyBuf.data(), keyBuf.size(), "%s[%d]", keyBase.c_str(), k);
1078                 // fprintf(stderr, "%s: initGuestUniformLocForKey. keyBu2 %s\n", __func__, keyBuf.data());
1079                 pData->initGuestUniformLocForKey(keyBuf.data());
1080             }
1081         }
1082     }
1083 }
1084 
sInitializeUniformLocs(ProgramData * pData,const std::vector<ST_ShaderVariable> & uniforms)1085 static void sInitializeUniformLocs(ProgramData* pData,
1086                                    const std::vector<ST_ShaderVariable>& uniforms) {
1087     // fprintf(stderr, "%s: call\n", __func__);
1088     // initialize in order of indices
1089     std::vector<std::string> orderedUniforms;
1090     GLint uniform_count;
1091     GLint nameLength;
1092 
1093     GLDispatch& gl = GLEScontext::dispatcher();
1094     gl.glGetProgramiv(pData->getProgramName(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &nameLength);
1095     gl.glGetProgramiv(pData->getProgramName(), GL_ACTIVE_UNIFORMS, &uniform_count);
1096 
1097     std::vector<char> name(nameLength, 0);
1098 
1099     for (int i = 0; i < uniform_count; i++) {
1100         GLint size;
1101         GLenum type;
1102         GLsizei length;
1103         gl.glGetActiveUniform(pData->getProgramName(), i, nameLength, &length,
1104                 &size, &type, name.data());
1105         // fprintf(stderr, "%s: host uniform: %s\n", __func__, name.data());
1106         orderedUniforms.push_back(pData->getDetranslatedName(name.data()));
1107         // fprintf(stderr, "%s: host uniform detranslated: %s\n", __func__, pData->getDetranslatedName(name.data()).str().c_str());
1108     }
1109 
1110     std::unordered_map<std::string, size_t> linkInfoUniformsByName;
1111 
1112     size_t i = 0;
1113     for (const auto& var : uniforms) {
1114         linkInfoUniformsByName[var.name] = i;
1115         i++;
1116     }
1117 
1118     for (const auto& str : orderedUniforms) {
1119         // fprintf(stderr, "%s: do ordered uniforms\n", __func__);
1120         if (linkInfoUniformsByName.find(str) != linkInfoUniformsByName.end()) {
1121             sRecursiveLocInitalize(pData, str, uniforms[linkInfoUniformsByName[str]]);
1122         } else {
1123             // fprintf(stderr, "%s: found in link info uniforms\n", __func__);
1124         }
1125     }
1126 
1127     for (const auto& var : uniforms) {
1128         sRecursiveLocInitalize(pData, var.name, var);
1129     }
1130 }
1131 
1132 #endif
1133 
initGuestUniformLocForKey(const std::string & key)1134 void ProgramData::initGuestUniformLocForKey(const std::string& key) {
1135     // fprintf(stderr, "%s: for %s\n", __func__, key.str().c_str());
1136     if (mUniNameToGuestLoc.find(key) == mUniNameToGuestLoc.end()) {
1137         mUniNameToGuestLoc[key] = mCurrUniformBaseLoc;
1138         // Emplace host location beforehand to workaround Unreal bug
1139         // BUG: 120548998
1140         GLDispatch& dispatcher = GLEScontext::dispatcher();
1141         std::string translatedName = getTranslatedName(key);
1142         // fprintf(stderr, "%s: trname: %s\n", __func__, translatedName.c_str());
1143         int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1144                 translatedName.c_str());
1145         if (hostLoc != -1) {
1146             mGuestLocToHostLoc.add(mCurrUniformBaseLoc, hostLoc);
1147         }
1148 
1149         mCurrUniformBaseLoc++;
1150     }
1151 }
1152 
initGuestUniformLocForKey(const std::string & key,const std::string & key2)1153 void ProgramData::initGuestUniformLocForKey(const std::string& key, const std::string& key2) {
1154     bool newUniform = false;
1155     if (mUniNameToGuestLoc.find(key) == mUniNameToGuestLoc.end()) {
1156         mUniNameToGuestLoc[key] = mCurrUniformBaseLoc;
1157         newUniform = true;
1158     }
1159     if (mUniNameToGuestLoc.find(key2) == mUniNameToGuestLoc.end()) {
1160         mUniNameToGuestLoc[key2] = mCurrUniformBaseLoc;
1161         newUniform = true;
1162     }
1163 
1164     if (newUniform) {
1165         // Emplace host location beforehand to workaround Unreal bug
1166         // BUG: 120548998
1167         GLDispatch& dispatcher = GLEScontext::dispatcher();
1168         std::string translatedName = getTranslatedName(key);
1169         int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1170                 translatedName.c_str());
1171         if (hostLoc != -1) {
1172             mGuestLocToHostLoc.add(mCurrUniformBaseLoc, hostLoc);
1173         }
1174 
1175         mCurrUniformBaseLoc++;
1176     }
1177 }
1178 
getGuestUniformLocation(const char * uniName)1179 int ProgramData::getGuestUniformLocation(const char* uniName) {
1180     GLDispatch& dispatcher = GLEScontext::dispatcher();
1181     if (mUseUniformLocationVirtualization) {
1182         if (mUseDirectDriverUniformInfo) {
1183             int guestLoc;
1184             const auto& activeLoc = mUniNameToGuestLoc.find(uniName);
1185             // If using direct driver uniform info, don't overwrite any
1186             // previously known guest location.
1187             if (activeLoc != mUniNameToGuestLoc.end()) {
1188                 guestLoc = activeLoc->second;
1189             } else {
1190                 guestLoc =
1191                     dispatcher.glGetUniformLocation(ProgramName, uniName);
1192                 if (guestLoc == -1) {
1193                     return -1;
1194                 } else {
1195                     mUniNameToGuestLoc[uniName] = guestLoc;
1196                     mGuestLocToHostLoc.add(guestLoc, guestLoc);
1197                 }
1198             }
1199             return guestLoc;
1200         } else {
1201             int guestLoc;
1202 
1203             const auto& activeLoc = mUniNameToGuestLoc.find(uniName);
1204 
1205             if (activeLoc != mUniNameToGuestLoc.end()) {
1206                 guestLoc = activeLoc->second;
1207             } else {
1208                 guestLoc = -1;
1209             }
1210 
1211             std::string translatedName = getTranslatedName(uniName);
1212             int hostLoc = dispatcher.glGetUniformLocation(ProgramName,
1213                     translatedName.c_str());
1214             if (hostLoc == -1) {
1215                 return -1;
1216             }
1217 
1218             mGuestLocToHostLoc.add(guestLoc, hostLoc);
1219             return guestLoc;
1220         }
1221     } else {
1222         return dispatcher.glGetUniformLocation(
1223                 ProgramName, getTranslatedName(uniName).c_str());
1224     }
1225 }
1226 
getHostUniformLocation(int guestLocation)1227 int ProgramData::getHostUniformLocation(int guestLocation) {
1228     if (mUseUniformLocationVirtualization) {
1229         if (guestLocation == -1) return -1;
1230 
1231         auto locPtr = mGuestLocToHostLoc.get_const(guestLocation);
1232         if (!locPtr) return -2;
1233         return *locPtr;
1234     } else {
1235         return guestLocation;
1236     }
1237 }
1238