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