1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // ProgramGL.cpp: Implements the class methods for ProgramGL.
8
9 #include "libANGLE/renderer/gl/ProgramGL.h"
10
11 #include "common/WorkerThread.h"
12 #include "common/angleutils.h"
13 #include "common/bitset_utils.h"
14 #include "common/debug.h"
15 #include "common/string_utils.h"
16 #include "common/utilities.h"
17 #include "libANGLE/Context.h"
18 #include "libANGLE/ProgramLinkedResources.h"
19 #include "libANGLE/Uniform.h"
20 #include "libANGLE/queryconversions.h"
21 #include "libANGLE/renderer/gl/ContextGL.h"
22 #include "libANGLE/renderer/gl/FunctionsGL.h"
23 #include "libANGLE/renderer/gl/RendererGL.h"
24 #include "libANGLE/renderer/gl/ShaderGL.h"
25 #include "libANGLE/renderer/gl/StateManagerGL.h"
26 #include "libANGLE/trace.h"
27 #include "platform/PlatformMethods.h"
28 #include "platform/autogen/FeaturesGL_autogen.h"
29
30 namespace rx
31 {
32
ProgramGL(const gl::ProgramState & data,const FunctionsGL * functions,const angle::FeaturesGL & features,StateManagerGL * stateManager,const std::shared_ptr<RendererGL> & renderer)33 ProgramGL::ProgramGL(const gl::ProgramState &data,
34 const FunctionsGL *functions,
35 const angle::FeaturesGL &features,
36 StateManagerGL *stateManager,
37 const std::shared_ptr<RendererGL> &renderer)
38 : ProgramImpl(data),
39 mFunctions(functions),
40 mFeatures(features),
41 mStateManager(stateManager),
42 mHasAppliedTransformFeedbackVaryings(false),
43 mClipDistanceEnabledUniformLocation(-1),
44 mMultiviewBaseViewLayerIndexUniformLocation(-1),
45 mProgramID(0),
46 mRenderer(renderer),
47 mLinkedInParallel(false)
48 {
49 ASSERT(mFunctions);
50 ASSERT(mStateManager);
51
52 mProgramID = mFunctions->createProgram();
53 }
54
~ProgramGL()55 ProgramGL::~ProgramGL()
56 {
57 mFunctions->deleteProgram(mProgramID);
58 mProgramID = 0;
59 }
60
load(const gl::Context * context,gl::BinaryInputStream * stream,gl::InfoLog & infoLog)61 std::unique_ptr<LinkEvent> ProgramGL::load(const gl::Context *context,
62 gl::BinaryInputStream *stream,
63 gl::InfoLog &infoLog)
64 {
65 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::load");
66 preLink();
67
68 // Read the binary format, size and blob
69 GLenum binaryFormat = stream->readInt<GLenum>();
70 GLint binaryLength = stream->readInt<GLint>();
71 const uint8_t *binary = stream->data() + stream->offset();
72 stream->skip(binaryLength);
73
74 // Load the binary
75 mFunctions->programBinary(mProgramID, binaryFormat, binary, binaryLength);
76
77 // Verify that the program linked
78 if (!checkLinkStatus(infoLog))
79 {
80 return std::make_unique<LinkEventDone>(angle::Result::Incomplete);
81 }
82
83 postLink();
84 reapplyUBOBindingsIfNeeded(context);
85
86 return std::make_unique<LinkEventDone>(angle::Result::Continue);
87 }
88
save(const gl::Context * context,gl::BinaryOutputStream * stream)89 void ProgramGL::save(const gl::Context *context, gl::BinaryOutputStream *stream)
90 {
91 GLint binaryLength = 0;
92 mFunctions->getProgramiv(mProgramID, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
93
94 std::vector<uint8_t> binary(std::max(binaryLength, 1));
95 GLenum binaryFormat = GL_NONE;
96 mFunctions->getProgramBinary(mProgramID, binaryLength, &binaryLength, &binaryFormat,
97 binary.data());
98
99 stream->writeInt(binaryFormat);
100 stream->writeInt(binaryLength);
101 stream->writeBytes(binary.data(), binaryLength);
102
103 reapplyUBOBindingsIfNeeded(context);
104 }
105
reapplyUBOBindingsIfNeeded(const gl::Context * context)106 void ProgramGL::reapplyUBOBindingsIfNeeded(const gl::Context *context)
107 {
108 // Re-apply UBO bindings to work around driver bugs.
109 const angle::FeaturesGL &features = GetImplAs<ContextGL>(context)->getFeaturesGL();
110 if (features.reapplyUBOBindingsAfterUsingBinaryProgram.enabled)
111 {
112 const auto &blocks = mState.getUniformBlocks();
113 for (size_t blockIndex : mState.getActiveUniformBlockBindingsMask())
114 {
115 setUniformBlockBinding(static_cast<GLuint>(blockIndex), blocks[blockIndex].binding);
116 }
117 }
118 }
119
setBinaryRetrievableHint(bool retrievable)120 void ProgramGL::setBinaryRetrievableHint(bool retrievable)
121 {
122 // glProgramParameteri isn't always available on ES backends.
123 if (mFunctions->programParameteri)
124 {
125 mFunctions->programParameteri(mProgramID, GL_PROGRAM_BINARY_RETRIEVABLE_HINT,
126 retrievable ? GL_TRUE : GL_FALSE);
127 }
128 }
129
setSeparable(bool separable)130 void ProgramGL::setSeparable(bool separable)
131 {
132 mFunctions->programParameteri(mProgramID, GL_PROGRAM_SEPARABLE, separable ? GL_TRUE : GL_FALSE);
133 }
134
135 using LinkImplFunctor = std::function<bool(std::string &)>;
136 class ProgramGL::LinkTask final : public angle::Closure
137 {
138 public:
LinkTask(LinkImplFunctor && functor)139 LinkTask(LinkImplFunctor &&functor) : mLinkImplFunctor(functor), mFallbackToMainContext(false)
140 {}
141
operator ()()142 void operator()() override
143 {
144 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::LinkTask::run");
145 mFallbackToMainContext = mLinkImplFunctor(mInfoLog);
146 }
147
fallbackToMainContext()148 bool fallbackToMainContext() { return mFallbackToMainContext; }
getInfoLog()149 const std::string &getInfoLog() { return mInfoLog; }
150
151 private:
152 LinkImplFunctor mLinkImplFunctor;
153 bool mFallbackToMainContext;
154 std::string mInfoLog;
155 };
156
157 using PostLinkImplFunctor = std::function<angle::Result(bool, const std::string &)>;
158
159 // The event for a parallelized linking using the native driver extension.
160 class ProgramGL::LinkEventNativeParallel final : public LinkEvent
161 {
162 public:
LinkEventNativeParallel(PostLinkImplFunctor && functor,const FunctionsGL * functions,GLuint programID)163 LinkEventNativeParallel(PostLinkImplFunctor &&functor,
164 const FunctionsGL *functions,
165 GLuint programID)
166 : mPostLinkImplFunctor(functor), mFunctions(functions), mProgramID(programID)
167 {}
168
wait(const gl::Context * context)169 angle::Result wait(const gl::Context *context) override
170 {
171 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::LinkEventNativeParallel::wait");
172
173 GLint linkStatus = GL_FALSE;
174 mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
175 if (linkStatus == GL_TRUE)
176 {
177 return mPostLinkImplFunctor(false, std::string());
178 }
179 return angle::Result::Incomplete;
180 }
181
isLinking()182 bool isLinking() override
183 {
184 GLint completionStatus = GL_FALSE;
185 mFunctions->getProgramiv(mProgramID, GL_COMPLETION_STATUS, &completionStatus);
186 return completionStatus == GL_FALSE;
187 }
188
189 private:
190 PostLinkImplFunctor mPostLinkImplFunctor;
191 const FunctionsGL *mFunctions;
192 GLuint mProgramID;
193 };
194
195 // The event for a parallelized linking using the worker thread pool.
196 class ProgramGL::LinkEventGL final : public LinkEvent
197 {
198 public:
LinkEventGL(std::shared_ptr<angle::WorkerThreadPool> workerPool,std::shared_ptr<ProgramGL::LinkTask> linkTask,PostLinkImplFunctor && functor)199 LinkEventGL(std::shared_ptr<angle::WorkerThreadPool> workerPool,
200 std::shared_ptr<ProgramGL::LinkTask> linkTask,
201 PostLinkImplFunctor &&functor)
202 : mLinkTask(linkTask),
203 mWaitableEvent(
204 std::shared_ptr<angle::WaitableEvent>(workerPool->postWorkerTask(mLinkTask))),
205 mPostLinkImplFunctor(functor)
206 {}
207
wait(const gl::Context * context)208 angle::Result wait(const gl::Context *context) override
209 {
210 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::LinkEventGL::wait");
211
212 mWaitableEvent->wait();
213 return mPostLinkImplFunctor(mLinkTask->fallbackToMainContext(), mLinkTask->getInfoLog());
214 }
215
isLinking()216 bool isLinking() override { return !mWaitableEvent->isReady(); }
217
218 private:
219 std::shared_ptr<ProgramGL::LinkTask> mLinkTask;
220 std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
221 PostLinkImplFunctor mPostLinkImplFunctor;
222 };
223
link(const gl::Context * context,const gl::ProgramLinkedResources & resources,gl::InfoLog & infoLog,const gl::ProgramMergedVaryings &)224 std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
225 const gl::ProgramLinkedResources &resources,
226 gl::InfoLog &infoLog,
227 const gl::ProgramMergedVaryings & /*mergedVaryings*/)
228 {
229 ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::link");
230
231 preLink();
232
233 if (mState.getAttachedShader(gl::ShaderType::Compute))
234 {
235 const ShaderGL *computeShaderGL =
236 GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute));
237
238 mFunctions->attachShader(mProgramID, computeShaderGL->getShaderID());
239 }
240 else
241 {
242 // Set the transform feedback state
243 std::vector<std::string> transformFeedbackVaryingMappedNames;
244 for (const auto &tfVarying : mState.getTransformFeedbackVaryingNames())
245 {
246 gl::ShaderType tfShaderType =
247 mState.getExecutable().hasLinkedShaderStage(gl::ShaderType::Geometry)
248 ? gl::ShaderType::Geometry
249 : gl::ShaderType::Vertex;
250 std::string tfVaryingMappedName =
251 mState.getAttachedShader(tfShaderType)
252 ->getTransformFeedbackVaryingMappedName(context, tfVarying);
253 transformFeedbackVaryingMappedNames.push_back(tfVaryingMappedName);
254 }
255
256 if (transformFeedbackVaryingMappedNames.empty())
257 {
258 // Only clear the transform feedback state if transform feedback varyings have already
259 // been set.
260 if (mHasAppliedTransformFeedbackVaryings)
261 {
262 ASSERT(mFunctions->transformFeedbackVaryings);
263 mFunctions->transformFeedbackVaryings(mProgramID, 0, nullptr,
264 mState.getTransformFeedbackBufferMode());
265 mHasAppliedTransformFeedbackVaryings = false;
266 }
267 }
268 else
269 {
270 ASSERT(mFunctions->transformFeedbackVaryings);
271 std::vector<const GLchar *> transformFeedbackVaryings;
272 for (const auto &varying : transformFeedbackVaryingMappedNames)
273 {
274 transformFeedbackVaryings.push_back(varying.c_str());
275 }
276 mFunctions->transformFeedbackVaryings(
277 mProgramID, static_cast<GLsizei>(transformFeedbackVaryingMappedNames.size()),
278 &transformFeedbackVaryings[0], mState.getTransformFeedbackBufferMode());
279 mHasAppliedTransformFeedbackVaryings = true;
280 }
281
282 for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
283 {
284 const ShaderGL *shaderGL =
285 rx::SafeGetImplAs<ShaderGL, gl::Shader>(mState.getAttachedShader(shaderType));
286 if (shaderGL)
287 {
288 mFunctions->attachShader(mProgramID, shaderGL->getShaderID());
289 }
290 }
291
292 // Bind attribute locations to match the GL layer.
293 for (const sh::ShaderVariable &attribute : mState.getProgramInputs())
294 {
295 if (!attribute.active || attribute.isBuiltIn())
296 {
297 continue;
298 }
299
300 mFunctions->bindAttribLocation(mProgramID, attribute.location,
301 attribute.mappedName.c_str());
302 }
303
304 // Bind the secondary fragment color outputs defined in EXT_blend_func_extended. We only use
305 // the API to bind fragment output locations in case EXT_blend_func_extended is enabled.
306 // Otherwise shader-assigned locations will work.
307 if (context->getExtensions().blendFuncExtendedEXT)
308 {
309 gl::Shader *fragmentShader = mState.getAttachedShader(gl::ShaderType::Fragment);
310 if (fragmentShader && fragmentShader->getShaderVersion(context) == 100 &&
311 mFunctions->standard == STANDARD_GL_DESKTOP)
312 {
313 const auto &shaderOutputs = mState.getAttachedShader(gl::ShaderType::Fragment)
314 ->getActiveOutputVariables(context);
315 for (const auto &output : shaderOutputs)
316 {
317 // TODO(http://anglebug.com/1085) This could be cleaner if the transformed names
318 // would be set correctly in ShaderVariable::mappedName. This would require some
319 // refactoring in the translator. Adding a mapped name dictionary for builtins
320 // into the symbol table would be one fairly clean way to do it.
321 if (output.name == "gl_SecondaryFragColorEXT")
322 {
323 mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0,
324 "webgl_FragColor");
325 mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1,
326 "webgl_SecondaryFragColor");
327 }
328 else if (output.name == "gl_SecondaryFragDataEXT")
329 {
330 // Basically we should have a loop here going over the output
331 // array binding "webgl_FragData[i]" and "webgl_SecondaryFragData[i]" array
332 // indices to the correct color buffers and color indices.
333 // However I'm not sure if this construct is legal or not, neither ARB or
334 // EXT version of the spec mention this. They only mention that
335 // automatically assigned array locations for ESSL 3.00 output arrays need
336 // to have contiguous locations.
337 //
338 // In practice it seems that binding array members works on some drivers and
339 // fails on others. One option could be to modify the shader translator to
340 // expand the arrays into individual output variables instead of using an
341 // array.
342 //
343 // For now we're going to have a limitation of assuming that
344 // GL_MAX_DUAL_SOURCE_DRAW_BUFFERS is *always* 1 and then only bind the
345 // basename of the variable ignoring any indices. This appears to work
346 // uniformly.
347 ASSERT(output.isArray() && output.getOutermostArraySize() == 1);
348
349 mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 0, "webgl_FragData");
350 mFunctions->bindFragDataLocationIndexed(mProgramID, 0, 1,
351 "webgl_SecondaryFragData");
352 }
353 }
354 }
355 else if (fragmentShader && fragmentShader->getShaderVersion(context) >= 300)
356 {
357 // ESSL 3.00 and up.
358 const auto &outputLocations = mState.getOutputLocations();
359 const auto &secondaryOutputLocations = mState.getSecondaryOutputLocations();
360 for (size_t outputLocationIndex = 0u; outputLocationIndex < outputLocations.size();
361 ++outputLocationIndex)
362 {
363 const gl::VariableLocation &outputLocation =
364 outputLocations[outputLocationIndex];
365 if (outputLocation.arrayIndex == 0 && outputLocation.used() &&
366 !outputLocation.ignored)
367 {
368 const sh::ShaderVariable &outputVar =
369 mState.getOutputVariables()[outputLocation.index];
370 if (outputVar.location == -1 || outputVar.index == -1)
371 {
372 // We only need to assign the location and index via the API in case the
373 // variable doesn't have a shader-assigned location and index. If a
374 // variable doesn't have its location set in the shader it doesn't have
375 // the index set either.
376 ASSERT(outputVar.index == -1);
377 mFunctions->bindFragDataLocationIndexed(
378 mProgramID, static_cast<int>(outputLocationIndex), 0,
379 outputVar.mappedName.c_str());
380 }
381 }
382 }
383 for (size_t outputLocationIndex = 0u;
384 outputLocationIndex < secondaryOutputLocations.size(); ++outputLocationIndex)
385 {
386 const gl::VariableLocation &outputLocation =
387 secondaryOutputLocations[outputLocationIndex];
388 if (outputLocation.arrayIndex == 0 && outputLocation.used() &&
389 !outputLocation.ignored)
390 {
391 const sh::ShaderVariable &outputVar =
392 mState.getOutputVariables()[outputLocation.index];
393 if (outputVar.location == -1 || outputVar.index == -1)
394 {
395 // We only need to assign the location and index via the API in case the
396 // variable doesn't have a shader-assigned location and index. If a
397 // variable doesn't have its location set in the shader it doesn't have
398 // the index set either.
399 ASSERT(outputVar.index == -1);
400 mFunctions->bindFragDataLocationIndexed(
401 mProgramID, static_cast<int>(outputLocationIndex), 1,
402 outputVar.mappedName.c_str());
403 }
404 }
405 }
406 }
407 }
408 }
409 auto workerPool = context->getShaderCompileThreadPool();
410 auto linkTask = std::make_shared<LinkTask>([this](std::string &infoLog) {
411 std::string workerInfoLog;
412 ScopedWorkerContextGL worker(mRenderer.get(), &workerInfoLog);
413 if (!worker())
414 {
415 #if !defined(NDEBUG)
416 infoLog += "bindWorkerContext failed.\n" + workerInfoLog;
417 #endif
418 // Fallback to the main context.
419 return true;
420 }
421
422 mFunctions->linkProgram(mProgramID);
423
424 // Make sure the driver actually does the link job.
425 GLint linkStatus = GL_FALSE;
426 mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
427
428 return false;
429 });
430
431 auto postLinkImplTask = [this, &infoLog, &resources](bool fallbackToMainContext,
432 const std::string &workerInfoLog) {
433 infoLog << workerInfoLog;
434 if (fallbackToMainContext)
435 {
436 mFunctions->linkProgram(mProgramID);
437 }
438
439 if (mState.getAttachedShader(gl::ShaderType::Compute))
440 {
441 const ShaderGL *computeShaderGL =
442 GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute));
443
444 mFunctions->detachShader(mProgramID, computeShaderGL->getShaderID());
445 }
446 else
447 {
448 for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
449 {
450 const ShaderGL *shaderGL =
451 rx::SafeGetImplAs<ShaderGL>(mState.getAttachedShader(shaderType));
452 if (shaderGL)
453 {
454 mFunctions->detachShader(mProgramID, shaderGL->getShaderID());
455 }
456 }
457 }
458 // Verify the link
459 if (!checkLinkStatus(infoLog))
460 {
461 return angle::Result::Incomplete;
462 }
463
464 if (mFeatures.alwaysCallUseProgramAfterLink.enabled)
465 {
466 mStateManager->forceUseProgram(mProgramID);
467 }
468
469 linkResources(resources);
470 postLink();
471
472 return angle::Result::Continue;
473 };
474
475 if (mRenderer->hasNativeParallelCompile())
476 {
477 mFunctions->linkProgram(mProgramID);
478
479 return std::make_unique<LinkEventNativeParallel>(postLinkImplTask, mFunctions, mProgramID);
480 }
481 else if (workerPool->isAsync() &&
482 (!mFeatures.dontRelinkProgramsInParallel.enabled || !mLinkedInParallel))
483 {
484 mLinkedInParallel = true;
485 return std::make_unique<LinkEventGL>(workerPool, linkTask, postLinkImplTask);
486 }
487 else
488 {
489 return std::make_unique<LinkEventDone>(postLinkImplTask(true, std::string()));
490 }
491 }
492
validate(const gl::Caps &,gl::InfoLog *)493 GLboolean ProgramGL::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/)
494 {
495 // TODO(jmadill): implement validate
496 return true;
497 }
498
setUniform1fv(GLint location,GLsizei count,const GLfloat * v)499 void ProgramGL::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
500 {
501 if (mFunctions->programUniform1fv != nullptr)
502 {
503 mFunctions->programUniform1fv(mProgramID, uniLoc(location), count, v);
504 }
505 else
506 {
507 mStateManager->useProgram(mProgramID);
508 mFunctions->uniform1fv(uniLoc(location), count, v);
509 }
510 }
511
setUniform2fv(GLint location,GLsizei count,const GLfloat * v)512 void ProgramGL::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
513 {
514 if (mFunctions->programUniform2fv != nullptr)
515 {
516 mFunctions->programUniform2fv(mProgramID, uniLoc(location), count, v);
517 }
518 else
519 {
520 mStateManager->useProgram(mProgramID);
521 mFunctions->uniform2fv(uniLoc(location), count, v);
522 }
523 }
524
setUniform3fv(GLint location,GLsizei count,const GLfloat * v)525 void ProgramGL::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
526 {
527 if (mFunctions->programUniform3fv != nullptr)
528 {
529 mFunctions->programUniform3fv(mProgramID, uniLoc(location), count, v);
530 }
531 else
532 {
533 mStateManager->useProgram(mProgramID);
534 mFunctions->uniform3fv(uniLoc(location), count, v);
535 }
536 }
537
setUniform4fv(GLint location,GLsizei count,const GLfloat * v)538 void ProgramGL::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
539 {
540 if (mFunctions->programUniform4fv != nullptr)
541 {
542 mFunctions->programUniform4fv(mProgramID, uniLoc(location), count, v);
543 }
544 else
545 {
546 mStateManager->useProgram(mProgramID);
547 mFunctions->uniform4fv(uniLoc(location), count, v);
548 }
549 }
550
setUniform1iv(GLint location,GLsizei count,const GLint * v)551 void ProgramGL::setUniform1iv(GLint location, GLsizei count, const GLint *v)
552 {
553 if (mFunctions->programUniform1iv != nullptr)
554 {
555 mFunctions->programUniform1iv(mProgramID, uniLoc(location), count, v);
556 }
557 else
558 {
559 mStateManager->useProgram(mProgramID);
560 mFunctions->uniform1iv(uniLoc(location), count, v);
561 }
562 }
563
setUniform2iv(GLint location,GLsizei count,const GLint * v)564 void ProgramGL::setUniform2iv(GLint location, GLsizei count, const GLint *v)
565 {
566 if (mFunctions->programUniform2iv != nullptr)
567 {
568 mFunctions->programUniform2iv(mProgramID, uniLoc(location), count, v);
569 }
570 else
571 {
572 mStateManager->useProgram(mProgramID);
573 mFunctions->uniform2iv(uniLoc(location), count, v);
574 }
575 }
576
setUniform3iv(GLint location,GLsizei count,const GLint * v)577 void ProgramGL::setUniform3iv(GLint location, GLsizei count, const GLint *v)
578 {
579 if (mFunctions->programUniform3iv != nullptr)
580 {
581 mFunctions->programUniform3iv(mProgramID, uniLoc(location), count, v);
582 }
583 else
584 {
585 mStateManager->useProgram(mProgramID);
586 mFunctions->uniform3iv(uniLoc(location), count, v);
587 }
588 }
589
setUniform4iv(GLint location,GLsizei count,const GLint * v)590 void ProgramGL::setUniform4iv(GLint location, GLsizei count, const GLint *v)
591 {
592 if (mFunctions->programUniform4iv != nullptr)
593 {
594 mFunctions->programUniform4iv(mProgramID, uniLoc(location), count, v);
595 }
596 else
597 {
598 mStateManager->useProgram(mProgramID);
599 mFunctions->uniform4iv(uniLoc(location), count, v);
600 }
601 }
602
setUniform1uiv(GLint location,GLsizei count,const GLuint * v)603 void ProgramGL::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
604 {
605 if (mFunctions->programUniform1uiv != nullptr)
606 {
607 mFunctions->programUniform1uiv(mProgramID, uniLoc(location), count, v);
608 }
609 else
610 {
611 mStateManager->useProgram(mProgramID);
612 mFunctions->uniform1uiv(uniLoc(location), count, v);
613 }
614 }
615
setUniform2uiv(GLint location,GLsizei count,const GLuint * v)616 void ProgramGL::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
617 {
618 if (mFunctions->programUniform2uiv != nullptr)
619 {
620 mFunctions->programUniform2uiv(mProgramID, uniLoc(location), count, v);
621 }
622 else
623 {
624 mStateManager->useProgram(mProgramID);
625 mFunctions->uniform2uiv(uniLoc(location), count, v);
626 }
627 }
628
setUniform3uiv(GLint location,GLsizei count,const GLuint * v)629 void ProgramGL::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
630 {
631 if (mFunctions->programUniform3uiv != nullptr)
632 {
633 mFunctions->programUniform3uiv(mProgramID, uniLoc(location), count, v);
634 }
635 else
636 {
637 mStateManager->useProgram(mProgramID);
638 mFunctions->uniform3uiv(uniLoc(location), count, v);
639 }
640 }
641
setUniform4uiv(GLint location,GLsizei count,const GLuint * v)642 void ProgramGL::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
643 {
644 if (mFunctions->programUniform4uiv != nullptr)
645 {
646 mFunctions->programUniform4uiv(mProgramID, uniLoc(location), count, v);
647 }
648 else
649 {
650 mStateManager->useProgram(mProgramID);
651 mFunctions->uniform4uiv(uniLoc(location), count, v);
652 }
653 }
654
setUniformMatrix2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)655 void ProgramGL::setUniformMatrix2fv(GLint location,
656 GLsizei count,
657 GLboolean transpose,
658 const GLfloat *value)
659 {
660 if (mFunctions->programUniformMatrix2fv != nullptr)
661 {
662 mFunctions->programUniformMatrix2fv(mProgramID, uniLoc(location), count, transpose, value);
663 }
664 else
665 {
666 mStateManager->useProgram(mProgramID);
667 mFunctions->uniformMatrix2fv(uniLoc(location), count, transpose, value);
668 }
669 }
670
setUniformMatrix3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)671 void ProgramGL::setUniformMatrix3fv(GLint location,
672 GLsizei count,
673 GLboolean transpose,
674 const GLfloat *value)
675 {
676 if (mFunctions->programUniformMatrix3fv != nullptr)
677 {
678 mFunctions->programUniformMatrix3fv(mProgramID, uniLoc(location), count, transpose, value);
679 }
680 else
681 {
682 mStateManager->useProgram(mProgramID);
683 mFunctions->uniformMatrix3fv(uniLoc(location), count, transpose, value);
684 }
685 }
686
setUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)687 void ProgramGL::setUniformMatrix4fv(GLint location,
688 GLsizei count,
689 GLboolean transpose,
690 const GLfloat *value)
691 {
692 if (mFunctions->programUniformMatrix4fv != nullptr)
693 {
694 mFunctions->programUniformMatrix4fv(mProgramID, uniLoc(location), count, transpose, value);
695 }
696 else
697 {
698 mStateManager->useProgram(mProgramID);
699 mFunctions->uniformMatrix4fv(uniLoc(location), count, transpose, value);
700 }
701 }
702
setUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)703 void ProgramGL::setUniformMatrix2x3fv(GLint location,
704 GLsizei count,
705 GLboolean transpose,
706 const GLfloat *value)
707 {
708 if (mFunctions->programUniformMatrix2x3fv != nullptr)
709 {
710 mFunctions->programUniformMatrix2x3fv(mProgramID, uniLoc(location), count, transpose,
711 value);
712 }
713 else
714 {
715 mStateManager->useProgram(mProgramID);
716 mFunctions->uniformMatrix2x3fv(uniLoc(location), count, transpose, value);
717 }
718 }
719
setUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)720 void ProgramGL::setUniformMatrix3x2fv(GLint location,
721 GLsizei count,
722 GLboolean transpose,
723 const GLfloat *value)
724 {
725 if (mFunctions->programUniformMatrix3x2fv != nullptr)
726 {
727 mFunctions->programUniformMatrix3x2fv(mProgramID, uniLoc(location), count, transpose,
728 value);
729 }
730 else
731 {
732 mStateManager->useProgram(mProgramID);
733 mFunctions->uniformMatrix3x2fv(uniLoc(location), count, transpose, value);
734 }
735 }
736
setUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)737 void ProgramGL::setUniformMatrix2x4fv(GLint location,
738 GLsizei count,
739 GLboolean transpose,
740 const GLfloat *value)
741 {
742 if (mFunctions->programUniformMatrix2x4fv != nullptr)
743 {
744 mFunctions->programUniformMatrix2x4fv(mProgramID, uniLoc(location), count, transpose,
745 value);
746 }
747 else
748 {
749 mStateManager->useProgram(mProgramID);
750 mFunctions->uniformMatrix2x4fv(uniLoc(location), count, transpose, value);
751 }
752 }
753
setUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)754 void ProgramGL::setUniformMatrix4x2fv(GLint location,
755 GLsizei count,
756 GLboolean transpose,
757 const GLfloat *value)
758 {
759 if (mFunctions->programUniformMatrix4x2fv != nullptr)
760 {
761 mFunctions->programUniformMatrix4x2fv(mProgramID, uniLoc(location), count, transpose,
762 value);
763 }
764 else
765 {
766 mStateManager->useProgram(mProgramID);
767 mFunctions->uniformMatrix4x2fv(uniLoc(location), count, transpose, value);
768 }
769 }
770
setUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)771 void ProgramGL::setUniformMatrix3x4fv(GLint location,
772 GLsizei count,
773 GLboolean transpose,
774 const GLfloat *value)
775 {
776 if (mFunctions->programUniformMatrix3x4fv != nullptr)
777 {
778 mFunctions->programUniformMatrix3x4fv(mProgramID, uniLoc(location), count, transpose,
779 value);
780 }
781 else
782 {
783 mStateManager->useProgram(mProgramID);
784 mFunctions->uniformMatrix3x4fv(uniLoc(location), count, transpose, value);
785 }
786 }
787
setUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)788 void ProgramGL::setUniformMatrix4x3fv(GLint location,
789 GLsizei count,
790 GLboolean transpose,
791 const GLfloat *value)
792 {
793 if (mFunctions->programUniformMatrix4x3fv != nullptr)
794 {
795 mFunctions->programUniformMatrix4x3fv(mProgramID, uniLoc(location), count, transpose,
796 value);
797 }
798 else
799 {
800 mStateManager->useProgram(mProgramID);
801 mFunctions->uniformMatrix4x3fv(uniLoc(location), count, transpose, value);
802 }
803 }
804
setUniformBlockBinding(GLuint uniformBlockIndex,GLuint uniformBlockBinding)805 void ProgramGL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
806 {
807 // Lazy init
808 if (mUniformBlockRealLocationMap.empty())
809 {
810 mUniformBlockRealLocationMap.reserve(mState.getUniformBlocks().size());
811 for (const gl::InterfaceBlock &uniformBlock : mState.getUniformBlocks())
812 {
813 const std::string &mappedNameWithIndex = uniformBlock.mappedNameWithArrayIndex();
814 GLuint blockIndex =
815 mFunctions->getUniformBlockIndex(mProgramID, mappedNameWithIndex.c_str());
816 mUniformBlockRealLocationMap.push_back(blockIndex);
817 }
818 }
819
820 GLuint realBlockIndex = mUniformBlockRealLocationMap[uniformBlockIndex];
821 if (realBlockIndex != GL_INVALID_INDEX)
822 {
823 mFunctions->uniformBlockBinding(mProgramID, realBlockIndex, uniformBlockBinding);
824 }
825 }
826
getUniformBlockSize(const std::string &,const std::string & blockMappedName,size_t * sizeOut) const827 bool ProgramGL::getUniformBlockSize(const std::string & /* blockName */,
828 const std::string &blockMappedName,
829 size_t *sizeOut) const
830 {
831 ASSERT(mProgramID != 0u);
832
833 GLuint blockIndex = mFunctions->getUniformBlockIndex(mProgramID, blockMappedName.c_str());
834 if (blockIndex == GL_INVALID_INDEX)
835 {
836 *sizeOut = 0;
837 return false;
838 }
839
840 GLint dataSize = 0;
841 mFunctions->getActiveUniformBlockiv(mProgramID, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE,
842 &dataSize);
843 *sizeOut = static_cast<size_t>(dataSize);
844 return true;
845 }
846
getUniformBlockMemberInfo(const std::string &,const std::string & memberUniformMappedName,sh::BlockMemberInfo * memberInfoOut) const847 bool ProgramGL::getUniformBlockMemberInfo(const std::string & /* memberUniformName */,
848 const std::string &memberUniformMappedName,
849 sh::BlockMemberInfo *memberInfoOut) const
850 {
851 GLuint uniformIndex;
852 const GLchar *memberNameGLStr = memberUniformMappedName.c_str();
853 mFunctions->getUniformIndices(mProgramID, 1, &memberNameGLStr, &uniformIndex);
854
855 if (uniformIndex == GL_INVALID_INDEX)
856 {
857 *memberInfoOut = sh::kDefaultBlockMemberInfo;
858 return false;
859 }
860
861 mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_OFFSET,
862 &memberInfoOut->offset);
863 mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_ARRAY_STRIDE,
864 &memberInfoOut->arrayStride);
865 mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_MATRIX_STRIDE,
866 &memberInfoOut->matrixStride);
867
868 // TODO(jmadill): possibly determine this at the gl::Program level.
869 GLint isRowMajorMatrix = 0;
870 mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_IS_ROW_MAJOR,
871 &isRowMajorMatrix);
872 memberInfoOut->isRowMajorMatrix = gl::ConvertToBool(isRowMajorMatrix);
873 return true;
874 }
875
getShaderStorageBlockMemberInfo(const std::string &,const std::string & memberUniformMappedName,sh::BlockMemberInfo * memberInfoOut) const876 bool ProgramGL::getShaderStorageBlockMemberInfo(const std::string & /* memberName */,
877 const std::string &memberUniformMappedName,
878 sh::BlockMemberInfo *memberInfoOut) const
879 {
880 const GLchar *memberNameGLStr = memberUniformMappedName.c_str();
881 GLuint index =
882 mFunctions->getProgramResourceIndex(mProgramID, GL_BUFFER_VARIABLE, memberNameGLStr);
883
884 if (index == GL_INVALID_INDEX)
885 {
886 *memberInfoOut = sh::kDefaultBlockMemberInfo;
887 return false;
888 }
889
890 constexpr int kPropCount = 5;
891 std::array<GLenum, kPropCount> props = {
892 {GL_ARRAY_STRIDE, GL_IS_ROW_MAJOR, GL_MATRIX_STRIDE, GL_OFFSET, GL_TOP_LEVEL_ARRAY_STRIDE}};
893 std::array<GLint, kPropCount> params;
894 GLsizei length;
895 mFunctions->getProgramResourceiv(mProgramID, GL_BUFFER_VARIABLE, index, kPropCount,
896 props.data(), kPropCount, &length, params.data());
897 ASSERT(kPropCount == length);
898 memberInfoOut->arrayStride = params[0];
899 memberInfoOut->isRowMajorMatrix = params[1] != 0;
900 memberInfoOut->matrixStride = params[2];
901 memberInfoOut->offset = params[3];
902 memberInfoOut->topLevelArrayStride = params[4];
903
904 return true;
905 }
906
getShaderStorageBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut) const907 bool ProgramGL::getShaderStorageBlockSize(const std::string &name,
908 const std::string &mappedName,
909 size_t *sizeOut) const
910 {
911 const GLchar *nameGLStr = mappedName.c_str();
912 GLuint index =
913 mFunctions->getProgramResourceIndex(mProgramID, GL_SHADER_STORAGE_BLOCK, nameGLStr);
914
915 if (index == GL_INVALID_INDEX)
916 {
917 *sizeOut = 0;
918 return false;
919 }
920
921 GLenum prop = GL_BUFFER_DATA_SIZE;
922 GLsizei length = 0;
923 GLint dataSize = 0;
924 mFunctions->getProgramResourceiv(mProgramID, GL_SHADER_STORAGE_BLOCK, index, 1, &prop, 1,
925 &length, &dataSize);
926 *sizeOut = static_cast<size_t>(dataSize);
927 return true;
928 }
929
getAtomicCounterBufferSizeMap(std::map<int,unsigned int> * sizeMapOut) const930 void ProgramGL::getAtomicCounterBufferSizeMap(std::map<int, unsigned int> *sizeMapOut) const
931 {
932 if (mFunctions->getProgramInterfaceiv == nullptr)
933 {
934 return;
935 }
936
937 int resourceCount = 0;
938 mFunctions->getProgramInterfaceiv(mProgramID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES,
939 &resourceCount);
940
941 for (int index = 0; index < resourceCount; index++)
942 {
943 constexpr int kPropCount = 2;
944 std::array<GLenum, kPropCount> props = {{GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE}};
945 std::array<GLint, kPropCount> params;
946 GLsizei length;
947 mFunctions->getProgramResourceiv(mProgramID, GL_ATOMIC_COUNTER_BUFFER, index, kPropCount,
948 props.data(), kPropCount, &length, params.data());
949 ASSERT(kPropCount == length);
950 int bufferBinding = params[0];
951 unsigned int bufferDataSize = params[1];
952 sizeMapOut->insert(std::pair<int, unsigned int>(bufferBinding, bufferDataSize));
953 }
954 }
955
preLink()956 void ProgramGL::preLink()
957 {
958 // Reset the program state
959 mUniformRealLocationMap.clear();
960 mUniformBlockRealLocationMap.clear();
961
962 mClipDistanceEnabledUniformLocation = -1;
963 mMultiviewBaseViewLayerIndexUniformLocation = -1;
964 }
965
checkLinkStatus(gl::InfoLog & infoLog)966 bool ProgramGL::checkLinkStatus(gl::InfoLog &infoLog)
967 {
968 GLint linkStatus = GL_FALSE;
969 mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
970 if (linkStatus == GL_FALSE)
971 {
972 // Linking or program binary loading failed, put the error into the info log.
973 GLint infoLogLength = 0;
974 mFunctions->getProgramiv(mProgramID, GL_INFO_LOG_LENGTH, &infoLogLength);
975
976 // Info log length includes the null terminator, so 1 means that the info log is an empty
977 // string.
978 if (infoLogLength > 1)
979 {
980 std::vector<char> buf(infoLogLength);
981 mFunctions->getProgramInfoLog(mProgramID, infoLogLength, nullptr, &buf[0]);
982
983 infoLog << buf.data();
984
985 WARN() << "Program link or binary loading failed: " << buf.data();
986 }
987 else
988 {
989 WARN() << "Program link or binary loading failed with no info log.";
990 }
991
992 // This may happen under normal circumstances if we're loading program binaries and the
993 // driver or hardware has changed.
994 ASSERT(mProgramID != 0);
995 return false;
996 }
997
998 return true;
999 }
1000
postLink()1001 void ProgramGL::postLink()
1002 {
1003 // Query the uniform information
1004 ASSERT(mUniformRealLocationMap.empty());
1005 const auto &uniformLocations = mState.getUniformLocations();
1006 const auto &uniforms = mState.getUniforms();
1007 mUniformRealLocationMap.resize(uniformLocations.size(), GL_INVALID_INDEX);
1008 for (size_t uniformLocation = 0; uniformLocation < uniformLocations.size(); uniformLocation++)
1009 {
1010 const auto &entry = uniformLocations[uniformLocation];
1011 if (!entry.used())
1012 {
1013 continue;
1014 }
1015
1016 // From the GLES 3.0.5 spec:
1017 // "Locations for sequential array indices are not required to be sequential."
1018 const gl::LinkedUniform &uniform = uniforms[entry.index];
1019 std::stringstream fullNameStr;
1020 if (uniform.isArray())
1021 {
1022 ASSERT(angle::EndsWith(uniform.mappedName, "[0]"));
1023 fullNameStr << uniform.mappedName.substr(0, uniform.mappedName.length() - 3);
1024 fullNameStr << "[" << entry.arrayIndex << "]";
1025 }
1026 else
1027 {
1028 fullNameStr << uniform.mappedName;
1029 }
1030 const std::string &fullName = fullNameStr.str();
1031
1032 GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
1033 mUniformRealLocationMap[uniformLocation] = realLocation;
1034 }
1035
1036 if (mFeatures.emulateClipDistanceState.enabled && mState.getExecutable().hasClipDistance())
1037 {
1038 ASSERT(mFunctions->standard == STANDARD_GL_ES);
1039 mClipDistanceEnabledUniformLocation =
1040 mFunctions->getUniformLocation(mProgramID, "angle_ClipDistanceEnabled");
1041 ASSERT(mClipDistanceEnabledUniformLocation != -1);
1042 }
1043
1044 if (mState.usesMultiview())
1045 {
1046 mMultiviewBaseViewLayerIndexUniformLocation =
1047 mFunctions->getUniformLocation(mProgramID, "multiviewBaseViewLayerIndex");
1048 ASSERT(mMultiviewBaseViewLayerIndexUniformLocation != -1);
1049 }
1050 }
1051
updateEnabledClipDistances(uint8_t enabledClipDistancesPacked) const1052 void ProgramGL::updateEnabledClipDistances(uint8_t enabledClipDistancesPacked) const
1053 {
1054 ASSERT(mState.getExecutable().hasClipDistance());
1055 ASSERT(mClipDistanceEnabledUniformLocation != -1);
1056
1057 ASSERT(mFunctions->programUniform1ui != nullptr);
1058 mFunctions->programUniform1ui(mProgramID, mClipDistanceEnabledUniformLocation,
1059 enabledClipDistancesPacked);
1060 }
1061
enableLayeredRenderingPath(int baseViewIndex) const1062 void ProgramGL::enableLayeredRenderingPath(int baseViewIndex) const
1063 {
1064 ASSERT(mState.usesMultiview());
1065 ASSERT(mMultiviewBaseViewLayerIndexUniformLocation != -1);
1066
1067 ASSERT(mFunctions->programUniform1i != nullptr);
1068 mFunctions->programUniform1i(mProgramID, mMultiviewBaseViewLayerIndexUniformLocation,
1069 baseViewIndex);
1070 }
1071
getUniformfv(const gl::Context * context,GLint location,GLfloat * params) const1072 void ProgramGL::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
1073 {
1074 mFunctions->getUniformfv(mProgramID, uniLoc(location), params);
1075 }
1076
getUniformiv(const gl::Context * context,GLint location,GLint * params) const1077 void ProgramGL::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
1078 {
1079 mFunctions->getUniformiv(mProgramID, uniLoc(location), params);
1080 }
1081
getUniformuiv(const gl::Context * context,GLint location,GLuint * params) const1082 void ProgramGL::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
1083 {
1084 mFunctions->getUniformuiv(mProgramID, uniLoc(location), params);
1085 }
1086
markUnusedUniformLocations(std::vector<gl::VariableLocation> * uniformLocations,std::vector<gl::SamplerBinding> * samplerBindings,std::vector<gl::ImageBinding> * imageBindings)1087 void ProgramGL::markUnusedUniformLocations(std::vector<gl::VariableLocation> *uniformLocations,
1088 std::vector<gl::SamplerBinding> *samplerBindings,
1089 std::vector<gl::ImageBinding> *imageBindings)
1090 {
1091 GLint maxLocation = static_cast<GLint>(uniformLocations->size());
1092 for (GLint location = 0; location < maxLocation; ++location)
1093 {
1094 if (uniLoc(location) == -1)
1095 {
1096 auto &locationRef = (*uniformLocations)[location];
1097 if (mState.isSamplerUniformIndex(locationRef.index))
1098 {
1099 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationRef.index);
1100 gl::SamplerBinding &samplerBinding = (*samplerBindings)[samplerIndex];
1101 if (locationRef.arrayIndex < samplerBinding.boundTextureUnits.size())
1102 {
1103 // Crop unused sampler bindings in the sampler array.
1104 samplerBinding.boundTextureUnits.resize(locationRef.arrayIndex);
1105 }
1106 }
1107 else if (mState.isImageUniformIndex(locationRef.index))
1108 {
1109 GLuint imageIndex = mState.getImageIndexFromUniformIndex(locationRef.index);
1110 gl::ImageBinding &imageBinding = (*imageBindings)[imageIndex];
1111 if (locationRef.arrayIndex < imageBinding.boundImageUnits.size())
1112 {
1113 // Crop unused image bindings in the image array.
1114 imageBinding.boundImageUnits.resize(locationRef.arrayIndex);
1115 }
1116 }
1117 // If the location has been previously bound by a glBindUniformLocation call, it should
1118 // be marked as ignored. Otherwise it's unused.
1119 if (mState.getUniformLocationBindings().getBindingByLocation(location) != -1)
1120 {
1121 locationRef.markIgnored();
1122 }
1123 else
1124 {
1125 locationRef.markUnused();
1126 }
1127 }
1128 }
1129 }
1130
linkResources(const gl::ProgramLinkedResources & resources)1131 void ProgramGL::linkResources(const gl::ProgramLinkedResources &resources)
1132 {
1133 // Gather interface block info.
1134 auto getUniformBlockSize = [this](const std::string &name, const std::string &mappedName,
1135 size_t *sizeOut) {
1136 return this->getUniformBlockSize(name, mappedName, sizeOut);
1137 };
1138
1139 auto getUniformBlockMemberInfo = [this](const std::string &name, const std::string &mappedName,
1140 sh::BlockMemberInfo *infoOut) {
1141 return this->getUniformBlockMemberInfo(name, mappedName, infoOut);
1142 };
1143
1144 resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1145
1146 auto getShaderStorageBlockSize = [this](const std::string &name, const std::string &mappedName,
1147 size_t *sizeOut) {
1148 return this->getShaderStorageBlockSize(name, mappedName, sizeOut);
1149 };
1150
1151 auto getShaderStorageBlockMemberInfo = [this](const std::string &name,
1152 const std::string &mappedName,
1153 sh::BlockMemberInfo *infoOut) {
1154 return this->getShaderStorageBlockMemberInfo(name, mappedName, infoOut);
1155 };
1156 resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1157 getShaderStorageBlockMemberInfo);
1158
1159 // Gather atomic counter buffer info.
1160 std::map<int, unsigned int> sizeMap;
1161 getAtomicCounterBufferSizeMap(&sizeMap);
1162 resources.atomicCounterBufferLinker.link(sizeMap);
1163 }
1164
syncState(const gl::Context * context,const gl::Program::DirtyBits & dirtyBits)1165 angle::Result ProgramGL::syncState(const gl::Context *context,
1166 const gl::Program::DirtyBits &dirtyBits)
1167 {
1168 for (size_t dirtyBit : dirtyBits)
1169 {
1170 ASSERT(dirtyBit <= gl::Program::DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX);
1171 GLuint binding = static_cast<GLuint>(dirtyBit);
1172 setUniformBlockBinding(binding, mState.getUniformBlockBinding(binding));
1173 }
1174 return angle::Result::Continue;
1175 }
1176 } // namespace rx
1177