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