blob: 9252b5af6577cef8b1c91c1ab69cc9ec04b0ee60 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill80a6fc02015-08-21 16:53:16 -040014#include "common/BitSetIterator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
17#include "common/utilities.h"
18#include "common/version.h"
19#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill437d2662014-12-05 14:23:35 -050021#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050022#include "libANGLE/features.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040023#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill192745a2016-12-22 15:58:21 -050025#include "libANGLE/VaryingPacking.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040026#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040027#include "libANGLE/Uniform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050028
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000029namespace gl
30{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000031
Geoff Lang7dd2e102014-11-10 15:19:26 -050032namespace
33{
34
Jamie Madill62d31cb2015-09-11 13:25:51 -040035void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
36{
37 stream->writeInt(var.type);
38 stream->writeInt(var.precision);
39 stream->writeString(var.name);
40 stream->writeString(var.mappedName);
41 stream->writeInt(var.arraySize);
42 stream->writeInt(var.staticUse);
43 stream->writeString(var.structName);
44 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050045}
46
Jamie Madill62d31cb2015-09-11 13:25:51 -040047void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
48{
49 var->type = stream->readInt<GLenum>();
50 var->precision = stream->readInt<GLenum>();
51 var->name = stream->readString();
52 var->mappedName = stream->readString();
53 var->arraySize = stream->readInt<unsigned int>();
54 var->staticUse = stream->readBool();
55 var->structName = stream->readString();
56}
57
Jamie Madill62d31cb2015-09-11 13:25:51 -040058// This simplified cast function doesn't need to worry about advanced concepts like
59// depth range values, or casting to bool.
60template <typename DestT, typename SrcT>
61DestT UniformStateQueryCast(SrcT value);
62
63// From-Float-To-Integer Casts
64template <>
65GLint UniformStateQueryCast(GLfloat value)
66{
67 return clampCast<GLint>(roundf(value));
68}
69
70template <>
71GLuint UniformStateQueryCast(GLfloat value)
72{
73 return clampCast<GLuint>(roundf(value));
74}
75
76// From-Integer-to-Integer Casts
77template <>
78GLint UniformStateQueryCast(GLuint value)
79{
80 return clampCast<GLint>(value);
81}
82
83template <>
84GLuint UniformStateQueryCast(GLint value)
85{
86 return clampCast<GLuint>(value);
87}
88
89// From-Boolean-to-Anything Casts
90template <>
91GLfloat UniformStateQueryCast(GLboolean value)
92{
93 return (value == GL_TRUE ? 1.0f : 0.0f);
94}
95
96template <>
97GLint UniformStateQueryCast(GLboolean value)
98{
99 return (value == GL_TRUE ? 1 : 0);
100}
101
102template <>
103GLuint UniformStateQueryCast(GLboolean value)
104{
105 return (value == GL_TRUE ? 1u : 0u);
106}
107
108// Default to static_cast
109template <typename DestT, typename SrcT>
110DestT UniformStateQueryCast(SrcT value)
111{
112 return static_cast<DestT>(value);
113}
114
115template <typename SrcT, typename DestT>
116void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
117{
118 for (int comp = 0; comp < components; ++comp)
119 {
120 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
121 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
122 size_t offset = comp * 4;
123 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
124 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
125 }
126}
127
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400128bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
129{
130 for (const LinkedUniform &uniform : list)
131 {
132 if (uniform.name == name)
133 return true;
134 }
135
136 return false;
137}
138
Jamie Madill192745a2016-12-22 15:58:21 -0500139// true if varying x has a higher priority in packing than y
140bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
141{
142 return gl::CompareShaderVar(*x.varying, *y.varying);
143}
144
Jamie Madill62d31cb2015-09-11 13:25:51 -0400145} // anonymous namespace
146
Jamie Madill4a3c2342015-10-08 12:58:45 -0400147const char *const g_fakepath = "C:\\fakepath";
148
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400149InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000150{
151}
152
153InfoLog::~InfoLog()
154{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000155}
156
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400157size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000158{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400159 const std::string &logString = mStream.str();
160 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000161}
162
Geoff Lange1a27752015-10-05 13:16:04 -0400163void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000164{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400165 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000166
167 if (bufSize > 0)
168 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400169 const std::string str(mStream.str());
170
171 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000172 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400173 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
174 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000175 }
176
177 infoLog[index] = '\0';
178 }
179
180 if (length)
181 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000183 }
184}
185
186// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300187// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000188// messages, so lets remove all occurrences of this fake file path from the log.
189void InfoLog::appendSanitized(const char *message)
190{
191 std::string msg(message);
192
193 size_t found;
194 do
195 {
196 found = msg.find(g_fakepath);
197 if (found != std::string::npos)
198 {
199 msg.erase(found, strlen(g_fakepath));
200 }
201 }
202 while (found != std::string::npos);
203
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400204 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000205}
206
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000207void InfoLog::reset()
208{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000209}
210
Geoff Langd8605522016-04-13 10:19:12 -0400211VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000212{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500213}
214
Geoff Langd8605522016-04-13 10:19:12 -0400215VariableLocation::VariableLocation(const std::string &name,
216 unsigned int element,
217 unsigned int index)
218 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500219{
220}
221
Geoff Langd8605522016-04-13 10:19:12 -0400222void Program::Bindings::bindLocation(GLuint index, const std::string &name)
223{
224 mBindings[name] = index;
225}
226
227int Program::Bindings::getBinding(const std::string &name) const
228{
229 auto iter = mBindings.find(name);
230 return (iter != mBindings.end()) ? iter->second : -1;
231}
232
233Program::Bindings::const_iterator Program::Bindings::begin() const
234{
235 return mBindings.begin();
236}
237
238Program::Bindings::const_iterator Program::Bindings::end() const
239{
240 return mBindings.end();
241}
242
Jamie Madill48ef11b2016-04-27 15:21:52 -0400243ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500244 : mLabel(),
245 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400246 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300247 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500248 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
249 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400250{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300251 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400252}
253
Jamie Madill48ef11b2016-04-27 15:21:52 -0400254ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400255{
256 if (mAttachedVertexShader != nullptr)
257 {
258 mAttachedVertexShader->release();
259 }
260
261 if (mAttachedFragmentShader != nullptr)
262 {
263 mAttachedFragmentShader->release();
264 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300265
266 if (mAttachedComputeShader != nullptr)
267 {
268 mAttachedComputeShader->release();
269 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400270}
271
Jamie Madill48ef11b2016-04-27 15:21:52 -0400272const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500273{
274 return mLabel;
275}
276
Jamie Madill48ef11b2016-04-27 15:21:52 -0400277const LinkedUniform *ProgramState::getUniformByName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400278{
279 for (const LinkedUniform &linkedUniform : mUniforms)
280 {
281 if (linkedUniform.name == name)
282 {
283 return &linkedUniform;
284 }
285 }
286
287 return nullptr;
288}
289
Jamie Madill48ef11b2016-04-27 15:21:52 -0400290GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400291{
292 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500293 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400294
295 for (size_t location = 0; location < mUniformLocations.size(); ++location)
296 {
297 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400298 if (!uniformLocation.used)
299 {
300 continue;
301 }
302
303 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400304
305 if (uniform.name == baseName)
306 {
Geoff Langd8605522016-04-13 10:19:12 -0400307 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400308 {
Geoff Langd8605522016-04-13 10:19:12 -0400309 if (uniformLocation.element == subscript ||
310 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
311 {
312 return static_cast<GLint>(location);
313 }
314 }
315 else
316 {
317 if (subscript == GL_INVALID_INDEX)
318 {
319 return static_cast<GLint>(location);
320 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400321 }
322 }
323 }
324
325 return -1;
326}
327
Jamie Madill48ef11b2016-04-27 15:21:52 -0400328GLuint ProgramState::getUniformIndex(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400329{
330 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500331 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400332
333 // The app is not allowed to specify array indices other than 0 for arrays of basic types
334 if (subscript != 0 && subscript != GL_INVALID_INDEX)
335 {
336 return GL_INVALID_INDEX;
337 }
338
339 for (size_t index = 0; index < mUniforms.size(); index++)
340 {
341 const LinkedUniform &uniform = mUniforms[index];
342 if (uniform.name == baseName)
343 {
344 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
345 {
346 return static_cast<GLuint>(index);
347 }
348 }
349 }
350
351 return GL_INVALID_INDEX;
352}
353
Jamie Madill7aea7e02016-05-10 10:39:45 -0400354Program::Program(rx::GLImplFactory *factory, ResourceManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400355 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400356 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500357 mLinked(false),
358 mDeleteStatus(false),
359 mRefCount(0),
360 mResourceManager(manager),
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400361 mHandle(handle),
362 mSamplerUniformRange(0, 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500363{
364 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000365
366 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500367 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368}
369
370Program::~Program()
371{
372 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000373
Geoff Lang7dd2e102014-11-10 15:19:26 -0500374 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375}
376
Geoff Lang70d0f492015-12-10 17:45:46 -0500377void Program::setLabel(const std::string &label)
378{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400379 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500380}
381
382const std::string &Program::getLabel() const
383{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400384 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500385}
386
Jamie Madillef300b12016-10-07 15:12:09 -0400387void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300389 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000390 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300391 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
Jamie Madillef300b12016-10-07 15:12:09 -0400393 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300394 mState.mAttachedVertexShader = shader;
395 mState.mAttachedVertexShader->addRef();
396 break;
397 }
398 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000399 {
Jamie Madillef300b12016-10-07 15:12:09 -0400400 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300401 mState.mAttachedFragmentShader = shader;
402 mState.mAttachedFragmentShader->addRef();
403 break;
404 }
405 case GL_COMPUTE_SHADER:
406 {
Jamie Madillef300b12016-10-07 15:12:09 -0400407 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300408 mState.mAttachedComputeShader = shader;
409 mState.mAttachedComputeShader->addRef();
410 break;
411 }
412 default:
413 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000414 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415}
416
417bool Program::detachShader(Shader *shader)
418{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300419 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300421 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300423 if (mState.mAttachedVertexShader != shader)
424 {
425 return false;
426 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427
Martin Radev4c4c8e72016-08-04 12:25:34 +0300428 shader->release();
429 mState.mAttachedVertexShader = nullptr;
430 break;
431 }
432 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300434 if (mState.mAttachedFragmentShader != shader)
435 {
436 return false;
437 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438
Martin Radev4c4c8e72016-08-04 12:25:34 +0300439 shader->release();
440 mState.mAttachedFragmentShader = nullptr;
441 break;
442 }
443 case GL_COMPUTE_SHADER:
444 {
445 if (mState.mAttachedComputeShader != shader)
446 {
447 return false;
448 }
449
450 shader->release();
451 mState.mAttachedComputeShader = nullptr;
452 break;
453 }
454 default:
455 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 return true;
459}
460
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000461int Program::getAttachedShadersCount() const
462{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300463 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
464 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000465}
466
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467void Program::bindAttributeLocation(GLuint index, const char *name)
468{
Geoff Langd8605522016-04-13 10:19:12 -0400469 mAttributeBindings.bindLocation(index, name);
470}
471
472void Program::bindUniformLocation(GLuint index, const char *name)
473{
474 // Bind the base uniform name only since array indices other than 0 cannot be bound
475 mUniformBindings.bindLocation(index, ParseUniformName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476}
477
Sami Väisänen46eaa942016-06-29 10:26:37 +0300478void Program::bindFragmentInputLocation(GLint index, const char *name)
479{
480 mFragmentInputBindings.bindLocation(index, name);
481}
482
483BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
484{
485 BindingInfo ret;
486 ret.type = GL_NONE;
487 ret.valid = false;
488
489 const Shader *fragmentShader = mState.getAttachedFragmentShader();
490 ASSERT(fragmentShader);
491
492 // Find the actual fragment shader varying we're interested in
493 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
494
495 for (const auto &binding : mFragmentInputBindings)
496 {
497 if (binding.second != static_cast<GLuint>(index))
498 continue;
499
500 ret.valid = true;
501
502 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400503 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300504
505 for (const auto &in : inputs)
506 {
507 if (in.name == originalName)
508 {
509 if (in.isArray())
510 {
511 // The client wants to bind either "name" or "name[0]".
512 // GL ES 3.1 spec refers to active array names with language such as:
513 // "if the string identifies the base name of an active array, where the
514 // string would exactly match the name of the variable if the suffix "[0]"
515 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400516 if (arrayIndex == GL_INVALID_INDEX)
517 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300518
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400519 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300520 }
521 else
522 {
523 ret.name = in.mappedName;
524 }
525 ret.type = in.type;
526 return ret;
527 }
528 }
529 }
530
531 return ret;
532}
533
534void Program::pathFragmentInputGen(GLint index,
535 GLenum genMode,
536 GLint components,
537 const GLfloat *coeffs)
538{
539 // If the location is -1 then the command is silently ignored
540 if (index == -1)
541 return;
542
543 const auto &binding = getFragmentInputBindingInfo(index);
544
545 // If the input doesn't exist then then the command is silently ignored
546 // This could happen through optimization for example, the shader translator
547 // decides that a variable is not actually being used and optimizes it away.
548 if (binding.name.empty())
549 return;
550
551 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
552}
553
Martin Radev4c4c8e72016-08-04 12:25:34 +0300554// The attached shaders are checked for linking errors by matching up their variables.
555// Uniform, input and output variables get collected.
556// The code gets compiled into binaries.
Jamie Madill9082b982016-04-27 15:21:51 -0400557Error Program::link(const ContextState &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000558{
559 unlink(false);
560
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000561 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000562 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000563
Martin Radev4c4c8e72016-08-04 12:25:34 +0300564 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500565
Jamie Madill192745a2016-12-22 15:58:21 -0500566 auto vertexShader = mState.mAttachedVertexShader;
567 auto fragmentShader = mState.mAttachedFragmentShader;
568 auto computeShader = mState.mAttachedComputeShader;
569
570 bool isComputeShaderAttached = (computeShader != nullptr);
571 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300572 // Check whether we both have a compute and non-compute shaders attached.
573 // If there are of both types attached, then linking should fail.
574 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
575 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500576 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300577 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
578 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400579 }
580
Jamie Madill192745a2016-12-22 15:58:21 -0500581 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500582 {
Jamie Madill192745a2016-12-22 15:58:21 -0500583 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300584 {
585 mInfoLog << "Attached compute shader is not compiled.";
586 return NoError();
587 }
Jamie Madill192745a2016-12-22 15:58:21 -0500588 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300589
Jamie Madill192745a2016-12-22 15:58:21 -0500590 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300591
592 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
593 // If the work group size is not specified, a link time error should occur.
594 if (!mState.mComputeShaderLocalSize.isDeclared())
595 {
596 mInfoLog << "Work group size is not specified.";
597 return NoError();
598 }
599
600 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
601 {
602 return NoError();
603 }
604
605 if (!linkUniformBlocks(mInfoLog, caps))
606 {
607 return NoError();
608 }
609
Jamie Madill192745a2016-12-22 15:58:21 -0500610 gl::VaryingPacking noVaryingPacking(0, PackMode::ANGLE_RELAXED);
611 ANGLE_TRY_RESULT(mProgram->link(data, noVaryingPacking, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500612 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300613 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500614 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300615 }
616 }
617 else
618 {
Jamie Madill192745a2016-12-22 15:58:21 -0500619 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300620 {
621 return NoError();
622 }
Jamie Madill192745a2016-12-22 15:58:21 -0500623 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300624
Jamie Madill192745a2016-12-22 15:58:21 -0500625 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300626 {
627 return NoError();
628 }
Jamie Madill192745a2016-12-22 15:58:21 -0500629 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300630
Jamie Madill192745a2016-12-22 15:58:21 -0500631 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300632 {
633 mInfoLog << "Fragment shader version does not match vertex shader version.";
634 return NoError();
635 }
636
Jamie Madilleb979bf2016-11-15 12:28:46 -0500637 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300638 {
639 return NoError();
640 }
641
Jamie Madill192745a2016-12-22 15:58:21 -0500642 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300643 {
644 return NoError();
645 }
646
647 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
648 {
649 return NoError();
650 }
651
652 if (!linkUniformBlocks(mInfoLog, caps))
653 {
654 return NoError();
655 }
656
657 const auto &mergedVaryings = getMergedVaryings();
658
659 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
660 {
661 return NoError();
662 }
663
664 linkOutputVariables();
665
Jamie Madill192745a2016-12-22 15:58:21 -0500666 // Validate we can pack the varyings.
667 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
668
669 // Map the varyings to the register file
670 // In WebGL, we use a slightly different handling for packing variables.
671 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
672 : PackMode::ANGLE_RELAXED;
673 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
674 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
675 mState.getTransformFeedbackVaryingNames()))
676 {
677 return NoError();
678 }
679
680 ANGLE_TRY_RESULT(mProgram->link(data, varyingPacking, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500681 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300682 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500683 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300684 }
685
686 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500687 }
688
Jamie Madill4a3c2342015-10-08 12:58:45 -0400689 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400690
Martin Radev4c4c8e72016-08-04 12:25:34 +0300691 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000692}
693
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000694// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000695void Program::unlink(bool destroy)
696{
697 if (destroy) // Object being destructed
698 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400699 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000700 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400701 mState.mAttachedFragmentShader->release();
702 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703 }
704
Jamie Madill48ef11b2016-04-27 15:21:52 -0400705 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000706 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400707 mState.mAttachedVertexShader->release();
708 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000709 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300710
711 if (mState.mAttachedComputeShader)
712 {
713 mState.mAttachedComputeShader->release();
714 mState.mAttachedComputeShader = nullptr;
715 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716 }
717
Jamie Madill48ef11b2016-04-27 15:21:52 -0400718 mState.mAttributes.clear();
719 mState.mActiveAttribLocationsMask.reset();
720 mState.mTransformFeedbackVaryingVars.clear();
721 mState.mUniforms.clear();
722 mState.mUniformLocations.clear();
723 mState.mUniformBlocks.clear();
724 mState.mOutputVariables.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300725 mState.mComputeShaderLocalSize.fill(1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500726
Geoff Lang7dd2e102014-11-10 15:19:26 -0500727 mValidated = false;
728
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000729 mLinked = false;
730}
731
Geoff Lange1a27752015-10-05 13:16:04 -0400732bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000733{
734 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000735}
736
Jamie Madilla2c74982016-12-12 11:20:42 -0500737Error Program::loadBinary(const Context *context,
738 GLenum binaryFormat,
739 const void *binary,
740 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000741{
742 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000743
Geoff Lang7dd2e102014-11-10 15:19:26 -0500744#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800745 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500746#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400747 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
748 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000749 {
Jamie Madillf6113162015-05-07 11:49:21 -0400750 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800751 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752 }
753
Geoff Langc46cc2f2015-10-01 17:16:20 -0400754 BinaryInputStream stream(binary, length);
755
Jamie Madilla2c74982016-12-12 11:20:42 -0500756 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
757 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
758 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
759 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500760 {
Jamie Madillf6113162015-05-07 11:49:21 -0400761 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800762 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500763 }
764
Jamie Madilla2c74982016-12-12 11:20:42 -0500765 int majorVersion = stream.readInt<int>();
766 int minorVersion = stream.readInt<int>();
767 if (majorVersion != context->getClientMajorVersion() ||
768 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500769 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500770 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800771 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500772 }
773
Martin Radev4c4c8e72016-08-04 12:25:34 +0300774 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
775 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
776 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
777
Jamie Madill63805b42015-08-25 13:17:39 -0400778 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
779 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400780 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500781
Jamie Madill3da79b72015-04-27 11:09:17 -0400782 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400783 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400784 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
785 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400786 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400787 LoadShaderVar(&stream, &attrib);
788 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400789 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400790 }
791
Jamie Madill62d31cb2015-09-11 13:25:51 -0400792 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400793 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400794 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
795 {
796 LinkedUniform uniform;
797 LoadShaderVar(&stream, &uniform);
798
799 uniform.blockIndex = stream.readInt<int>();
800 uniform.blockInfo.offset = stream.readInt<int>();
801 uniform.blockInfo.arrayStride = stream.readInt<int>();
802 uniform.blockInfo.matrixStride = stream.readInt<int>();
803 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
804
Jamie Madill48ef11b2016-04-27 15:21:52 -0400805 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400806 }
807
808 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400809 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400810 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
811 uniformIndexIndex++)
812 {
813 VariableLocation variable;
814 stream.readString(&variable.name);
815 stream.readInt(&variable.element);
816 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400817 stream.readBool(&variable.used);
818 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400819
Jamie Madill48ef11b2016-04-27 15:21:52 -0400820 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400821 }
822
823 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400824 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400825 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
826 ++uniformBlockIndex)
827 {
828 UniformBlock uniformBlock;
829 stream.readString(&uniformBlock.name);
830 stream.readBool(&uniformBlock.isArray);
831 stream.readInt(&uniformBlock.arrayElement);
832 stream.readInt(&uniformBlock.dataSize);
833 stream.readBool(&uniformBlock.vertexStaticUse);
834 stream.readBool(&uniformBlock.fragmentStaticUse);
835
836 unsigned int numMembers = stream.readInt<unsigned int>();
837 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
838 {
839 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
840 }
841
Jamie Madill48ef11b2016-04-27 15:21:52 -0400842 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400843 }
844
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500845 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
846 ++bindingIndex)
847 {
848 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
849 mState.mActiveUniformBlockBindings.set(bindingIndex,
850 mState.mUniformBlockBindings[bindingIndex] != 0);
851 }
852
Brandon Jones1048ea72015-10-06 15:34:52 -0700853 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400854 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700855 for (unsigned int transformFeedbackVaryingIndex = 0;
856 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
857 ++transformFeedbackVaryingIndex)
858 {
859 sh::Varying varying;
860 stream.readInt(&varying.arraySize);
861 stream.readInt(&varying.type);
862 stream.readString(&varying.name);
863
Jamie Madill48ef11b2016-04-27 15:21:52 -0400864 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700865 }
866
Jamie Madill48ef11b2016-04-27 15:21:52 -0400867 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400868
Jamie Madill80a6fc02015-08-21 16:53:16 -0400869 unsigned int outputVarCount = stream.readInt<unsigned int>();
870 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
871 {
872 int locationIndex = stream.readInt<int>();
873 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400874 stream.readInt(&locationData.element);
875 stream.readInt(&locationData.index);
876 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400877 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400878 }
879
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400880 stream.readInt(&mSamplerUniformRange.start);
881 stream.readInt(&mSamplerUniformRange.end);
882
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500883 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000884
Jamie Madillb0a838b2016-11-13 20:02:12 -0500885 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500886#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500887}
888
Jamie Madilla2c74982016-12-12 11:20:42 -0500889Error Program::saveBinary(const Context *context,
890 GLenum *binaryFormat,
891 void *binary,
892 GLsizei bufSize,
893 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500894{
895 if (binaryFormat)
896 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400897 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500898 }
899
900 BinaryOutputStream stream;
901
Geoff Lang7dd2e102014-11-10 15:19:26 -0500902 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
903
Jamie Madilla2c74982016-12-12 11:20:42 -0500904 // nullptr context is supported when computing binary length.
905 if (context)
906 {
907 stream.writeInt(context->getClientVersion().major);
908 stream.writeInt(context->getClientVersion().minor);
909 }
910 else
911 {
912 stream.writeInt(2);
913 stream.writeInt(0);
914 }
915
Martin Radev4c4c8e72016-08-04 12:25:34 +0300916 stream.writeInt(mState.mComputeShaderLocalSize[0]);
917 stream.writeInt(mState.mComputeShaderLocalSize[1]);
918 stream.writeInt(mState.mComputeShaderLocalSize[2]);
919
Jamie Madill48ef11b2016-04-27 15:21:52 -0400920 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500921
Jamie Madill48ef11b2016-04-27 15:21:52 -0400922 stream.writeInt(mState.mAttributes.size());
923 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400924 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400925 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400926 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400927 }
928
Jamie Madill48ef11b2016-04-27 15:21:52 -0400929 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500930 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400931 {
932 WriteShaderVar(&stream, uniform);
933
934 // FIXME: referenced
935
936 stream.writeInt(uniform.blockIndex);
937 stream.writeInt(uniform.blockInfo.offset);
938 stream.writeInt(uniform.blockInfo.arrayStride);
939 stream.writeInt(uniform.blockInfo.matrixStride);
940 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
941 }
942
Jamie Madill48ef11b2016-04-27 15:21:52 -0400943 stream.writeInt(mState.mUniformLocations.size());
944 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400945 {
946 stream.writeString(variable.name);
947 stream.writeInt(variable.element);
948 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400949 stream.writeInt(variable.used);
950 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400951 }
952
Jamie Madill48ef11b2016-04-27 15:21:52 -0400953 stream.writeInt(mState.mUniformBlocks.size());
954 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400955 {
956 stream.writeString(uniformBlock.name);
957 stream.writeInt(uniformBlock.isArray);
958 stream.writeInt(uniformBlock.arrayElement);
959 stream.writeInt(uniformBlock.dataSize);
960
961 stream.writeInt(uniformBlock.vertexStaticUse);
962 stream.writeInt(uniformBlock.fragmentStaticUse);
963
964 stream.writeInt(uniformBlock.memberUniformIndexes.size());
965 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
966 {
967 stream.writeInt(memberUniformIndex);
968 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400969 }
970
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500971 for (GLuint binding : mState.mUniformBlockBindings)
972 {
973 stream.writeInt(binding);
974 }
975
Jamie Madill48ef11b2016-04-27 15:21:52 -0400976 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
977 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700978 {
979 stream.writeInt(varying.arraySize);
980 stream.writeInt(varying.type);
981 stream.writeString(varying.name);
982 }
983
Jamie Madill48ef11b2016-04-27 15:21:52 -0400984 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400985
Jamie Madill48ef11b2016-04-27 15:21:52 -0400986 stream.writeInt(mState.mOutputVariables.size());
987 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -0400988 {
989 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -0400990 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400991 stream.writeInt(outputPair.second.index);
992 stream.writeString(outputPair.second.name);
993 }
994
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400995 stream.writeInt(mSamplerUniformRange.start);
996 stream.writeInt(mSamplerUniformRange.end);
997
Jamie Madilla2c74982016-12-12 11:20:42 -0500998 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -0500999
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001000 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001001 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001002
1003 if (streamLength > bufSize)
1004 {
1005 if (length)
1006 {
1007 *length = 0;
1008 }
1009
1010 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1011 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1012 // sizes and then copy it.
1013 return Error(GL_INVALID_OPERATION);
1014 }
1015
1016 if (binary)
1017 {
1018 char *ptr = reinterpret_cast<char*>(binary);
1019
Jamie Madill48ef11b2016-04-27 15:21:52 -04001020 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001021 ptr += streamLength;
1022
1023 ASSERT(ptr - streamLength == binary);
1024 }
1025
1026 if (length)
1027 {
1028 *length = streamLength;
1029 }
1030
He Yunchaoacd18982017-01-04 10:46:42 +08001031 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001032}
1033
1034GLint Program::getBinaryLength() const
1035{
1036 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001037 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001038 if (error.isError())
1039 {
1040 return 0;
1041 }
1042
1043 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001044}
1045
Geoff Langc5629752015-12-07 16:29:04 -05001046void Program::setBinaryRetrievableHint(bool retrievable)
1047{
1048 // TODO(jmadill) : replace with dirty bits
1049 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001050 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001051}
1052
1053bool Program::getBinaryRetrievableHint() const
1054{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001055 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001056}
1057
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001058void Program::release()
1059{
1060 mRefCount--;
1061
1062 if (mRefCount == 0 && mDeleteStatus)
1063 {
1064 mResourceManager->deleteProgram(mHandle);
1065 }
1066}
1067
1068void Program::addRef()
1069{
1070 mRefCount++;
1071}
1072
1073unsigned int Program::getRefCount() const
1074{
1075 return mRefCount;
1076}
1077
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001078int Program::getInfoLogLength() const
1079{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001080 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001081}
1082
Geoff Lange1a27752015-10-05 13:16:04 -04001083void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001084{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001085 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001086}
1087
Geoff Lange1a27752015-10-05 13:16:04 -04001088void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001089{
1090 int total = 0;
1091
Martin Radev4c4c8e72016-08-04 12:25:34 +03001092 if (mState.mAttachedComputeShader)
1093 {
1094 if (total < maxCount)
1095 {
1096 shaders[total] = mState.mAttachedComputeShader->getHandle();
1097 total++;
1098 }
1099 }
1100
Jamie Madill48ef11b2016-04-27 15:21:52 -04001101 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001102 {
1103 if (total < maxCount)
1104 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001105 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001106 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001107 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001108 }
1109
Jamie Madill48ef11b2016-04-27 15:21:52 -04001110 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001111 {
1112 if (total < maxCount)
1113 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001114 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001115 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001116 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001117 }
1118
1119 if (count)
1120 {
1121 *count = total;
1122 }
1123}
1124
Geoff Lange1a27752015-10-05 13:16:04 -04001125GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001126{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001127 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001128 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001129 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001131 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001132 }
1133 }
1134
Austin Kinrossb8af7232015-03-16 22:33:25 -07001135 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001136}
1137
Jamie Madill63805b42015-08-25 13:17:39 -04001138bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001139{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001140 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1141 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001142}
1143
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001144void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1145{
Jamie Madillc349ec02015-08-21 16:53:12 -04001146 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001147 {
1148 if (bufsize > 0)
1149 {
1150 name[0] = '\0';
1151 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001152
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001153 if (length)
1154 {
1155 *length = 0;
1156 }
1157
1158 *type = GL_NONE;
1159 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001160 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001161 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001162
1163 size_t attributeIndex = 0;
1164
Jamie Madill48ef11b2016-04-27 15:21:52 -04001165 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001166 {
1167 // Skip over inactive attributes
1168 if (attribute.staticUse)
1169 {
1170 if (static_cast<size_t>(index) == attributeIndex)
1171 {
1172 break;
1173 }
1174 attributeIndex++;
1175 }
1176 }
1177
Jamie Madill48ef11b2016-04-27 15:21:52 -04001178 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
1179 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -04001180
1181 if (bufsize > 0)
1182 {
1183 const char *string = attrib.name.c_str();
1184
1185 strncpy(name, string, bufsize);
1186 name[bufsize - 1] = '\0';
1187
1188 if (length)
1189 {
1190 *length = static_cast<GLsizei>(strlen(name));
1191 }
1192 }
1193
1194 // Always a single 'type' instance
1195 *size = 1;
1196 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001197}
1198
Geoff Lange1a27752015-10-05 13:16:04 -04001199GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001200{
Jamie Madillc349ec02015-08-21 16:53:12 -04001201 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001202 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001203 return 0;
1204 }
1205
1206 GLint count = 0;
1207
Jamie Madill48ef11b2016-04-27 15:21:52 -04001208 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001209 {
1210 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001211 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001212
1213 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001214}
1215
Geoff Lange1a27752015-10-05 13:16:04 -04001216GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001217{
Jamie Madillc349ec02015-08-21 16:53:12 -04001218 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001219 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001220 return 0;
1221 }
1222
1223 size_t maxLength = 0;
1224
Jamie Madill48ef11b2016-04-27 15:21:52 -04001225 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001226 {
1227 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001228 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001229 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001230 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001231 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001232
Jamie Madillc349ec02015-08-21 16:53:12 -04001233 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001234}
1235
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236GLint Program::getFragDataLocation(const std::string &name) const
1237{
1238 std::string baseName(name);
1239 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001240 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001241 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001242 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001243 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1244 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001245 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001246 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001247 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001248 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001249}
1250
Geoff Lange1a27752015-10-05 13:16:04 -04001251void Program::getActiveUniform(GLuint index,
1252 GLsizei bufsize,
1253 GLsizei *length,
1254 GLint *size,
1255 GLenum *type,
1256 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001257{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001258 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001259 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001260 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001261 ASSERT(index < mState.mUniforms.size());
1262 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001263
1264 if (bufsize > 0)
1265 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001266 std::string string = uniform.name;
1267 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001268 {
1269 string += "[0]";
1270 }
1271
1272 strncpy(name, string.c_str(), bufsize);
1273 name[bufsize - 1] = '\0';
1274
1275 if (length)
1276 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001277 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001278 }
1279 }
1280
Jamie Madill62d31cb2015-09-11 13:25:51 -04001281 *size = uniform.elementCount();
1282 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001283 }
1284 else
1285 {
1286 if (bufsize > 0)
1287 {
1288 name[0] = '\0';
1289 }
1290
1291 if (length)
1292 {
1293 *length = 0;
1294 }
1295
1296 *size = 0;
1297 *type = GL_NONE;
1298 }
1299}
1300
Geoff Lange1a27752015-10-05 13:16:04 -04001301GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001302{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001303 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001304 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001305 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001306 }
1307 else
1308 {
1309 return 0;
1310 }
1311}
1312
Geoff Lange1a27752015-10-05 13:16:04 -04001313GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001314{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001315 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001316
1317 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001318 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001319 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001320 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001321 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001322 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001323 size_t length = uniform.name.length() + 1u;
1324 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001325 {
1326 length += 3; // Counting in "[0]".
1327 }
1328 maxLength = std::max(length, maxLength);
1329 }
1330 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001331 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001332
Jamie Madill62d31cb2015-09-11 13:25:51 -04001333 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001334}
1335
1336GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1337{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001338 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001339 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001340 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001341 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001342 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1343 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1344 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1345 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1346 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1347 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1348 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1349 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1350 default:
1351 UNREACHABLE();
1352 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001353 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001354 return 0;
1355}
1356
1357bool Program::isValidUniformLocation(GLint location) const
1358{
Jamie Madille2e406c2016-06-02 13:04:10 -04001359 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001360 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1361 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001362}
1363
1364bool Program::isIgnoredUniformLocation(GLint location) const
1365{
1366 // Location is ignored if it is -1 or it was bound but non-existant in the shader or optimized
1367 // out
1368 return location == -1 ||
Jamie Madill48ef11b2016-04-27 15:21:52 -04001369 (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1370 mState.mUniformLocations[static_cast<size_t>(location)].ignored);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001371}
1372
Jamie Madill62d31cb2015-09-11 13:25:51 -04001373const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001374{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001375 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1376 return mState.mUniforms[mState.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001377}
1378
Jamie Madill62d31cb2015-09-11 13:25:51 -04001379GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001381 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001382}
1383
Jamie Madill62d31cb2015-09-11 13:25:51 -04001384GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001386 return mState.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387}
1388
1389void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1390{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001391 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1392 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393}
1394
1395void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1396{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001397 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1398 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399}
1400
1401void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1402{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001403 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1404 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001405}
1406
1407void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1408{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001409 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1410 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411}
1412
1413void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1414{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001415 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1416 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001417}
1418
1419void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1420{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001421 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1422 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001423}
1424
1425void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1426{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001427 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1428 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001429}
1430
1431void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1432{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001433 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1434 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001435}
1436
1437void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1438{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001439 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1440 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001441}
1442
1443void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1444{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001445 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1446 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001447}
1448
1449void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1450{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001451 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1452 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001453}
1454
1455void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1456{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001457 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1458 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001459}
1460
1461void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1462{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001463 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1464 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001465}
1466
1467void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1468{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001469 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1470 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471}
1472
1473void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1474{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001475 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1476 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001477}
1478
1479void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1480{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001481 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1482 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001483}
1484
1485void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1486{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001487 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1488 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001489}
1490
1491void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1492{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001493 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1494 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001495}
1496
1497void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1498{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001499 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1500 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001501}
1502
1503void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1504{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001505 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1506 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001507}
1508
1509void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1510{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001511 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1512 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001513}
1514
Geoff Lange1a27752015-10-05 13:16:04 -04001515void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001516{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001517 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001518}
1519
Geoff Lange1a27752015-10-05 13:16:04 -04001520void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001522 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523}
1524
Geoff Lange1a27752015-10-05 13:16:04 -04001525void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001526{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001527 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001528}
1529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001530void Program::flagForDeletion()
1531{
1532 mDeleteStatus = true;
1533}
1534
1535bool Program::isFlaggedForDeletion() const
1536{
1537 return mDeleteStatus;
1538}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001539
Brandon Jones43a53e22014-08-28 16:23:22 -07001540void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001541{
1542 mInfoLog.reset();
1543
Geoff Lang7dd2e102014-11-10 15:19:26 -05001544 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001545 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001546 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001547 }
1548 else
1549 {
Jamie Madillf6113162015-05-07 11:49:21 -04001550 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001551 }
1552}
1553
Geoff Lang7dd2e102014-11-10 15:19:26 -05001554bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1555{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001556 // Skip cache if we're using an infolog, so we get the full error.
1557 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1558 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1559 {
1560 return mCachedValidateSamplersResult.value();
1561 }
1562
1563 if (mTextureUnitTypesCache.empty())
1564 {
1565 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1566 }
1567 else
1568 {
1569 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1570 }
1571
1572 // if any two active samplers in a program are of different types, but refer to the same
1573 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1574 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1575 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1576 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1577 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001578 const LinkedUniform &uniform = mState.mUniforms[samplerIndex];
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001579 ASSERT(uniform.isSampler());
1580
1581 if (!uniform.staticUse)
1582 continue;
1583
1584 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1585 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1586
1587 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1588 {
1589 GLuint textureUnit = dataPtr[arrayElement];
1590
1591 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1592 {
1593 if (infoLog)
1594 {
1595 (*infoLog) << "Sampler uniform (" << textureUnit
1596 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1597 << caps.maxCombinedTextureImageUnits << ")";
1598 }
1599
1600 mCachedValidateSamplersResult = false;
1601 return false;
1602 }
1603
1604 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1605 {
1606 if (textureType != mTextureUnitTypesCache[textureUnit])
1607 {
1608 if (infoLog)
1609 {
1610 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1611 "image unit ("
1612 << textureUnit << ").";
1613 }
1614
1615 mCachedValidateSamplersResult = false;
1616 return false;
1617 }
1618 }
1619 else
1620 {
1621 mTextureUnitTypesCache[textureUnit] = textureType;
1622 }
1623 }
1624 }
1625
1626 mCachedValidateSamplersResult = true;
1627 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001628}
1629
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001630bool Program::isValidated() const
1631{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001632 return mValidated;
1633}
1634
Geoff Lange1a27752015-10-05 13:16:04 -04001635GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001637 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638}
1639
1640void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1641{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001642 ASSERT(
1643 uniformBlockIndex <
1644 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001645
Jamie Madill48ef11b2016-04-27 15:21:52 -04001646 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647
1648 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001649 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650 std::string string = uniformBlock.name;
1651
Jamie Madill62d31cb2015-09-11 13:25:51 -04001652 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001653 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001654 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001655 }
1656
1657 strncpy(uniformBlockName, string.c_str(), bufSize);
1658 uniformBlockName[bufSize - 1] = '\0';
1659
1660 if (length)
1661 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001662 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001663 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001664 }
1665}
1666
Geoff Lange1a27752015-10-05 13:16:04 -04001667GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001668{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001669 int maxLength = 0;
1670
1671 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001672 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001673 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1675 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001676 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677 if (!uniformBlock.name.empty())
1678 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001679 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001680
1681 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001682 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001683
1684 maxLength = std::max(length + arrayLength, maxLength);
1685 }
1686 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001687 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001688
1689 return maxLength;
1690}
1691
Geoff Lange1a27752015-10-05 13:16:04 -04001692GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001694 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -05001695 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001696
Jamie Madill48ef11b2016-04-27 15:21:52 -04001697 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001698 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1699 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001700 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001701 if (uniformBlock.name == baseName)
1702 {
1703 const bool arrayElementZero =
1704 (subscript == GL_INVALID_INDEX &&
1705 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1706 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1707 {
1708 return blockIndex;
1709 }
1710 }
1711 }
1712
1713 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001714}
1715
Jamie Madill62d31cb2015-09-11 13:25:51 -04001716const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001717{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001718 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1719 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001720}
1721
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001722void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1723{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001724 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001725 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001726 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001727}
1728
1729GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1730{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001731 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001732}
1733
1734void Program::resetUniformBlockBindings()
1735{
1736 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1737 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001738 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001739 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001740 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001741}
1742
Geoff Lang48dcae72014-02-05 16:28:24 -05001743void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1744{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001745 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001746 for (GLsizei i = 0; i < count; i++)
1747 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001748 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001749 }
1750
Jamie Madill48ef11b2016-04-27 15:21:52 -04001751 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001752}
1753
1754void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1755{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001756 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001757 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001758 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1759 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001760 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1761 if (length)
1762 {
1763 *length = lastNameIdx;
1764 }
1765 if (size)
1766 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001767 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001768 }
1769 if (type)
1770 {
1771 *type = varying.type;
1772 }
1773 if (name)
1774 {
1775 memcpy(name, varying.name.c_str(), lastNameIdx);
1776 name[lastNameIdx] = '\0';
1777 }
1778 }
1779}
1780
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001781GLsizei Program::getTransformFeedbackVaryingCount() const
1782{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001783 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001784 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001785 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001786 }
1787 else
1788 {
1789 return 0;
1790 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001791}
1792
1793GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1794{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001795 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001796 {
1797 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001798 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001799 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001800 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1801 }
1802
1803 return maxSize;
1804 }
1805 else
1806 {
1807 return 0;
1808 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001809}
1810
1811GLenum Program::getTransformFeedbackBufferMode() const
1812{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001813 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001814}
1815
Jamie Madill192745a2016-12-22 15:58:21 -05001816bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001817{
Jamie Madill192745a2016-12-22 15:58:21 -05001818 const Shader *vertexShader = mState.mAttachedVertexShader;
1819 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1820
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001821 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1822
Jamie Madill4cff2472015-08-21 16:53:18 -04001823 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1824 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001825
Sami Väisänen46eaa942016-06-29 10:26:37 +03001826 std::map<GLuint, std::string> staticFragmentInputLocations;
1827
Jamie Madill4cff2472015-08-21 16:53:18 -04001828 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001830 bool matched = false;
1831
1832 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001833 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001834 {
1835 continue;
1836 }
1837
Jamie Madill4cff2472015-08-21 16:53:18 -04001838 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001839 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001840 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001842 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001843 if (!linkValidateVaryings(infoLog, output.name, input, output,
1844 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001845 {
1846 return false;
1847 }
1848
Geoff Lang7dd2e102014-11-10 15:19:26 -05001849 matched = true;
1850 break;
1851 }
1852 }
1853
1854 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001855 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001857 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001858 return false;
1859 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001860
1861 // Check for aliased path rendering input bindings (if any).
1862 // If more than one binding refer statically to the same
1863 // location the link must fail.
1864
1865 if (!output.staticUse)
1866 continue;
1867
1868 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1869 if (inputBinding == -1)
1870 continue;
1871
1872 const auto it = staticFragmentInputLocations.find(inputBinding);
1873 if (it == std::end(staticFragmentInputLocations))
1874 {
1875 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1876 }
1877 else
1878 {
1879 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1880 << it->second;
1881 return false;
1882 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001883 }
1884
Jamie Madillada9ecc2015-08-17 12:53:37 -04001885 // TODO(jmadill): verify no unmatched vertex varyings?
1886
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 return true;
1888}
1889
Martin Radev4c4c8e72016-08-04 12:25:34 +03001890bool Program::validateVertexAndFragmentUniforms(InfoLog &infoLog) const
Jamie Madillea918db2015-08-18 14:48:59 -04001891{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001892 // Check that uniforms defined in the vertex and fragment shaders are identical
1893 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001894 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1895 const std::vector<sh::Uniform> &fragmentUniforms =
1896 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001897
Jamie Madillea918db2015-08-18 14:48:59 -04001898 for (const sh::Uniform &vertexUniform : vertexUniforms)
1899 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001900 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001901 }
1902
1903 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1904 {
1905 auto entry = linkedUniforms.find(fragmentUniform.name);
1906 if (entry != linkedUniforms.end())
1907 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001908 LinkedUniform *vertexUniform = &entry->second;
1909 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1910 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001911 {
1912 return false;
1913 }
1914 }
1915 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03001916 return true;
1917}
1918
Jamie Madilla2c74982016-12-12 11:20:42 -05001919bool Program::linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001920{
1921 if (mState.mAttachedVertexShader && mState.mAttachedFragmentShader)
1922 {
1923 ASSERT(mState.mAttachedComputeShader == nullptr);
1924 if (!validateVertexAndFragmentUniforms(infoLog))
1925 {
1926 return false;
1927 }
1928 }
Jamie Madillea918db2015-08-18 14:48:59 -04001929
Jamie Madill62d31cb2015-09-11 13:25:51 -04001930 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1931 // Also check the maximum uniform vector and sampler counts.
1932 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1933 {
1934 return false;
1935 }
1936
Geoff Langd8605522016-04-13 10:19:12 -04001937 if (!indexUniforms(infoLog, caps, uniformBindings))
1938 {
1939 return false;
1940 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001941
Jamie Madillea918db2015-08-18 14:48:59 -04001942 return true;
1943}
1944
Jamie Madilla2c74982016-12-12 11:20:42 -05001945bool Program::indexUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001946{
Geoff Langd8605522016-04-13 10:19:12 -04001947 // Uniforms awaiting a location
1948 std::vector<VariableLocation> unboundUniforms;
1949 std::map<GLuint, VariableLocation> boundUniforms;
1950 int maxUniformLocation = -1;
1951
1952 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001953 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001954 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001955 const LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001956
Geoff Langd8605522016-04-13 10:19:12 -04001957 if (uniform.isBuiltIn())
1958 {
1959 continue;
1960 }
1961
1962 int bindingLocation = uniformBindings.getBinding(uniform.name);
1963
1964 // Verify that this location isn't bound twice
1965 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1966 {
1967 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1968 return false;
1969 }
1970
Jamie Madill62d31cb2015-09-11 13:25:51 -04001971 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1972 {
Geoff Langd8605522016-04-13 10:19:12 -04001973 VariableLocation location(uniform.name, arrayIndex,
1974 static_cast<unsigned int>(uniformIndex));
1975
1976 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001977 {
Geoff Langd8605522016-04-13 10:19:12 -04001978 boundUniforms[bindingLocation] = location;
1979 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1980 }
1981 else
1982 {
1983 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001984 }
1985 }
1986 }
Geoff Langd8605522016-04-13 10:19:12 -04001987
1988 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1989 // not be assigned to those locations.
1990 std::set<GLuint> reservedLocations;
1991 for (const auto &binding : uniformBindings)
1992 {
1993 GLuint location = binding.second;
1994 if (boundUniforms.find(location) == boundUniforms.end())
1995 {
1996 reservedLocations.insert(location);
1997 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1998 }
1999 }
2000
2001 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04002002 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04002003 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
2004 static_cast<size_t>(maxUniformLocation + 1)));
2005
2006 // Assign bound uniforms
2007 for (const auto &boundUniform : boundUniforms)
2008 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002009 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04002010 }
2011
2012 // Assign reserved uniforms
2013 for (const auto &reservedLocation : reservedLocations)
2014 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002015 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04002016 }
2017
2018 // Assign unbound uniforms
2019 size_t nextUniformLocation = 0;
2020 for (const auto &unboundUniform : unboundUniforms)
2021 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002022 while (mState.mUniformLocations[nextUniformLocation].used ||
2023 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04002024 {
2025 nextUniformLocation++;
2026 }
2027
Jamie Madill48ef11b2016-04-27 15:21:52 -04002028 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
2029 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04002030 nextUniformLocation++;
2031 }
2032
2033 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002034}
2035
Martin Radev4c4c8e72016-08-04 12:25:34 +03002036bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2037 const std::string &uniformName,
2038 const sh::InterfaceBlockField &vertexUniform,
2039 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002040{
Jamie Madillc4c744222015-11-04 09:39:47 -05002041 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
2042 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002043 {
2044 return false;
2045 }
2046
2047 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2048 {
Jamie Madillf6113162015-05-07 11:49:21 -04002049 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002050 return false;
2051 }
2052
2053 return true;
2054}
2055
Jamie Madilleb979bf2016-11-15 12:28:46 -05002056// Assigns locations to all attributes from the bindings and program locations.
2057bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002058{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002059 const auto *vertexShader = mState.getAttachedVertexShader();
2060
Geoff Lang7dd2e102014-11-10 15:19:26 -05002061 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002062 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002063 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002064
2065 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002066 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002067 {
Jamie Madillf6113162015-05-07 11:49:21 -04002068 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002069 return false;
2070 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002072 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002073
Jamie Madillc349ec02015-08-21 16:53:12 -04002074 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002075 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002076 {
2077 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05002078 ASSERT(attribute.staticUse);
2079
Jamie Madilleb979bf2016-11-15 12:28:46 -05002080 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002081 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002082 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002083 attribute.location = bindingLocation;
2084 }
2085
2086 if (attribute.location != -1)
2087 {
2088 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002089 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002090
Jamie Madill63805b42015-08-25 13:17:39 -04002091 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002092 {
Jamie Madillf6113162015-05-07 11:49:21 -04002093 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002094 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002095
2096 return false;
2097 }
2098
Jamie Madill63805b42015-08-25 13:17:39 -04002099 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002100 {
Jamie Madill63805b42015-08-25 13:17:39 -04002101 const int regLocation = attribute.location + reg;
2102 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002103
2104 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002105 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002106 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002107 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002108 // TODO(jmadill): fix aliasing on ES2
2109 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002110 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002111 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002112 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002113 return false;
2114 }
2115 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002116 else
2117 {
Jamie Madill63805b42015-08-25 13:17:39 -04002118 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002119 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002120
Jamie Madill63805b42015-08-25 13:17:39 -04002121 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002122 }
2123 }
2124 }
2125
2126 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002127 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002128 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002129 ASSERT(attribute.staticUse);
2130
Jamie Madillc349ec02015-08-21 16:53:12 -04002131 // Not set by glBindAttribLocation or by location layout qualifier
2132 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002133 {
Jamie Madill63805b42015-08-25 13:17:39 -04002134 int regs = VariableRegisterCount(attribute.type);
2135 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002136
Jamie Madill63805b42015-08-25 13:17:39 -04002137 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002138 {
Jamie Madillf6113162015-05-07 11:49:21 -04002139 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002140 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002141 }
2142
Jamie Madillc349ec02015-08-21 16:53:12 -04002143 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144 }
2145 }
2146
Jamie Madill48ef11b2016-04-27 15:21:52 -04002147 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002148 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002149 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04002150 ASSERT(attribute.location != -1);
2151 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002152
Jamie Madill63805b42015-08-25 13:17:39 -04002153 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002154 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002155 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002156 }
2157 }
2158
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159 return true;
2160}
2161
Martin Radev4c4c8e72016-08-04 12:25:34 +03002162bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2163 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2164 const std::string &errorMessage,
2165 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002166{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002167 GLuint blockCount = 0;
2168 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002169 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002170 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002171 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002172 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002173 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002174 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002175 return false;
2176 }
2177 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002179 return true;
2180}
Jamie Madille473dee2015-08-18 14:49:01 -04002181
Martin Radev4c4c8e72016-08-04 12:25:34 +03002182bool Program::validateVertexAndFragmentInterfaceBlocks(
2183 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2184 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2185 InfoLog &infoLog) const
2186{
2187 // Check that interface blocks defined in the vertex and fragment shaders are identical
2188 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2189 UniformBlockMap linkedUniformBlocks;
2190
2191 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2192 {
2193 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2194 }
2195
Jamie Madille473dee2015-08-18 14:49:01 -04002196 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002197 {
Jamie Madille473dee2015-08-18 14:49:01 -04002198 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002199 if (entry != linkedUniformBlocks.end())
2200 {
2201 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2202 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2203 {
2204 return false;
2205 }
2206 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002207 }
2208 return true;
2209}
Jamie Madille473dee2015-08-18 14:49:01 -04002210
Martin Radev4c4c8e72016-08-04 12:25:34 +03002211bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2212{
2213 if (mState.mAttachedComputeShader)
2214 {
2215 const Shader &computeShader = *mState.mAttachedComputeShader;
2216 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2217
2218 if (!validateUniformBlocksCount(
2219 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2220 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2221 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002222 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002223 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002224 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002225 return true;
2226 }
2227
2228 const Shader &vertexShader = *mState.mAttachedVertexShader;
2229 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2230
2231 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2232 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2233
2234 if (!validateUniformBlocksCount(
2235 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2236 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2237 {
2238 return false;
2239 }
2240 if (!validateUniformBlocksCount(
2241 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2242 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2243 infoLog))
2244 {
2245
2246 return false;
2247 }
2248 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2249 infoLog))
2250 {
2251 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002252 }
Jamie Madille473dee2015-08-18 14:49:01 -04002253
Geoff Lang7dd2e102014-11-10 15:19:26 -05002254 return true;
2255}
2256
Jamie Madilla2c74982016-12-12 11:20:42 -05002257bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002258 const sh::InterfaceBlock &vertexInterfaceBlock,
2259 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002260{
2261 const char* blockName = vertexInterfaceBlock.name.c_str();
2262 // validate blocks for the same member types
2263 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2264 {
Jamie Madillf6113162015-05-07 11:49:21 -04002265 infoLog << "Types for interface block '" << blockName
2266 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002267 return false;
2268 }
2269 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2270 {
Jamie Madillf6113162015-05-07 11:49:21 -04002271 infoLog << "Array sizes differ for interface block '" << blockName
2272 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002273 return false;
2274 }
2275 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2276 {
Jamie Madillf6113162015-05-07 11:49:21 -04002277 infoLog << "Layout qualifiers differ for interface block '" << blockName
2278 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002279 return false;
2280 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002281 const unsigned int numBlockMembers =
2282 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002283 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2284 {
2285 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2286 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2287 if (vertexMember.name != fragmentMember.name)
2288 {
Jamie Madillf6113162015-05-07 11:49:21 -04002289 infoLog << "Name mismatch for field " << blockMemberIndex
2290 << " of interface block '" << blockName
2291 << "': (in vertex: '" << vertexMember.name
2292 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002293 return false;
2294 }
2295 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2296 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2297 {
2298 return false;
2299 }
2300 }
2301 return true;
2302}
2303
2304bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2305 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2306{
2307 if (vertexVariable.type != fragmentVariable.type)
2308 {
Jamie Madillf6113162015-05-07 11:49:21 -04002309 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002310 return false;
2311 }
2312 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2313 {
Jamie Madillf6113162015-05-07 11:49:21 -04002314 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002315 return false;
2316 }
2317 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2318 {
Jamie Madillf6113162015-05-07 11:49:21 -04002319 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002320 return false;
2321 }
2322
2323 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2324 {
Jamie Madillf6113162015-05-07 11:49:21 -04002325 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002326 return false;
2327 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002328 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002329 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2330 {
2331 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2332 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2333
2334 if (vertexMember.name != fragmentMember.name)
2335 {
Jamie Madillf6113162015-05-07 11:49:21 -04002336 infoLog << "Name mismatch for field '" << memberIndex
2337 << "' of " << variableName
2338 << ": (in vertex: '" << vertexMember.name
2339 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002340 return false;
2341 }
2342
2343 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2344 vertexMember.name + "'";
2345
2346 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2347 {
2348 return false;
2349 }
2350 }
2351
2352 return true;
2353}
2354
2355bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2356{
Cooper Partin1acf4382015-06-12 12:38:57 -07002357#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2358 const bool validatePrecision = true;
2359#else
2360 const bool validatePrecision = false;
2361#endif
2362
2363 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002364 {
2365 return false;
2366 }
2367
2368 return true;
2369}
2370
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002371bool Program::linkValidateVaryings(InfoLog &infoLog,
2372 const std::string &varyingName,
2373 const sh::Varying &vertexVarying,
2374 const sh::Varying &fragmentVarying,
2375 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002376{
2377 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2378 {
2379 return false;
2380 }
2381
Jamie Madille9cc4692015-02-19 16:00:13 -05002382 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002383 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002384 infoLog << "Interpolation types for " << varyingName
2385 << " differ between vertex and fragment shaders.";
2386 return false;
2387 }
2388
2389 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2390 {
2391 infoLog << "Invariance for " << varyingName
2392 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002393 return false;
2394 }
2395
2396 return true;
2397}
2398
Jamie Madillccdf74b2015-08-18 10:46:12 -04002399bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002400 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002401 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002402{
2403 size_t totalComponents = 0;
2404
Jamie Madillccdf74b2015-08-18 10:46:12 -04002405 std::set<std::string> uniqueNames;
2406
Jamie Madill48ef11b2016-04-27 15:21:52 -04002407 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002408 {
2409 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002410 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002411 {
Jamie Madill192745a2016-12-22 15:58:21 -05002412 const sh::Varying *varying = ref.second.get();
2413
Jamie Madillccdf74b2015-08-18 10:46:12 -04002414 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002415 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002416 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002417 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002418 infoLog << "Two transform feedback varyings specify the same output variable ("
2419 << tfVaryingName << ").";
2420 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002421 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002422 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002423
Geoff Lang1a683462015-09-29 15:09:59 -04002424 if (varying->isArray())
2425 {
2426 infoLog << "Capture of arrays is undefined and not supported.";
2427 return false;
2428 }
2429
Jamie Madillccdf74b2015-08-18 10:46:12 -04002430 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002431 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002432 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002433 componentCount > caps.maxTransformFeedbackSeparateComponents)
2434 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002435 infoLog << "Transform feedback varying's " << varying->name << " components ("
2436 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002437 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002438 return false;
2439 }
2440
2441 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002442 found = true;
2443 break;
2444 }
2445 }
2446
Jamie Madill89bb70e2015-08-31 14:18:39 -04002447 if (tfVaryingName.find('[') != std::string::npos)
2448 {
Geoff Lang1a683462015-09-29 15:09:59 -04002449 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002450 return false;
2451 }
2452
Geoff Lang7dd2e102014-11-10 15:19:26 -05002453 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2454 ASSERT(found);
2455 }
2456
Jamie Madill48ef11b2016-04-27 15:21:52 -04002457 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002458 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002459 {
Jamie Madillf6113162015-05-07 11:49:21 -04002460 infoLog << "Transform feedback varying total components (" << totalComponents
2461 << ") exceed the maximum interleaved components ("
2462 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002463 return false;
2464 }
2465
2466 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002467}
2468
Jamie Madill192745a2016-12-22 15:58:21 -05002469void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002470{
2471 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002472 mState.mTransformFeedbackVaryingVars.clear();
2473 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002474 {
Jamie Madill192745a2016-12-22 15:58:21 -05002475 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002476 {
Jamie Madill192745a2016-12-22 15:58:21 -05002477 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002478 if (tfVaryingName == varying->name)
2479 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002480 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002481 break;
2482 }
2483 }
2484 }
2485}
2486
Jamie Madill192745a2016-12-22 15:58:21 -05002487Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002488{
Jamie Madill192745a2016-12-22 15:58:21 -05002489 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002490
Jamie Madill48ef11b2016-04-27 15:21:52 -04002491 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002492 {
Jamie Madill192745a2016-12-22 15:58:21 -05002493 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002494 }
2495
Jamie Madill48ef11b2016-04-27 15:21:52 -04002496 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002497 {
Jamie Madill192745a2016-12-22 15:58:21 -05002498 merged[varying.name].fragment = &varying;
2499 }
2500
2501 return merged;
2502}
2503
2504std::vector<PackedVarying> Program::getPackedVaryings(
2505 const Program::MergedVaryings &mergedVaryings) const
2506{
2507 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2508 std::vector<PackedVarying> packedVaryings;
2509
2510 for (const auto &ref : mergedVaryings)
2511 {
2512 const sh::Varying *input = ref.second.vertex;
2513 const sh::Varying *output = ref.second.fragment;
2514
2515 // Only pack varyings that have a matched input or output, plus special builtins.
2516 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002517 {
Jamie Madill192745a2016-12-22 15:58:21 -05002518 // Will get the vertex shader interpolation by default.
2519 auto interpolation = ref.second.get()->interpolation;
2520
2521 // Interpolation qualifiers must match.
2522 if (output->isStruct())
2523 {
2524 ASSERT(!output->isArray());
2525 for (const auto &field : output->fields)
2526 {
2527 ASSERT(!field.isStruct() && !field.isArray());
2528 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2529 }
2530 }
2531 else
2532 {
2533 packedVaryings.push_back(PackedVarying(*output, interpolation));
2534 }
2535 continue;
2536 }
2537
2538 // Keep Transform FB varyings in the merged list always.
2539 if (!input)
2540 {
2541 continue;
2542 }
2543
2544 for (const std::string &tfVarying : tfVaryings)
2545 {
2546 if (tfVarying == input->name)
2547 {
2548 // Transform feedback for varying structs is underspecified.
2549 // See Khronos bug 9856.
2550 // TODO(jmadill): Figure out how to be spec-compliant here.
2551 if (!input->isStruct())
2552 {
2553 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2554 packedVaryings.back().vertexOnly = true;
2555 }
2556 break;
2557 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002558 }
2559 }
2560
Jamie Madill192745a2016-12-22 15:58:21 -05002561 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2562
2563 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002564}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002565
2566void Program::linkOutputVariables()
2567{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002568 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002569 ASSERT(fragmentShader != nullptr);
2570
2571 // Skip this step for GLES2 shaders.
2572 if (fragmentShader->getShaderVersion() == 100)
2573 return;
2574
Jamie Madilla0a9e122015-09-02 15:54:30 -04002575 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002576
2577 // TODO(jmadill): any caps validation here?
2578
2579 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2580 outputVariableIndex++)
2581 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002582 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002583
2584 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2585 if (outputVariable.isBuiltIn())
2586 continue;
2587
2588 // Since multiple output locations must be specified, use 0 for non-specified locations.
2589 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2590
2591 ASSERT(outputVariable.staticUse);
2592
2593 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2594 elementIndex++)
2595 {
2596 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002597 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002598 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002599 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002600 VariableLocation(outputVariable.name, element, outputVariableIndex);
2601 }
2602 }
2603}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002604
Jamie Madilla2c74982016-12-12 11:20:42 -05002605bool Program::flattenUniformsAndCheckCapsForShader(const Shader &shader,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002606 GLuint maxUniformComponents,
2607 GLuint maxTextureImageUnits,
2608 const std::string &componentsErrorMessage,
2609 const std::string &samplerErrorMessage,
2610 std::vector<LinkedUniform> &samplerUniforms,
2611 InfoLog &infoLog)
2612{
2613 VectorAndSamplerCount vasCount;
2614 for (const sh::Uniform &uniform : shader.getUniforms())
2615 {
2616 if (uniform.staticUse)
2617 {
2618 vasCount += flattenUniform(uniform, uniform.name, &samplerUniforms);
2619 }
2620 }
2621
2622 if (vasCount.vectorCount > maxUniformComponents)
2623 {
2624 infoLog << componentsErrorMessage << maxUniformComponents << ").";
2625 return false;
2626 }
2627
2628 if (vasCount.samplerCount > maxTextureImageUnits)
2629 {
2630 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
2631 return false;
2632 }
2633
2634 return true;
2635}
2636
Jamie Madill62d31cb2015-09-11 13:25:51 -04002637bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2638{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002639 std::vector<LinkedUniform> samplerUniforms;
2640
Martin Radev4c4c8e72016-08-04 12:25:34 +03002641 if (mState.mAttachedComputeShader)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002642 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002643 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002644
2645 // TODO (mradev): check whether we need finer-grained component counting
2646 if (!flattenUniformsAndCheckCapsForShader(
2647 *computeShader, caps.maxComputeUniformComponents / 4,
2648 caps.maxComputeTextureImageUnits,
2649 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
2650 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
2651 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002652 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002653 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002654 }
2655 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002656 else
Jamie Madill62d31cb2015-09-11 13:25:51 -04002657 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002658 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002659
Martin Radev4c4c8e72016-08-04 12:25:34 +03002660 if (!flattenUniformsAndCheckCapsForShader(
2661 *vertexShader, caps.maxVertexUniformVectors, caps.maxVertexTextureImageUnits,
2662 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
2663 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
2664 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002665 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002666 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002667 }
Jamie Madilla2c74982016-12-12 11:20:42 -05002668 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002669
Martin Radev4c4c8e72016-08-04 12:25:34 +03002670 if (!flattenUniformsAndCheckCapsForShader(
2671 *fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
2672 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
2673 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms,
2674 infoLog))
2675 {
2676 return false;
2677 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002678 }
2679
Jamie Madill48ef11b2016-04-27 15:21:52 -04002680 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002681 mSamplerUniformRange.end =
2682 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2683
Jamie Madill48ef11b2016-04-27 15:21:52 -04002684 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002685
Jamie Madill62d31cb2015-09-11 13:25:51 -04002686 return true;
2687}
2688
2689Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002690 const std::string &fullName,
2691 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002692{
2693 VectorAndSamplerCount vectorAndSamplerCount;
2694
2695 if (uniform.isStruct())
2696 {
2697 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2698 {
2699 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2700
2701 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2702 {
2703 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2704 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2705
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002706 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002707 }
2708 }
2709
2710 return vectorAndSamplerCount;
2711 }
2712
2713 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002714 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002715 if (!UniformInList(mState.getUniforms(), fullName) &&
2716 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002717 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002718 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
2719 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002720 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002721
2722 // Store sampler uniforms separately, so we'll append them to the end of the list.
2723 if (isSampler)
2724 {
2725 samplerUniforms->push_back(linkedUniform);
2726 }
2727 else
2728 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002729 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002730 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002731 }
2732
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002733 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002734
2735 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2736 // Likewise, don't count "real" uniforms towards sampler count.
2737 vectorAndSamplerCount.vectorCount =
2738 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002739 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002740
2741 return vectorAndSamplerCount;
2742}
2743
2744void Program::gatherInterfaceBlockInfo()
2745{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002746 ASSERT(mState.mUniformBlocks.empty());
2747
2748 if (mState.mAttachedComputeShader)
2749 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002750 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002751
2752 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2753 {
2754
2755 // Only 'packed' blocks are allowed to be considered inactive.
2756 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2757 continue;
2758
Jamie Madilla2c74982016-12-12 11:20:42 -05002759 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002760 {
2761 if (block.name == computeBlock.name)
2762 {
2763 block.computeStaticUse = computeBlock.staticUse;
2764 }
2765 }
2766
2767 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2768 }
2769 return;
2770 }
2771
Jamie Madill62d31cb2015-09-11 13:25:51 -04002772 std::set<std::string> visitedList;
2773
Jamie Madilla2c74982016-12-12 11:20:42 -05002774 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002775
Jamie Madill62d31cb2015-09-11 13:25:51 -04002776 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2777 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002778 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002779 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2780 continue;
2781
2782 if (visitedList.count(vertexBlock.name) > 0)
2783 continue;
2784
2785 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2786 visitedList.insert(vertexBlock.name);
2787 }
2788
Jamie Madilla2c74982016-12-12 11:20:42 -05002789 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002790
2791 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2792 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002793 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002794 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2795 continue;
2796
2797 if (visitedList.count(fragmentBlock.name) > 0)
2798 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002799 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002800 {
2801 if (block.name == fragmentBlock.name)
2802 {
2803 block.fragmentStaticUse = fragmentBlock.staticUse;
2804 }
2805 }
2806
2807 continue;
2808 }
2809
2810 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2811 visitedList.insert(fragmentBlock.name);
2812 }
2813}
2814
Jamie Madill4a3c2342015-10-08 12:58:45 -04002815template <typename VarT>
2816void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2817 const std::string &prefix,
2818 int blockIndex)
2819{
2820 for (const VarT &field : fields)
2821 {
2822 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2823
2824 if (field.isStruct())
2825 {
2826 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2827 {
2828 const std::string uniformElementName =
2829 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2830 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2831 }
2832 }
2833 else
2834 {
2835 // If getBlockMemberInfo returns false, the uniform is optimized out.
2836 sh::BlockMemberInfo memberInfo;
2837 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2838 {
2839 continue;
2840 }
2841
2842 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2843 blockIndex, memberInfo);
2844
2845 // Since block uniforms have no location, we don't need to store them in the uniform
2846 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002847 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002848 }
2849 }
2850}
2851
Jamie Madill62d31cb2015-09-11 13:25:51 -04002852void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2853{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002854 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002855 size_t blockSize = 0;
2856
2857 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002858 std::stringstream blockNameStr;
2859 blockNameStr << interfaceBlock.name;
2860 if (interfaceBlock.arraySize > 0)
2861 {
2862 blockNameStr << "[0]";
2863 }
2864 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002865 {
2866 return;
2867 }
2868
2869 // Track the first and last uniform index to determine the range of active uniforms in the
2870 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002871 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002872 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002873 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002874
2875 std::vector<unsigned int> blockUniformIndexes;
2876 for (size_t blockUniformIndex = firstBlockUniformIndex;
2877 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2878 {
2879 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2880 }
2881
2882 if (interfaceBlock.arraySize > 0)
2883 {
2884 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2885 {
2886 UniformBlock block(interfaceBlock.name, true, arrayElement);
2887 block.memberUniformIndexes = blockUniformIndexes;
2888
Martin Radev4c4c8e72016-08-04 12:25:34 +03002889 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002890 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002891 case GL_VERTEX_SHADER:
2892 {
2893 block.vertexStaticUse = interfaceBlock.staticUse;
2894 break;
2895 }
2896 case GL_FRAGMENT_SHADER:
2897 {
2898 block.fragmentStaticUse = interfaceBlock.staticUse;
2899 break;
2900 }
2901 case GL_COMPUTE_SHADER:
2902 {
2903 block.computeStaticUse = interfaceBlock.staticUse;
2904 break;
2905 }
2906 default:
2907 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002908 }
2909
Qin Jiajia0350a642016-11-01 17:01:51 +08002910 // Since all block elements in an array share the same active uniforms, they will all be
2911 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2912 // here we will add every block element in the array.
2913 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002914 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002915 }
2916 }
2917 else
2918 {
2919 UniformBlock block(interfaceBlock.name, false, 0);
2920 block.memberUniformIndexes = blockUniformIndexes;
2921
Martin Radev4c4c8e72016-08-04 12:25:34 +03002922 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002923 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002924 case GL_VERTEX_SHADER:
2925 {
2926 block.vertexStaticUse = interfaceBlock.staticUse;
2927 break;
2928 }
2929 case GL_FRAGMENT_SHADER:
2930 {
2931 block.fragmentStaticUse = interfaceBlock.staticUse;
2932 break;
2933 }
2934 case GL_COMPUTE_SHADER:
2935 {
2936 block.computeStaticUse = interfaceBlock.staticUse;
2937 break;
2938 }
2939 default:
2940 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002941 }
2942
Jamie Madill4a3c2342015-10-08 12:58:45 -04002943 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002944 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002945 }
2946}
2947
2948template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002949GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002950{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002951 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2952 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002953 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2954
Corentin Wallez15ac5342016-11-03 17:06:39 -04002955 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2956 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2957 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002958 GLsizei maxElementCount =
2959 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2960
2961 GLsizei count = countIn;
2962 GLsizei clampedCount = count * vectorSize;
2963 if (clampedCount > maxElementCount)
2964 {
2965 clampedCount = maxElementCount;
2966 count = maxElementCount / vectorSize;
2967 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002968
Jamie Madill62d31cb2015-09-11 13:25:51 -04002969 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2970 {
2971 // Do a cast conversion for boolean types. From the spec:
2972 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2973 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002974 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002975 {
2976 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2977 }
2978 }
2979 else
2980 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002981 // Invalide the validation cache if we modify the sampler data.
Corentin Wallez15ac5342016-11-03 17:06:39 -04002982 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * clampedCount) != 0)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002983 {
2984 mCachedValidateSamplersResult.reset();
2985 }
2986
Corentin Wallez15ac5342016-11-03 17:06:39 -04002987 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002988 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002989
2990 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002991}
2992
2993template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002994GLsizei Program::setMatrixUniformInternal(GLint location,
2995 GLsizei count,
2996 GLboolean transpose,
2997 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002998{
2999 if (!transpose)
3000 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003001 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003002 }
3003
3004 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003005 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3006 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003007 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04003008
3009 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3010 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3011 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
3012 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
3013
3014 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003015 {
3016 size_t elementOffset = element * rows * cols;
3017
3018 for (size_t row = 0; row < rows; ++row)
3019 {
3020 for (size_t col = 0; col < cols; ++col)
3021 {
3022 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
3023 }
3024 }
3025 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003026
3027 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003028}
3029
3030template <typename DestT>
3031void Program::getUniformInternal(GLint location, DestT *dataOut) const
3032{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003033 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3034 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003035
3036 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
3037
3038 GLenum componentType = VariableComponentType(uniform.type);
3039 if (componentType == GLTypeToGLenum<DestT>::value)
3040 {
3041 memcpy(dataOut, srcPointer, uniform.getElementSize());
3042 return;
3043 }
3044
Corentin Wallez6596c462016-03-17 17:26:58 -04003045 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003046
3047 switch (componentType)
3048 {
3049 case GL_INT:
3050 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
3051 break;
3052 case GL_UNSIGNED_INT:
3053 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
3054 break;
3055 case GL_BOOL:
3056 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
3057 break;
3058 case GL_FLOAT:
3059 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
3060 break;
3061 default:
3062 UNREACHABLE();
3063 }
3064}
Jamie Madilla2c74982016-12-12 11:20:42 -05003065} // namespace gl