blob: ae6777782a053adabc79f9b67643a2fab98ed1e5 [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 Madill9082b982016-04-27 15:21:51 -040020#include "libANGLE/ContextState.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 Madill62d31cb2015-09-11 13:25:51 -040025#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040026#include "libANGLE/Uniform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050027
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028namespace gl
29{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000030
Geoff Lang7dd2e102014-11-10 15:19:26 -050031namespace
32{
33
Jamie Madill62d31cb2015-09-11 13:25:51 -040034void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
35{
36 stream->writeInt(var.type);
37 stream->writeInt(var.precision);
38 stream->writeString(var.name);
39 stream->writeString(var.mappedName);
40 stream->writeInt(var.arraySize);
41 stream->writeInt(var.staticUse);
42 stream->writeString(var.structName);
43 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050044}
45
Jamie Madill62d31cb2015-09-11 13:25:51 -040046void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
47{
48 var->type = stream->readInt<GLenum>();
49 var->precision = stream->readInt<GLenum>();
50 var->name = stream->readString();
51 var->mappedName = stream->readString();
52 var->arraySize = stream->readInt<unsigned int>();
53 var->staticUse = stream->readBool();
54 var->structName = stream->readString();
55}
56
Jamie Madill62d31cb2015-09-11 13:25:51 -040057// This simplified cast function doesn't need to worry about advanced concepts like
58// depth range values, or casting to bool.
59template <typename DestT, typename SrcT>
60DestT UniformStateQueryCast(SrcT value);
61
62// From-Float-To-Integer Casts
63template <>
64GLint UniformStateQueryCast(GLfloat value)
65{
66 return clampCast<GLint>(roundf(value));
67}
68
69template <>
70GLuint UniformStateQueryCast(GLfloat value)
71{
72 return clampCast<GLuint>(roundf(value));
73}
74
75// From-Integer-to-Integer Casts
76template <>
77GLint UniformStateQueryCast(GLuint value)
78{
79 return clampCast<GLint>(value);
80}
81
82template <>
83GLuint UniformStateQueryCast(GLint value)
84{
85 return clampCast<GLuint>(value);
86}
87
88// From-Boolean-to-Anything Casts
89template <>
90GLfloat UniformStateQueryCast(GLboolean value)
91{
92 return (value == GL_TRUE ? 1.0f : 0.0f);
93}
94
95template <>
96GLint UniformStateQueryCast(GLboolean value)
97{
98 return (value == GL_TRUE ? 1 : 0);
99}
100
101template <>
102GLuint UniformStateQueryCast(GLboolean value)
103{
104 return (value == GL_TRUE ? 1u : 0u);
105}
106
107// Default to static_cast
108template <typename DestT, typename SrcT>
109DestT UniformStateQueryCast(SrcT value)
110{
111 return static_cast<DestT>(value);
112}
113
114template <typename SrcT, typename DestT>
115void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
116{
117 for (int comp = 0; comp < components; ++comp)
118 {
119 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
120 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
121 size_t offset = comp * 4;
122 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
123 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
124 }
125}
126
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400127bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
128{
129 for (const LinkedUniform &uniform : list)
130 {
131 if (uniform.name == name)
132 return true;
133 }
134
135 return false;
136}
137
Jamie Madill62d31cb2015-09-11 13:25:51 -0400138} // anonymous namespace
139
Jamie Madill4a3c2342015-10-08 12:58:45 -0400140const char *const g_fakepath = "C:\\fakepath";
141
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400142InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000143{
144}
145
146InfoLog::~InfoLog()
147{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000148}
149
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400150size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000151{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400152 const std::string &logString = mStream.str();
153 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000154}
155
Geoff Lange1a27752015-10-05 13:16:04 -0400156void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000157{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400158 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000159
160 if (bufSize > 0)
161 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400162 const std::string str(mStream.str());
163
164 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000165 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400166 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
167 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000168 }
169
170 infoLog[index] = '\0';
171 }
172
173 if (length)
174 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400175 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000176 }
177}
178
179// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300180// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000181// messages, so lets remove all occurrences of this fake file path from the log.
182void InfoLog::appendSanitized(const char *message)
183{
184 std::string msg(message);
185
186 size_t found;
187 do
188 {
189 found = msg.find(g_fakepath);
190 if (found != std::string::npos)
191 {
192 msg.erase(found, strlen(g_fakepath));
193 }
194 }
195 while (found != std::string::npos);
196
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400197 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000198}
199
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000200void InfoLog::reset()
201{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000202}
203
Geoff Langd8605522016-04-13 10:19:12 -0400204VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000205{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500206}
207
Geoff Langd8605522016-04-13 10:19:12 -0400208VariableLocation::VariableLocation(const std::string &name,
209 unsigned int element,
210 unsigned int index)
211 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500212{
213}
214
Geoff Langd8605522016-04-13 10:19:12 -0400215void Program::Bindings::bindLocation(GLuint index, const std::string &name)
216{
217 mBindings[name] = index;
218}
219
220int Program::Bindings::getBinding(const std::string &name) const
221{
222 auto iter = mBindings.find(name);
223 return (iter != mBindings.end()) ? iter->second : -1;
224}
225
226Program::Bindings::const_iterator Program::Bindings::begin() const
227{
228 return mBindings.begin();
229}
230
231Program::Bindings::const_iterator Program::Bindings::end() const
232{
233 return mBindings.end();
234}
235
Jamie Madill48ef11b2016-04-27 15:21:52 -0400236ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500237 : mLabel(),
238 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400239 mAttachedVertexShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500240 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
241 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400242{
243}
244
Jamie Madill48ef11b2016-04-27 15:21:52 -0400245ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400246{
247 if (mAttachedVertexShader != nullptr)
248 {
249 mAttachedVertexShader->release();
250 }
251
252 if (mAttachedFragmentShader != nullptr)
253 {
254 mAttachedFragmentShader->release();
255 }
256}
257
Jamie Madill48ef11b2016-04-27 15:21:52 -0400258const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500259{
260 return mLabel;
261}
262
Jamie Madill48ef11b2016-04-27 15:21:52 -0400263const LinkedUniform *ProgramState::getUniformByName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400264{
265 for (const LinkedUniform &linkedUniform : mUniforms)
266 {
267 if (linkedUniform.name == name)
268 {
269 return &linkedUniform;
270 }
271 }
272
273 return nullptr;
274}
275
Jamie Madill48ef11b2016-04-27 15:21:52 -0400276GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400277{
278 size_t subscript = GL_INVALID_INDEX;
279 std::string baseName = gl::ParseUniformName(name, &subscript);
280
281 for (size_t location = 0; location < mUniformLocations.size(); ++location)
282 {
283 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400284 if (!uniformLocation.used)
285 {
286 continue;
287 }
288
289 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400290
291 if (uniform.name == baseName)
292 {
Geoff Langd8605522016-04-13 10:19:12 -0400293 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400294 {
Geoff Langd8605522016-04-13 10:19:12 -0400295 if (uniformLocation.element == subscript ||
296 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
297 {
298 return static_cast<GLint>(location);
299 }
300 }
301 else
302 {
303 if (subscript == GL_INVALID_INDEX)
304 {
305 return static_cast<GLint>(location);
306 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400307 }
308 }
309 }
310
311 return -1;
312}
313
Jamie Madill48ef11b2016-04-27 15:21:52 -0400314GLuint ProgramState::getUniformIndex(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400315{
316 size_t subscript = GL_INVALID_INDEX;
317 std::string baseName = gl::ParseUniformName(name, &subscript);
318
319 // The app is not allowed to specify array indices other than 0 for arrays of basic types
320 if (subscript != 0 && subscript != GL_INVALID_INDEX)
321 {
322 return GL_INVALID_INDEX;
323 }
324
325 for (size_t index = 0; index < mUniforms.size(); index++)
326 {
327 const LinkedUniform &uniform = mUniforms[index];
328 if (uniform.name == baseName)
329 {
330 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
331 {
332 return static_cast<GLuint>(index);
333 }
334 }
335 }
336
337 return GL_INVALID_INDEX;
338}
339
Jamie Madill7aea7e02016-05-10 10:39:45 -0400340Program::Program(rx::GLImplFactory *factory, ResourceManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400341 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400342 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500343 mLinked(false),
344 mDeleteStatus(false),
345 mRefCount(0),
346 mResourceManager(manager),
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400347 mHandle(handle),
348 mSamplerUniformRange(0, 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500349{
350 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000351
352 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500353 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354}
355
356Program::~Program()
357{
358 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000359
Geoff Lang7dd2e102014-11-10 15:19:26 -0500360 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361}
362
Geoff Lang70d0f492015-12-10 17:45:46 -0500363void Program::setLabel(const std::string &label)
364{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400365 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500366}
367
368const std::string &Program::getLabel() const
369{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400370 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500371}
372
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373bool Program::attachShader(Shader *shader)
374{
375 if (shader->getType() == GL_VERTEX_SHADER)
376 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400377 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000378 {
379 return false;
380 }
381
Jamie Madill48ef11b2016-04-27 15:21:52 -0400382 mState.mAttachedVertexShader = shader;
383 mState.mAttachedVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384 }
385 else if (shader->getType() == GL_FRAGMENT_SHADER)
386 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400387 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388 {
389 return false;
390 }
391
Jamie Madill48ef11b2016-04-27 15:21:52 -0400392 mState.mAttachedFragmentShader = shader;
393 mState.mAttachedFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000394 }
395 else UNREACHABLE();
396
397 return true;
398}
399
400bool Program::detachShader(Shader *shader)
401{
402 if (shader->getType() == GL_VERTEX_SHADER)
403 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400404 if (mState.mAttachedVertexShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000405 {
406 return false;
407 }
408
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400409 shader->release();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400410 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 }
412 else if (shader->getType() == GL_FRAGMENT_SHADER)
413 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400414 if (mState.mAttachedFragmentShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 {
416 return false;
417 }
418
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400419 shader->release();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400420 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421 }
422 else UNREACHABLE();
423
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424 return true;
425}
426
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000427int Program::getAttachedShadersCount() const
428{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400429 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000430}
431
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432void Program::bindAttributeLocation(GLuint index, const char *name)
433{
Geoff Langd8605522016-04-13 10:19:12 -0400434 mAttributeBindings.bindLocation(index, name);
435}
436
437void Program::bindUniformLocation(GLuint index, const char *name)
438{
439 // Bind the base uniform name only since array indices other than 0 cannot be bound
440 mUniformBindings.bindLocation(index, ParseUniformName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441}
442
Sami Väisänen46eaa942016-06-29 10:26:37 +0300443void Program::bindFragmentInputLocation(GLint index, const char *name)
444{
445 mFragmentInputBindings.bindLocation(index, name);
446}
447
448BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
449{
450 BindingInfo ret;
451 ret.type = GL_NONE;
452 ret.valid = false;
453
454 const Shader *fragmentShader = mState.getAttachedFragmentShader();
455 ASSERT(fragmentShader);
456
457 // Find the actual fragment shader varying we're interested in
458 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
459
460 for (const auto &binding : mFragmentInputBindings)
461 {
462 if (binding.second != static_cast<GLuint>(index))
463 continue;
464
465 ret.valid = true;
466
467 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400468 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300469
470 for (const auto &in : inputs)
471 {
472 if (in.name == originalName)
473 {
474 if (in.isArray())
475 {
476 // The client wants to bind either "name" or "name[0]".
477 // GL ES 3.1 spec refers to active array names with language such as:
478 // "if the string identifies the base name of an active array, where the
479 // string would exactly match the name of the variable if the suffix "[0]"
480 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400481 if (arrayIndex == GL_INVALID_INDEX)
482 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300483
Geoff Lang3f6a3982016-07-15 15:20:45 -0400484 ret.name = in.mappedName + "[" + std::to_string(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300485 }
486 else
487 {
488 ret.name = in.mappedName;
489 }
490 ret.type = in.type;
491 return ret;
492 }
493 }
494 }
495
496 return ret;
497}
498
499void Program::pathFragmentInputGen(GLint index,
500 GLenum genMode,
501 GLint components,
502 const GLfloat *coeffs)
503{
504 // If the location is -1 then the command is silently ignored
505 if (index == -1)
506 return;
507
508 const auto &binding = getFragmentInputBindingInfo(index);
509
510 // If the input doesn't exist then then the command is silently ignored
511 // This could happen through optimization for example, the shader translator
512 // decides that a variable is not actually being used and optimizes it away.
513 if (binding.name.empty())
514 return;
515
516 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
517}
518
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
520// compiling them into binaries, determining the attribute mappings, and collecting
521// a list of uniforms
Jamie Madill9082b982016-04-27 15:21:51 -0400522Error Program::link(const ContextState &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000523{
524 unlink(false);
525
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000526 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000527 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000528
Jamie Madill48ef11b2016-04-27 15:21:52 -0400529 if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500530 {
531 return Error(GL_NO_ERROR);
532 }
Jamie Madill48ef11b2016-04-27 15:21:52 -0400533 ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500534
Jamie Madill48ef11b2016-04-27 15:21:52 -0400535 if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500536 {
537 return Error(GL_NO_ERROR);
538 }
Jamie Madill48ef11b2016-04-27 15:21:52 -0400539 ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500540
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400541 if (mState.mAttachedFragmentShader->getShaderVersion() !=
542 mState.mAttachedVertexShader->getShaderVersion())
543 {
544 mInfoLog << "Fragment shader version does not match vertex shader version.";
545 return Error(GL_NO_ERROR);
546 }
547
Jamie Madill48ef11b2016-04-27 15:21:52 -0400548 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mState.mAttachedVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500549 {
550 return Error(GL_NO_ERROR);
551 }
552
Jamie Madill48ef11b2016-04-27 15:21:52 -0400553 if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
Jamie Madillada9ecc2015-08-17 12:53:37 -0400554 {
555 return Error(GL_NO_ERROR);
556 }
557
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700558 if (!linkUniforms(mInfoLog, data.getCaps(), mUniformBindings))
Jamie Madillea918db2015-08-18 14:48:59 -0400559 {
560 return Error(GL_NO_ERROR);
561 }
562
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700563 if (!linkUniformBlocks(mInfoLog, data.getCaps()))
Jamie Madille473dee2015-08-18 14:49:01 -0400564 {
565 return Error(GL_NO_ERROR);
566 }
567
Jamie Madillccdf74b2015-08-18 10:46:12 -0400568 const auto &mergedVaryings = getMergedVaryings();
569
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700570 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, data.getCaps()))
Jamie Madillccdf74b2015-08-18 10:46:12 -0400571 {
572 return Error(GL_NO_ERROR);
573 }
574
Jamie Madill80a6fc02015-08-21 16:53:16 -0400575 linkOutputVariables();
576
Jamie Madillf5f4ad22015-09-02 18:32:38 +0000577 rx::LinkResult result = mProgram->link(data, mInfoLog);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500578 if (result.error.isError() || !result.linkSuccess)
579 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500580 return result.error;
581 }
582
Jamie Madillccdf74b2015-08-18 10:46:12 -0400583 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill4a3c2342015-10-08 12:58:45 -0400584 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400585
Geoff Lang7dd2e102014-11-10 15:19:26 -0500586 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400587 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000588}
589
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000590// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000591void Program::unlink(bool destroy)
592{
593 if (destroy) // Object being destructed
594 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400595 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400597 mState.mAttachedFragmentShader->release();
598 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 }
600
Jamie Madill48ef11b2016-04-27 15:21:52 -0400601 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000602 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400603 mState.mAttachedVertexShader->release();
604 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606 }
607
Jamie Madill48ef11b2016-04-27 15:21:52 -0400608 mState.mAttributes.clear();
609 mState.mActiveAttribLocationsMask.reset();
610 mState.mTransformFeedbackVaryingVars.clear();
611 mState.mUniforms.clear();
612 mState.mUniformLocations.clear();
613 mState.mUniformBlocks.clear();
614 mState.mOutputVariables.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500615
Geoff Lang7dd2e102014-11-10 15:19:26 -0500616 mValidated = false;
617
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000618 mLinked = false;
619}
620
Geoff Lange1a27752015-10-05 13:16:04 -0400621bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000622{
623 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624}
625
Geoff Lang7dd2e102014-11-10 15:19:26 -0500626Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000627{
628 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000629
Geoff Lang7dd2e102014-11-10 15:19:26 -0500630#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
631 return Error(GL_NO_ERROR);
632#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400633 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
634 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000635 {
Jamie Madillf6113162015-05-07 11:49:21 -0400636 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500637 return Error(GL_NO_ERROR);
638 }
639
Geoff Langc46cc2f2015-10-01 17:16:20 -0400640 BinaryInputStream stream(binary, length);
641
Geoff Lang7dd2e102014-11-10 15:19:26 -0500642 int majorVersion = stream.readInt<int>();
643 int minorVersion = stream.readInt<int>();
644 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
645 {
Jamie Madillf6113162015-05-07 11:49:21 -0400646 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500647 return Error(GL_NO_ERROR);
648 }
649
650 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
651 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
652 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
653 {
Jamie Madillf6113162015-05-07 11:49:21 -0400654 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500655 return Error(GL_NO_ERROR);
656 }
657
Jamie Madill63805b42015-08-25 13:17:39 -0400658 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
659 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400660 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500661
Jamie Madill3da79b72015-04-27 11:09:17 -0400662 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400663 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400664 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
665 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400666 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400667 LoadShaderVar(&stream, &attrib);
668 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400669 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400670 }
671
Jamie Madill62d31cb2015-09-11 13:25:51 -0400672 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400673 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400674 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
675 {
676 LinkedUniform uniform;
677 LoadShaderVar(&stream, &uniform);
678
679 uniform.blockIndex = stream.readInt<int>();
680 uniform.blockInfo.offset = stream.readInt<int>();
681 uniform.blockInfo.arrayStride = stream.readInt<int>();
682 uniform.blockInfo.matrixStride = stream.readInt<int>();
683 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
684
Jamie Madill48ef11b2016-04-27 15:21:52 -0400685 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400686 }
687
688 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400689 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400690 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
691 uniformIndexIndex++)
692 {
693 VariableLocation variable;
694 stream.readString(&variable.name);
695 stream.readInt(&variable.element);
696 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400697 stream.readBool(&variable.used);
698 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400699
Jamie Madill48ef11b2016-04-27 15:21:52 -0400700 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400701 }
702
703 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400704 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400705 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
706 ++uniformBlockIndex)
707 {
708 UniformBlock uniformBlock;
709 stream.readString(&uniformBlock.name);
710 stream.readBool(&uniformBlock.isArray);
711 stream.readInt(&uniformBlock.arrayElement);
712 stream.readInt(&uniformBlock.dataSize);
713 stream.readBool(&uniformBlock.vertexStaticUse);
714 stream.readBool(&uniformBlock.fragmentStaticUse);
715
716 unsigned int numMembers = stream.readInt<unsigned int>();
717 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
718 {
719 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
720 }
721
Jamie Madill48ef11b2016-04-27 15:21:52 -0400722 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400723 }
724
Brandon Jones1048ea72015-10-06 15:34:52 -0700725 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400726 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700727 for (unsigned int transformFeedbackVaryingIndex = 0;
728 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
729 ++transformFeedbackVaryingIndex)
730 {
731 sh::Varying varying;
732 stream.readInt(&varying.arraySize);
733 stream.readInt(&varying.type);
734 stream.readString(&varying.name);
735
Jamie Madill48ef11b2016-04-27 15:21:52 -0400736 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700737 }
738
Jamie Madill48ef11b2016-04-27 15:21:52 -0400739 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400740
Jamie Madill80a6fc02015-08-21 16:53:16 -0400741 unsigned int outputVarCount = stream.readInt<unsigned int>();
742 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
743 {
744 int locationIndex = stream.readInt<int>();
745 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400746 stream.readInt(&locationData.element);
747 stream.readInt(&locationData.index);
748 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400749 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400750 }
751
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400752 stream.readInt(&mSamplerUniformRange.start);
753 stream.readInt(&mSamplerUniformRange.end);
754
Geoff Lang7dd2e102014-11-10 15:19:26 -0500755 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
756 if (result.error.isError() || !result.linkSuccess)
757 {
Geoff Langb543aff2014-09-30 14:52:54 -0400758 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000759 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000760
Geoff Lang7dd2e102014-11-10 15:19:26 -0500761 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400762 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500763#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
764}
765
766Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
767{
768 if (binaryFormat)
769 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400770 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500771 }
772
773 BinaryOutputStream stream;
774
Geoff Lang7dd2e102014-11-10 15:19:26 -0500775 stream.writeInt(ANGLE_MAJOR_VERSION);
776 stream.writeInt(ANGLE_MINOR_VERSION);
777 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
778
Jamie Madill48ef11b2016-04-27 15:21:52 -0400779 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500780
Jamie Madill48ef11b2016-04-27 15:21:52 -0400781 stream.writeInt(mState.mAttributes.size());
782 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400783 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400784 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400785 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400786 }
787
Jamie Madill48ef11b2016-04-27 15:21:52 -0400788 stream.writeInt(mState.mUniforms.size());
789 for (const gl::LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400790 {
791 WriteShaderVar(&stream, uniform);
792
793 // FIXME: referenced
794
795 stream.writeInt(uniform.blockIndex);
796 stream.writeInt(uniform.blockInfo.offset);
797 stream.writeInt(uniform.blockInfo.arrayStride);
798 stream.writeInt(uniform.blockInfo.matrixStride);
799 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
800 }
801
Jamie Madill48ef11b2016-04-27 15:21:52 -0400802 stream.writeInt(mState.mUniformLocations.size());
803 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400804 {
805 stream.writeString(variable.name);
806 stream.writeInt(variable.element);
807 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400808 stream.writeInt(variable.used);
809 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400810 }
811
Jamie Madill48ef11b2016-04-27 15:21:52 -0400812 stream.writeInt(mState.mUniformBlocks.size());
813 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400814 {
815 stream.writeString(uniformBlock.name);
816 stream.writeInt(uniformBlock.isArray);
817 stream.writeInt(uniformBlock.arrayElement);
818 stream.writeInt(uniformBlock.dataSize);
819
820 stream.writeInt(uniformBlock.vertexStaticUse);
821 stream.writeInt(uniformBlock.fragmentStaticUse);
822
823 stream.writeInt(uniformBlock.memberUniformIndexes.size());
824 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
825 {
826 stream.writeInt(memberUniformIndex);
827 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400828 }
829
Jamie Madill48ef11b2016-04-27 15:21:52 -0400830 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
831 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700832 {
833 stream.writeInt(varying.arraySize);
834 stream.writeInt(varying.type);
835 stream.writeString(varying.name);
836 }
837
Jamie Madill48ef11b2016-04-27 15:21:52 -0400838 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400839
Jamie Madill48ef11b2016-04-27 15:21:52 -0400840 stream.writeInt(mState.mOutputVariables.size());
841 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -0400842 {
843 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -0400844 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400845 stream.writeInt(outputPair.second.index);
846 stream.writeString(outputPair.second.name);
847 }
848
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400849 stream.writeInt(mSamplerUniformRange.start);
850 stream.writeInt(mSamplerUniformRange.end);
851
Geoff Lang7dd2e102014-11-10 15:19:26 -0500852 gl::Error error = mProgram->save(&stream);
853 if (error.isError())
854 {
855 return error;
856 }
857
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700858 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -0400859 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500860
861 if (streamLength > bufSize)
862 {
863 if (length)
864 {
865 *length = 0;
866 }
867
868 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
869 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
870 // sizes and then copy it.
871 return Error(GL_INVALID_OPERATION);
872 }
873
874 if (binary)
875 {
876 char *ptr = reinterpret_cast<char*>(binary);
877
Jamie Madill48ef11b2016-04-27 15:21:52 -0400878 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500879 ptr += streamLength;
880
881 ASSERT(ptr - streamLength == binary);
882 }
883
884 if (length)
885 {
886 *length = streamLength;
887 }
888
889 return Error(GL_NO_ERROR);
890}
891
892GLint Program::getBinaryLength() const
893{
894 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400895 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500896 if (error.isError())
897 {
898 return 0;
899 }
900
901 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000902}
903
Geoff Langc5629752015-12-07 16:29:04 -0500904void Program::setBinaryRetrievableHint(bool retrievable)
905{
906 // TODO(jmadill) : replace with dirty bits
907 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400908 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -0500909}
910
911bool Program::getBinaryRetrievableHint() const
912{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400913 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -0500914}
915
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000916void Program::release()
917{
918 mRefCount--;
919
920 if (mRefCount == 0 && mDeleteStatus)
921 {
922 mResourceManager->deleteProgram(mHandle);
923 }
924}
925
926void Program::addRef()
927{
928 mRefCount++;
929}
930
931unsigned int Program::getRefCount() const
932{
933 return mRefCount;
934}
935
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000936int Program::getInfoLogLength() const
937{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400938 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000939}
940
Geoff Lange1a27752015-10-05 13:16:04 -0400941void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000942{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000943 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000944}
945
Geoff Lange1a27752015-10-05 13:16:04 -0400946void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000947{
948 int total = 0;
949
Jamie Madill48ef11b2016-04-27 15:21:52 -0400950 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000951 {
952 if (total < maxCount)
953 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400954 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200955 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000956 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000957 }
958
Jamie Madill48ef11b2016-04-27 15:21:52 -0400959 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000960 {
961 if (total < maxCount)
962 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400963 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200964 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000965 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000966 }
967
968 if (count)
969 {
970 *count = total;
971 }
972}
973
Geoff Lange1a27752015-10-05 13:16:04 -0400974GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500975{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400976 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500977 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400978 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500979 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400980 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500981 }
982 }
983
Austin Kinrossb8af7232015-03-16 22:33:25 -0700984 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500985}
986
Jamie Madill63805b42015-08-25 13:17:39 -0400987bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400988{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400989 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
990 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500991}
992
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000993void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
994{
Jamie Madillc349ec02015-08-21 16:53:12 -0400995 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000996 {
997 if (bufsize > 0)
998 {
999 name[0] = '\0';
1000 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001002 if (length)
1003 {
1004 *length = 0;
1005 }
1006
1007 *type = GL_NONE;
1008 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001009 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001010 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001011
1012 size_t attributeIndex = 0;
1013
Jamie Madill48ef11b2016-04-27 15:21:52 -04001014 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001015 {
1016 // Skip over inactive attributes
1017 if (attribute.staticUse)
1018 {
1019 if (static_cast<size_t>(index) == attributeIndex)
1020 {
1021 break;
1022 }
1023 attributeIndex++;
1024 }
1025 }
1026
Jamie Madill48ef11b2016-04-27 15:21:52 -04001027 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
1028 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -04001029
1030 if (bufsize > 0)
1031 {
1032 const char *string = attrib.name.c_str();
1033
1034 strncpy(name, string, bufsize);
1035 name[bufsize - 1] = '\0';
1036
1037 if (length)
1038 {
1039 *length = static_cast<GLsizei>(strlen(name));
1040 }
1041 }
1042
1043 // Always a single 'type' instance
1044 *size = 1;
1045 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001046}
1047
Geoff Lange1a27752015-10-05 13:16:04 -04001048GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001049{
Jamie Madillc349ec02015-08-21 16:53:12 -04001050 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001051 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001052 return 0;
1053 }
1054
1055 GLint count = 0;
1056
Jamie Madill48ef11b2016-04-27 15:21:52 -04001057 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001058 {
1059 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001060 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061
1062 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001063}
1064
Geoff Lange1a27752015-10-05 13:16:04 -04001065GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001066{
Jamie Madillc349ec02015-08-21 16:53:12 -04001067 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001068 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001069 return 0;
1070 }
1071
1072 size_t maxLength = 0;
1073
Jamie Madill48ef11b2016-04-27 15:21:52 -04001074 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001075 {
1076 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001077 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001078 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001079 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001080 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001081
Jamie Madillc349ec02015-08-21 16:53:12 -04001082 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001083}
1084
Geoff Lang7dd2e102014-11-10 15:19:26 -05001085GLint Program::getFragDataLocation(const std::string &name) const
1086{
1087 std::string baseName(name);
1088 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001089 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001090 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001091 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001092 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1093 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001094 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001095 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001096 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001097 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001098}
1099
Geoff Lange1a27752015-10-05 13:16:04 -04001100void Program::getActiveUniform(GLuint index,
1101 GLsizei bufsize,
1102 GLsizei *length,
1103 GLint *size,
1104 GLenum *type,
1105 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001106{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001107 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001108 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001109 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001110 ASSERT(index < mState.mUniforms.size());
1111 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001112
1113 if (bufsize > 0)
1114 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001115 std::string string = uniform.name;
1116 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001117 {
1118 string += "[0]";
1119 }
1120
1121 strncpy(name, string.c_str(), bufsize);
1122 name[bufsize - 1] = '\0';
1123
1124 if (length)
1125 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001126 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001127 }
1128 }
1129
Jamie Madill62d31cb2015-09-11 13:25:51 -04001130 *size = uniform.elementCount();
1131 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001132 }
1133 else
1134 {
1135 if (bufsize > 0)
1136 {
1137 name[0] = '\0';
1138 }
1139
1140 if (length)
1141 {
1142 *length = 0;
1143 }
1144
1145 *size = 0;
1146 *type = GL_NONE;
1147 }
1148}
1149
Geoff Lange1a27752015-10-05 13:16:04 -04001150GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001151{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001152 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001153 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001154 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001155 }
1156 else
1157 {
1158 return 0;
1159 }
1160}
1161
Geoff Lange1a27752015-10-05 13:16:04 -04001162GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001163{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001164 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001165
1166 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001167 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001168 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001169 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001170 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001171 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001172 size_t length = uniform.name.length() + 1u;
1173 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001174 {
1175 length += 3; // Counting in "[0]".
1176 }
1177 maxLength = std::max(length, maxLength);
1178 }
1179 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001180 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001181
Jamie Madill62d31cb2015-09-11 13:25:51 -04001182 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001183}
1184
1185GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1186{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001187 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
1188 const gl::LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001189 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001190 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001191 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1192 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1193 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1194 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1195 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1196 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1197 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1198 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1199 default:
1200 UNREACHABLE();
1201 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001202 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001203 return 0;
1204}
1205
1206bool Program::isValidUniformLocation(GLint location) const
1207{
Jamie Madille2e406c2016-06-02 13:04:10 -04001208 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001209 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1210 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001211}
1212
1213bool Program::isIgnoredUniformLocation(GLint location) const
1214{
1215 // Location is ignored if it is -1 or it was bound but non-existant in the shader or optimized
1216 // out
1217 return location == -1 ||
Jamie Madill48ef11b2016-04-27 15:21:52 -04001218 (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1219 mState.mUniformLocations[static_cast<size_t>(location)].ignored);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001220}
1221
Jamie Madill62d31cb2015-09-11 13:25:51 -04001222const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001223{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001224 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1225 return mState.mUniforms[mState.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001226}
1227
Jamie Madill62d31cb2015-09-11 13:25:51 -04001228GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001229{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001230 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001231}
1232
Jamie Madill62d31cb2015-09-11 13:25:51 -04001233GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001234{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001235 return mState.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236}
1237
1238void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1239{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001240 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001241 mProgram->setUniform1fv(location, count, v);
1242}
1243
1244void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1245{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001246 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001247 mProgram->setUniform2fv(location, count, v);
1248}
1249
1250void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1251{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001252 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001253 mProgram->setUniform3fv(location, count, v);
1254}
1255
1256void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1257{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001258 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001259 mProgram->setUniform4fv(location, count, v);
1260}
1261
1262void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1263{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001264 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001265 mProgram->setUniform1iv(location, count, v);
1266}
1267
1268void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1269{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001270 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001271 mProgram->setUniform2iv(location, count, v);
1272}
1273
1274void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1275{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001276 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001277 mProgram->setUniform3iv(location, count, v);
1278}
1279
1280void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1281{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001282 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001283 mProgram->setUniform4iv(location, count, v);
1284}
1285
1286void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1287{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001288 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289 mProgram->setUniform1uiv(location, count, v);
1290}
1291
1292void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1293{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001294 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001295 mProgram->setUniform2uiv(location, count, v);
1296}
1297
1298void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1299{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001300 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001301 mProgram->setUniform3uiv(location, count, v);
1302}
1303
1304void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1305{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001306 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001307 mProgram->setUniform4uiv(location, count, v);
1308}
1309
1310void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1311{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001312 setMatrixUniformInternal<2, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001313 mProgram->setUniformMatrix2fv(location, count, transpose, v);
1314}
1315
1316void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1317{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001318 setMatrixUniformInternal<3, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001319 mProgram->setUniformMatrix3fv(location, count, transpose, v);
1320}
1321
1322void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1323{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001324 setMatrixUniformInternal<4, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001325 mProgram->setUniformMatrix4fv(location, count, transpose, v);
1326}
1327
1328void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1329{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001330 setMatrixUniformInternal<2, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001331 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
1332}
1333
1334void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1335{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001336 setMatrixUniformInternal<2, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001337 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
1338}
1339
1340void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1341{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001342 setMatrixUniformInternal<3, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001343 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
1344}
1345
1346void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1347{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001348 setMatrixUniformInternal<3, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001349 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
1350}
1351
1352void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1353{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001354 setMatrixUniformInternal<4, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001355 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
1356}
1357
1358void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1359{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001360 setMatrixUniformInternal<4, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001361 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
1362}
1363
Geoff Lange1a27752015-10-05 13:16:04 -04001364void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001365{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001366 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001367}
1368
Geoff Lange1a27752015-10-05 13:16:04 -04001369void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001370{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001371 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001372}
1373
Geoff Lange1a27752015-10-05 13:16:04 -04001374void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001375{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001376 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001377}
1378
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001379void Program::flagForDeletion()
1380{
1381 mDeleteStatus = true;
1382}
1383
1384bool Program::isFlaggedForDeletion() const
1385{
1386 return mDeleteStatus;
1387}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001388
Brandon Jones43a53e22014-08-28 16:23:22 -07001389void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001390{
1391 mInfoLog.reset();
1392
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001394 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001395 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001396 }
1397 else
1398 {
Jamie Madillf6113162015-05-07 11:49:21 -04001399 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001400 }
1401}
1402
Geoff Lang7dd2e102014-11-10 15:19:26 -05001403bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1404{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001405 // Skip cache if we're using an infolog, so we get the full error.
1406 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1407 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1408 {
1409 return mCachedValidateSamplersResult.value();
1410 }
1411
1412 if (mTextureUnitTypesCache.empty())
1413 {
1414 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1415 }
1416 else
1417 {
1418 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1419 }
1420
1421 // if any two active samplers in a program are of different types, but refer to the same
1422 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1423 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1424 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1425 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1426 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001427 const LinkedUniform &uniform = mState.mUniforms[samplerIndex];
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001428 ASSERT(uniform.isSampler());
1429
1430 if (!uniform.staticUse)
1431 continue;
1432
1433 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1434 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1435
1436 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1437 {
1438 GLuint textureUnit = dataPtr[arrayElement];
1439
1440 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1441 {
1442 if (infoLog)
1443 {
1444 (*infoLog) << "Sampler uniform (" << textureUnit
1445 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1446 << caps.maxCombinedTextureImageUnits << ")";
1447 }
1448
1449 mCachedValidateSamplersResult = false;
1450 return false;
1451 }
1452
1453 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1454 {
1455 if (textureType != mTextureUnitTypesCache[textureUnit])
1456 {
1457 if (infoLog)
1458 {
1459 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1460 "image unit ("
1461 << textureUnit << ").";
1462 }
1463
1464 mCachedValidateSamplersResult = false;
1465 return false;
1466 }
1467 }
1468 else
1469 {
1470 mTextureUnitTypesCache[textureUnit] = textureType;
1471 }
1472 }
1473 }
1474
1475 mCachedValidateSamplersResult = true;
1476 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001477}
1478
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001479bool Program::isValidated() const
1480{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481 return mValidated;
1482}
1483
Geoff Lange1a27752015-10-05 13:16:04 -04001484GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001486 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001487}
1488
1489void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1490{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001491 ASSERT(
1492 uniformBlockIndex <
1493 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494
Jamie Madill48ef11b2016-04-27 15:21:52 -04001495 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001496
1497 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001498 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001499 std::string string = uniformBlock.name;
1500
Jamie Madill62d31cb2015-09-11 13:25:51 -04001501 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001502 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001503 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504 }
1505
1506 strncpy(uniformBlockName, string.c_str(), bufSize);
1507 uniformBlockName[bufSize - 1] = '\0';
1508
1509 if (length)
1510 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001511 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001512 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001513 }
1514}
1515
Geoff Lang7dd2e102014-11-10 15:19:26 -05001516void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001517{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001518 ASSERT(
1519 uniformBlockIndex <
1520 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521
Jamie Madill48ef11b2016-04-27 15:21:52 -04001522 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523
1524 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001525 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001526 case GL_UNIFORM_BLOCK_DATA_SIZE:
1527 *params = static_cast<GLint>(uniformBlock.dataSize);
1528 break;
1529 case GL_UNIFORM_BLOCK_NAME_LENGTH:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001530 *params =
1531 static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001532 break;
1533 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1534 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1535 break;
1536 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1537 {
1538 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1539 {
1540 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1541 }
1542 }
1543 break;
1544 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001545 *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001546 break;
1547 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001548 *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001549 break;
1550 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001551 }
1552}
1553
Geoff Lange1a27752015-10-05 13:16:04 -04001554GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001555{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001556 int maxLength = 0;
1557
1558 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001559 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001560 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1562 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001563 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564 if (!uniformBlock.name.empty())
1565 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001566 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001567
1568 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001569 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570
1571 maxLength = std::max(length + arrayLength, maxLength);
1572 }
1573 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001574 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001575
1576 return maxLength;
1577}
1578
Geoff Lange1a27752015-10-05 13:16:04 -04001579GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001580{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001581 size_t subscript = GL_INVALID_INDEX;
1582 std::string baseName = gl::ParseUniformName(name, &subscript);
1583
Jamie Madill48ef11b2016-04-27 15:21:52 -04001584 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001585 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1586 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001587 const gl::UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001588 if (uniformBlock.name == baseName)
1589 {
1590 const bool arrayElementZero =
1591 (subscript == GL_INVALID_INDEX &&
1592 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1593 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1594 {
1595 return blockIndex;
1596 }
1597 }
1598 }
1599
1600 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001601}
1602
Jamie Madill62d31cb2015-09-11 13:25:51 -04001603const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001604{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001605 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1606 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001607}
1608
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001609void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1610{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001611 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Geoff Lang5d124a62015-09-15 13:03:27 -04001612 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001613}
1614
1615GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1616{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001617 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001618}
1619
1620void Program::resetUniformBlockBindings()
1621{
1622 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1623 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001624 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001625 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001626 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001627}
1628
Geoff Lang48dcae72014-02-05 16:28:24 -05001629void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1630{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001631 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001632 for (GLsizei i = 0; i < count; i++)
1633 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001634 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001635 }
1636
Jamie Madill48ef11b2016-04-27 15:21:52 -04001637 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001638}
1639
1640void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1641{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001642 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001643 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001644 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1645 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001646 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1647 if (length)
1648 {
1649 *length = lastNameIdx;
1650 }
1651 if (size)
1652 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001653 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001654 }
1655 if (type)
1656 {
1657 *type = varying.type;
1658 }
1659 if (name)
1660 {
1661 memcpy(name, varying.name.c_str(), lastNameIdx);
1662 name[lastNameIdx] = '\0';
1663 }
1664 }
1665}
1666
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001667GLsizei Program::getTransformFeedbackVaryingCount() const
1668{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001669 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001670 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001671 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001672 }
1673 else
1674 {
1675 return 0;
1676 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001677}
1678
1679GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1680{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001681 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001682 {
1683 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001684 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001685 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001686 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1687 }
1688
1689 return maxSize;
1690 }
1691 else
1692 {
1693 return 0;
1694 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001695}
1696
1697GLenum Program::getTransformFeedbackBufferMode() const
1698{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001699 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001700}
1701
Jamie Madillada9ecc2015-08-17 12:53:37 -04001702bool Program::linkVaryings(InfoLog &infoLog,
1703 const Shader *vertexShader,
Sami Väisänen46eaa942016-06-29 10:26:37 +03001704 const Shader *fragmentShader) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001705{
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001706 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1707
Jamie Madill4cff2472015-08-21 16:53:18 -04001708 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1709 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001710
Sami Väisänen46eaa942016-06-29 10:26:37 +03001711 std::map<GLuint, std::string> staticFragmentInputLocations;
1712
Jamie Madill4cff2472015-08-21 16:53:18 -04001713 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001714 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715 bool matched = false;
1716
1717 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001718 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001719 {
1720 continue;
1721 }
1722
Jamie Madill4cff2472015-08-21 16:53:18 -04001723 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001724 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001725 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001726 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001727 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001728 if (!linkValidateVaryings(infoLog, output.name, input, output,
1729 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001730 {
1731 return false;
1732 }
1733
Geoff Lang7dd2e102014-11-10 15:19:26 -05001734 matched = true;
1735 break;
1736 }
1737 }
1738
1739 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001740 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001741 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001742 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001743 return false;
1744 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001745
1746 // Check for aliased path rendering input bindings (if any).
1747 // If more than one binding refer statically to the same
1748 // location the link must fail.
1749
1750 if (!output.staticUse)
1751 continue;
1752
1753 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1754 if (inputBinding == -1)
1755 continue;
1756
1757 const auto it = staticFragmentInputLocations.find(inputBinding);
1758 if (it == std::end(staticFragmentInputLocations))
1759 {
1760 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1761 }
1762 else
1763 {
1764 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1765 << it->second;
1766 return false;
1767 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001768 }
1769
Jamie Madillada9ecc2015-08-17 12:53:37 -04001770 // TODO(jmadill): verify no unmatched vertex varyings?
1771
Geoff Lang7dd2e102014-11-10 15:19:26 -05001772 return true;
1773}
1774
Geoff Langd8605522016-04-13 10:19:12 -04001775bool Program::linkUniforms(gl::InfoLog &infoLog,
1776 const gl::Caps &caps,
1777 const Bindings &uniformBindings)
Jamie Madillea918db2015-08-18 14:48:59 -04001778{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001779 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1780 const std::vector<sh::Uniform> &fragmentUniforms =
1781 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001782
1783 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill62d31cb2015-09-11 13:25:51 -04001784 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madillea918db2015-08-18 14:48:59 -04001785
1786 for (const sh::Uniform &vertexUniform : vertexUniforms)
1787 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001788 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001789 }
1790
1791 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1792 {
1793 auto entry = linkedUniforms.find(fragmentUniform.name);
1794 if (entry != linkedUniforms.end())
1795 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001796 LinkedUniform *vertexUniform = &entry->second;
1797 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1798 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001799 {
1800 return false;
1801 }
1802 }
1803 }
1804
Jamie Madill62d31cb2015-09-11 13:25:51 -04001805 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1806 // Also check the maximum uniform vector and sampler counts.
1807 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1808 {
1809 return false;
1810 }
1811
Geoff Langd8605522016-04-13 10:19:12 -04001812 if (!indexUniforms(infoLog, caps, uniformBindings))
1813 {
1814 return false;
1815 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001816
Jamie Madillea918db2015-08-18 14:48:59 -04001817 return true;
1818}
1819
Geoff Langd8605522016-04-13 10:19:12 -04001820bool Program::indexUniforms(gl::InfoLog &infoLog,
1821 const gl::Caps &caps,
1822 const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001823{
Geoff Langd8605522016-04-13 10:19:12 -04001824 // Uniforms awaiting a location
1825 std::vector<VariableLocation> unboundUniforms;
1826 std::map<GLuint, VariableLocation> boundUniforms;
1827 int maxUniformLocation = -1;
1828
1829 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001830 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001831 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001832 const gl::LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001833
Geoff Langd8605522016-04-13 10:19:12 -04001834 if (uniform.isBuiltIn())
1835 {
1836 continue;
1837 }
1838
1839 int bindingLocation = uniformBindings.getBinding(uniform.name);
1840
1841 // Verify that this location isn't bound twice
1842 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1843 {
1844 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1845 return false;
1846 }
1847
Jamie Madill62d31cb2015-09-11 13:25:51 -04001848 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1849 {
Geoff Langd8605522016-04-13 10:19:12 -04001850 VariableLocation location(uniform.name, arrayIndex,
1851 static_cast<unsigned int>(uniformIndex));
1852
1853 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001854 {
Geoff Langd8605522016-04-13 10:19:12 -04001855 boundUniforms[bindingLocation] = location;
1856 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1857 }
1858 else
1859 {
1860 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001861 }
1862 }
1863 }
Geoff Langd8605522016-04-13 10:19:12 -04001864
1865 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1866 // not be assigned to those locations.
1867 std::set<GLuint> reservedLocations;
1868 for (const auto &binding : uniformBindings)
1869 {
1870 GLuint location = binding.second;
1871 if (boundUniforms.find(location) == boundUniforms.end())
1872 {
1873 reservedLocations.insert(location);
1874 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1875 }
1876 }
1877
1878 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04001879 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04001880 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
1881 static_cast<size_t>(maxUniformLocation + 1)));
1882
1883 // Assign bound uniforms
1884 for (const auto &boundUniform : boundUniforms)
1885 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001886 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04001887 }
1888
1889 // Assign reserved uniforms
1890 for (const auto &reservedLocation : reservedLocations)
1891 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001892 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04001893 }
1894
1895 // Assign unbound uniforms
1896 size_t nextUniformLocation = 0;
1897 for (const auto &unboundUniform : unboundUniforms)
1898 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001899 while (mState.mUniformLocations[nextUniformLocation].used ||
1900 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04001901 {
1902 nextUniformLocation++;
1903 }
1904
Jamie Madill48ef11b2016-04-27 15:21:52 -04001905 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
1906 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04001907 nextUniformLocation++;
1908 }
1909
1910 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04001911}
1912
Geoff Lang7dd2e102014-11-10 15:19:26 -05001913bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1914{
Jamie Madillc4c744222015-11-04 09:39:47 -05001915 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1916 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001917 {
1918 return false;
1919 }
1920
1921 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1922 {
Jamie Madillf6113162015-05-07 11:49:21 -04001923 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924 return false;
1925 }
1926
1927 return true;
1928}
1929
1930// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill9082b982016-04-27 15:21:51 -04001931bool Program::linkAttributes(const ContextState &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001932 InfoLog &infoLog,
Geoff Langd8605522016-04-13 10:19:12 -04001933 const Bindings &attributeBindings,
Jamie Madill3da79b72015-04-27 11:09:17 -04001934 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001935{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001936 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001937 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001938 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04001939
1940 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001941 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001942 {
Jamie Madillf6113162015-05-07 11:49:21 -04001943 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001944 return false;
1945 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001946
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001947 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001948
Jamie Madillc349ec02015-08-21 16:53:12 -04001949 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001950 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001951 {
1952 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05001953 ASSERT(attribute.staticUse);
1954
Geoff Langd8605522016-04-13 10:19:12 -04001955 int bindingLocation = attributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04001956 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04001957 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001958 attribute.location = bindingLocation;
1959 }
1960
1961 if (attribute.location != -1)
1962 {
1963 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04001964 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001965
Jamie Madill63805b42015-08-25 13:17:39 -04001966 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001967 {
Jamie Madillf6113162015-05-07 11:49:21 -04001968 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04001969 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001970
1971 return false;
1972 }
1973
Jamie Madill63805b42015-08-25 13:17:39 -04001974 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001975 {
Jamie Madill63805b42015-08-25 13:17:39 -04001976 const int regLocation = attribute.location + reg;
1977 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001978
1979 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001980 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04001981 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001982 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001983 // TODO(jmadill): fix aliasing on ES2
1984 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001985 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001986 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04001987 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001988 return false;
1989 }
1990 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001991 else
1992 {
Jamie Madill63805b42015-08-25 13:17:39 -04001993 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04001994 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001995
Jamie Madill63805b42015-08-25 13:17:39 -04001996 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001997 }
1998 }
1999 }
2000
2001 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002002 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002003 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002004 ASSERT(attribute.staticUse);
2005
Jamie Madillc349ec02015-08-21 16:53:12 -04002006 // Not set by glBindAttribLocation or by location layout qualifier
2007 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002008 {
Jamie Madill63805b42015-08-25 13:17:39 -04002009 int regs = VariableRegisterCount(attribute.type);
2010 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002011
Jamie Madill63805b42015-08-25 13:17:39 -04002012 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002013 {
Jamie Madillf6113162015-05-07 11:49:21 -04002014 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002015 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002016 }
2017
Jamie Madillc349ec02015-08-21 16:53:12 -04002018 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002019 }
2020 }
2021
Jamie Madill48ef11b2016-04-27 15:21:52 -04002022 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002023 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002024 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04002025 ASSERT(attribute.location != -1);
2026 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002027
Jamie Madill63805b42015-08-25 13:17:39 -04002028 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002029 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002030 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002031 }
2032 }
2033
Geoff Lang7dd2e102014-11-10 15:19:26 -05002034 return true;
2035}
2036
Jamie Madille473dee2015-08-18 14:49:01 -04002037bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002038{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002039 const Shader &vertexShader = *mState.mAttachedVertexShader;
2040 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
Jamie Madille473dee2015-08-18 14:49:01 -04002041
Geoff Lang7dd2e102014-11-10 15:19:26 -05002042 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2043 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madille473dee2015-08-18 14:49:01 -04002044
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045 // Check that interface blocks defined in the vertex and fragment shaders are identical
2046 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2047 UniformBlockMap linkedUniformBlocks;
Jamie Madille473dee2015-08-18 14:49:01 -04002048
2049 GLuint vertexBlockCount = 0;
2050 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002051 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002052 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jamie Madille473dee2015-08-18 14:49:01 -04002053
2054 // Note: shared and std140 layouts are always considered active
2055 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2056 {
2057 if (++vertexBlockCount > caps.maxVertexUniformBlocks)
2058 {
2059 infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
2060 << caps.maxVertexUniformBlocks << ")";
2061 return false;
2062 }
2063 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064 }
Jamie Madille473dee2015-08-18 14:49:01 -04002065
2066 GLuint fragmentBlockCount = 0;
2067 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002068 {
Jamie Madille473dee2015-08-18 14:49:01 -04002069 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002070 if (entry != linkedUniformBlocks.end())
2071 {
2072 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2073 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2074 {
2075 return false;
2076 }
2077 }
Jamie Madille473dee2015-08-18 14:49:01 -04002078
Geoff Lang7dd2e102014-11-10 15:19:26 -05002079 // Note: shared and std140 layouts are always considered active
Jamie Madille473dee2015-08-18 14:49:01 -04002080 if (fragmentInterfaceBlock.staticUse ||
2081 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002082 {
Jamie Madille473dee2015-08-18 14:49:01 -04002083 if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002084 {
Jamie Madille473dee2015-08-18 14:49:01 -04002085 infoLog
2086 << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
2087 << caps.maxFragmentUniformBlocks << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002088 return false;
2089 }
2090 }
2091 }
Jamie Madille473dee2015-08-18 14:49:01 -04002092
Geoff Lang7dd2e102014-11-10 15:19:26 -05002093 return true;
2094}
2095
2096bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
2097 const sh::InterfaceBlock &fragmentInterfaceBlock)
2098{
2099 const char* blockName = vertexInterfaceBlock.name.c_str();
2100 // validate blocks for the same member types
2101 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2102 {
Jamie Madillf6113162015-05-07 11:49:21 -04002103 infoLog << "Types for interface block '" << blockName
2104 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002105 return false;
2106 }
2107 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2108 {
Jamie Madillf6113162015-05-07 11:49:21 -04002109 infoLog << "Array sizes differ for interface block '" << blockName
2110 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002111 return false;
2112 }
2113 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2114 {
Jamie Madillf6113162015-05-07 11:49:21 -04002115 infoLog << "Layout qualifiers differ for interface block '" << blockName
2116 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002117 return false;
2118 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002119 const unsigned int numBlockMembers =
2120 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002121 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2122 {
2123 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2124 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2125 if (vertexMember.name != fragmentMember.name)
2126 {
Jamie Madillf6113162015-05-07 11:49:21 -04002127 infoLog << "Name mismatch for field " << blockMemberIndex
2128 << " of interface block '" << blockName
2129 << "': (in vertex: '" << vertexMember.name
2130 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 return false;
2132 }
2133 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2134 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2135 {
2136 return false;
2137 }
2138 }
2139 return true;
2140}
2141
2142bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2143 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2144{
2145 if (vertexVariable.type != fragmentVariable.type)
2146 {
Jamie Madillf6113162015-05-07 11:49:21 -04002147 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002148 return false;
2149 }
2150 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2151 {
Jamie Madillf6113162015-05-07 11:49:21 -04002152 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002153 return false;
2154 }
2155 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2156 {
Jamie Madillf6113162015-05-07 11:49:21 -04002157 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002158 return false;
2159 }
2160
2161 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2162 {
Jamie Madillf6113162015-05-07 11:49:21 -04002163 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002164 return false;
2165 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002166 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002167 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2168 {
2169 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2170 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2171
2172 if (vertexMember.name != fragmentMember.name)
2173 {
Jamie Madillf6113162015-05-07 11:49:21 -04002174 infoLog << "Name mismatch for field '" << memberIndex
2175 << "' of " << variableName
2176 << ": (in vertex: '" << vertexMember.name
2177 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 return false;
2179 }
2180
2181 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2182 vertexMember.name + "'";
2183
2184 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2185 {
2186 return false;
2187 }
2188 }
2189
2190 return true;
2191}
2192
2193bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2194{
Cooper Partin1acf4382015-06-12 12:38:57 -07002195#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2196 const bool validatePrecision = true;
2197#else
2198 const bool validatePrecision = false;
2199#endif
2200
2201 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002202 {
2203 return false;
2204 }
2205
2206 return true;
2207}
2208
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002209bool Program::linkValidateVaryings(InfoLog &infoLog,
2210 const std::string &varyingName,
2211 const sh::Varying &vertexVarying,
2212 const sh::Varying &fragmentVarying,
2213 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002214{
2215 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2216 {
2217 return false;
2218 }
2219
Jamie Madille9cc4692015-02-19 16:00:13 -05002220 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002222 infoLog << "Interpolation types for " << varyingName
2223 << " differ between vertex and fragment shaders.";
2224 return false;
2225 }
2226
2227 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2228 {
2229 infoLog << "Invariance for " << varyingName
2230 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002231 return false;
2232 }
2233
2234 return true;
2235}
2236
Jamie Madillccdf74b2015-08-18 10:46:12 -04002237bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2238 const std::vector<const sh::Varying *> &varyings,
2239 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002240{
2241 size_t totalComponents = 0;
2242
Jamie Madillccdf74b2015-08-18 10:46:12 -04002243 std::set<std::string> uniqueNames;
2244
Jamie Madill48ef11b2016-04-27 15:21:52 -04002245 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002246 {
2247 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002248 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002249 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002250 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002251 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002252 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002253 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002254 infoLog << "Two transform feedback varyings specify the same output variable ("
2255 << tfVaryingName << ").";
2256 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002257 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002258 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002259
Geoff Lang1a683462015-09-29 15:09:59 -04002260 if (varying->isArray())
2261 {
2262 infoLog << "Capture of arrays is undefined and not supported.";
2263 return false;
2264 }
2265
Jamie Madillccdf74b2015-08-18 10:46:12 -04002266 // TODO(jmadill): Investigate implementation limits on D3D11
2267 size_t componentCount = gl::VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002268 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002269 componentCount > caps.maxTransformFeedbackSeparateComponents)
2270 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002271 infoLog << "Transform feedback varying's " << varying->name << " components ("
2272 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002273 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002274 return false;
2275 }
2276
2277 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002278 found = true;
2279 break;
2280 }
2281 }
2282
Jamie Madill89bb70e2015-08-31 14:18:39 -04002283 if (tfVaryingName.find('[') != std::string::npos)
2284 {
Geoff Lang1a683462015-09-29 15:09:59 -04002285 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002286 return false;
2287 }
2288
Geoff Lang7dd2e102014-11-10 15:19:26 -05002289 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2290 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04002291 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002292 }
2293
Jamie Madill48ef11b2016-04-27 15:21:52 -04002294 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002295 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002296 {
Jamie Madillf6113162015-05-07 11:49:21 -04002297 infoLog << "Transform feedback varying total components (" << totalComponents
2298 << ") exceed the maximum interleaved components ("
2299 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002300 return false;
2301 }
2302
2303 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002304}
2305
Jamie Madillccdf74b2015-08-18 10:46:12 -04002306void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2307{
2308 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002309 mState.mTransformFeedbackVaryingVars.clear();
2310 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002311 {
2312 for (const sh::Varying *varying : varyings)
2313 {
2314 if (tfVaryingName == varying->name)
2315 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002316 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002317 break;
2318 }
2319 }
2320 }
2321}
2322
2323std::vector<const sh::Varying *> Program::getMergedVaryings() const
2324{
2325 std::set<std::string> uniqueNames;
2326 std::vector<const sh::Varying *> varyings;
2327
Jamie Madill48ef11b2016-04-27 15:21:52 -04002328 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002329 {
2330 if (uniqueNames.count(varying.name) == 0)
2331 {
2332 uniqueNames.insert(varying.name);
2333 varyings.push_back(&varying);
2334 }
2335 }
2336
Jamie Madill48ef11b2016-04-27 15:21:52 -04002337 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002338 {
2339 if (uniqueNames.count(varying.name) == 0)
2340 {
2341 uniqueNames.insert(varying.name);
2342 varyings.push_back(&varying);
2343 }
2344 }
2345
2346 return varyings;
2347}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002348
2349void Program::linkOutputVariables()
2350{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002351 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002352 ASSERT(fragmentShader != nullptr);
2353
2354 // Skip this step for GLES2 shaders.
2355 if (fragmentShader->getShaderVersion() == 100)
2356 return;
2357
Jamie Madilla0a9e122015-09-02 15:54:30 -04002358 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002359
2360 // TODO(jmadill): any caps validation here?
2361
2362 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2363 outputVariableIndex++)
2364 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002365 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002366
2367 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2368 if (outputVariable.isBuiltIn())
2369 continue;
2370
2371 // Since multiple output locations must be specified, use 0 for non-specified locations.
2372 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2373
2374 ASSERT(outputVariable.staticUse);
2375
2376 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2377 elementIndex++)
2378 {
2379 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002380 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002381 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002382 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002383 VariableLocation(outputVariable.name, element, outputVariableIndex);
2384 }
2385 }
2386}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002387
2388bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2389{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002390 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002391 VectorAndSamplerCount vsCounts;
2392
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002393 std::vector<LinkedUniform> samplerUniforms;
2394
Jamie Madill62d31cb2015-09-11 13:25:51 -04002395 for (const sh::Uniform &uniform : vertexShader->getUniforms())
2396 {
2397 if (uniform.staticUse)
2398 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002399 vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002400 }
2401 }
2402
2403 if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
2404 {
2405 infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
2406 << caps.maxVertexUniformVectors << ").";
2407 return false;
2408 }
2409
2410 if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
2411 {
2412 infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
2413 << caps.maxVertexTextureImageUnits << ").";
2414 return false;
2415 }
2416
Jamie Madill48ef11b2016-04-27 15:21:52 -04002417 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002418 VectorAndSamplerCount fsCounts;
2419
2420 for (const sh::Uniform &uniform : fragmentShader->getUniforms())
2421 {
2422 if (uniform.staticUse)
2423 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002424 fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002425 }
2426 }
2427
2428 if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
2429 {
2430 infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
2431 << caps.maxFragmentUniformVectors << ").";
2432 return false;
2433 }
2434
2435 if (fsCounts.samplerCount > caps.maxTextureImageUnits)
2436 {
2437 infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
2438 << caps.maxTextureImageUnits << ").";
2439 return false;
2440 }
2441
Jamie Madill48ef11b2016-04-27 15:21:52 -04002442 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002443 mSamplerUniformRange.end =
2444 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2445
Jamie Madill48ef11b2016-04-27 15:21:52 -04002446 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002447
Jamie Madill62d31cb2015-09-11 13:25:51 -04002448 return true;
2449}
2450
2451Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002452 const std::string &fullName,
2453 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002454{
2455 VectorAndSamplerCount vectorAndSamplerCount;
2456
2457 if (uniform.isStruct())
2458 {
2459 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2460 {
2461 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2462
2463 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2464 {
2465 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2466 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2467
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002468 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002469 }
2470 }
2471
2472 return vectorAndSamplerCount;
2473 }
2474
2475 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002476 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002477 if (!UniformInList(mState.getUniforms(), fullName) &&
2478 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002479 {
2480 gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
2481 uniform.arraySize, -1,
2482 sh::BlockMemberInfo::getDefaultBlockInfo());
2483 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002484
2485 // Store sampler uniforms separately, so we'll append them to the end of the list.
2486 if (isSampler)
2487 {
2488 samplerUniforms->push_back(linkedUniform);
2489 }
2490 else
2491 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002492 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002493 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002494 }
2495
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002496 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002497
2498 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2499 // Likewise, don't count "real" uniforms towards sampler count.
2500 vectorAndSamplerCount.vectorCount =
2501 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002502 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002503
2504 return vectorAndSamplerCount;
2505}
2506
2507void Program::gatherInterfaceBlockInfo()
2508{
2509 std::set<std::string> visitedList;
2510
Jamie Madill48ef11b2016-04-27 15:21:52 -04002511 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002512
Jamie Madill48ef11b2016-04-27 15:21:52 -04002513 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002514 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2515 {
2516 // Only 'packed' blocks are allowed to be considered inacive.
2517 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2518 continue;
2519
2520 if (visitedList.count(vertexBlock.name) > 0)
2521 continue;
2522
2523 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2524 visitedList.insert(vertexBlock.name);
2525 }
2526
Jamie Madill48ef11b2016-04-27 15:21:52 -04002527 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002528
2529 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2530 {
2531 // Only 'packed' blocks are allowed to be considered inacive.
2532 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2533 continue;
2534
2535 if (visitedList.count(fragmentBlock.name) > 0)
2536 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002537 for (gl::UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002538 {
2539 if (block.name == fragmentBlock.name)
2540 {
2541 block.fragmentStaticUse = fragmentBlock.staticUse;
2542 }
2543 }
2544
2545 continue;
2546 }
2547
2548 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2549 visitedList.insert(fragmentBlock.name);
2550 }
2551}
2552
Jamie Madill4a3c2342015-10-08 12:58:45 -04002553template <typename VarT>
2554void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2555 const std::string &prefix,
2556 int blockIndex)
2557{
2558 for (const VarT &field : fields)
2559 {
2560 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2561
2562 if (field.isStruct())
2563 {
2564 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2565 {
2566 const std::string uniformElementName =
2567 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2568 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2569 }
2570 }
2571 else
2572 {
2573 // If getBlockMemberInfo returns false, the uniform is optimized out.
2574 sh::BlockMemberInfo memberInfo;
2575 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2576 {
2577 continue;
2578 }
2579
2580 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2581 blockIndex, memberInfo);
2582
2583 // Since block uniforms have no location, we don't need to store them in the uniform
2584 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002585 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002586 }
2587 }
2588}
2589
Jamie Madill62d31cb2015-09-11 13:25:51 -04002590void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2591{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002592 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002593 size_t blockSize = 0;
2594
2595 // Don't define this block at all if it's not active in the implementation.
2596 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2597 {
2598 return;
2599 }
2600
2601 // Track the first and last uniform index to determine the range of active uniforms in the
2602 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002603 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002604 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002605 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002606
2607 std::vector<unsigned int> blockUniformIndexes;
2608 for (size_t blockUniformIndex = firstBlockUniformIndex;
2609 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2610 {
2611 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2612 }
2613
2614 if (interfaceBlock.arraySize > 0)
2615 {
2616 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2617 {
2618 UniformBlock block(interfaceBlock.name, true, arrayElement);
2619 block.memberUniformIndexes = blockUniformIndexes;
2620
2621 if (shaderType == GL_VERTEX_SHADER)
2622 {
2623 block.vertexStaticUse = interfaceBlock.staticUse;
2624 }
2625 else
2626 {
2627 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2628 block.fragmentStaticUse = interfaceBlock.staticUse;
2629 }
2630
Jamie Madill4a3c2342015-10-08 12:58:45 -04002631 // TODO(jmadill): Determine if we can ever have an inactive array element block.
2632 size_t blockElementSize = 0;
2633 if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
2634 {
2635 continue;
2636 }
2637
2638 ASSERT(blockElementSize == blockSize);
2639 block.dataSize = static_cast<unsigned int>(blockElementSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002640 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002641 }
2642 }
2643 else
2644 {
2645 UniformBlock block(interfaceBlock.name, false, 0);
2646 block.memberUniformIndexes = blockUniformIndexes;
2647
2648 if (shaderType == GL_VERTEX_SHADER)
2649 {
2650 block.vertexStaticUse = interfaceBlock.staticUse;
2651 }
2652 else
2653 {
2654 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2655 block.fragmentStaticUse = interfaceBlock.staticUse;
2656 }
2657
Jamie Madill4a3c2342015-10-08 12:58:45 -04002658 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002659 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002660 }
2661}
2662
2663template <typename T>
2664void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
2665{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002666 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2667 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002668 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2669
2670 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2671 {
2672 // Do a cast conversion for boolean types. From the spec:
2673 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2674 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
2675 for (GLsizei component = 0; component < count; ++component)
2676 {
2677 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2678 }
2679 }
2680 else
2681 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002682 // Invalide the validation cache if we modify the sampler data.
2683 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
2684 {
2685 mCachedValidateSamplersResult.reset();
2686 }
2687
Jamie Madill62d31cb2015-09-11 13:25:51 -04002688 memcpy(destPointer, v, sizeof(T) * count);
2689 }
2690}
2691
2692template <size_t cols, size_t rows, typename T>
2693void Program::setMatrixUniformInternal(GLint location,
2694 GLsizei count,
2695 GLboolean transpose,
2696 const T *v)
2697{
2698 if (!transpose)
2699 {
2700 setUniformInternal(location, count * cols * rows, v);
2701 return;
2702 }
2703
2704 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002705 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2706 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002707 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
2708 for (GLsizei element = 0; element < count; ++element)
2709 {
2710 size_t elementOffset = element * rows * cols;
2711
2712 for (size_t row = 0; row < rows; ++row)
2713 {
2714 for (size_t col = 0; col < cols; ++col)
2715 {
2716 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2717 }
2718 }
2719 }
2720}
2721
2722template <typename DestT>
2723void Program::getUniformInternal(GLint location, DestT *dataOut) const
2724{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002725 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2726 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002727
2728 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2729
2730 GLenum componentType = VariableComponentType(uniform.type);
2731 if (componentType == GLTypeToGLenum<DestT>::value)
2732 {
2733 memcpy(dataOut, srcPointer, uniform.getElementSize());
2734 return;
2735 }
2736
Corentin Wallez6596c462016-03-17 17:26:58 -04002737 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002738
2739 switch (componentType)
2740 {
2741 case GL_INT:
2742 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2743 break;
2744 case GL_UNSIGNED_INT:
2745 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2746 break;
2747 case GL_BOOL:
2748 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2749 break;
2750 case GL_FLOAT:
2751 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2752 break;
2753 default:
2754 UNREACHABLE();
2755 }
2756}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002757}