blob: dc56af3bd362558bda4d76b2a04570a3fb2e3409 [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.
180// The D3D compiler includes a fake file path in some of the warning or error
181// 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
444// compiling them into binaries, determining the attribute mappings, and collecting
445// a list of uniforms
Jamie Madill9082b982016-04-27 15:21:51 -0400446Error Program::link(const ContextState &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000447{
448 unlink(false);
449
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000450 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000451 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000452
Jamie Madill48ef11b2016-04-27 15:21:52 -0400453 if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500454 {
455 return Error(GL_NO_ERROR);
456 }
Jamie Madill48ef11b2016-04-27 15:21:52 -0400457 ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500458
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459 if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500460 {
461 return Error(GL_NO_ERROR);
462 }
Jamie Madill48ef11b2016-04-27 15:21:52 -0400463 ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500464
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400465 if (mState.mAttachedFragmentShader->getShaderVersion() !=
466 mState.mAttachedVertexShader->getShaderVersion())
467 {
468 mInfoLog << "Fragment shader version does not match vertex shader version.";
469 return Error(GL_NO_ERROR);
470 }
471
Jamie Madill48ef11b2016-04-27 15:21:52 -0400472 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mState.mAttachedVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500473 {
474 return Error(GL_NO_ERROR);
475 }
476
Jamie Madill48ef11b2016-04-27 15:21:52 -0400477 if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
Jamie Madillada9ecc2015-08-17 12:53:37 -0400478 {
479 return Error(GL_NO_ERROR);
480 }
481
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700482 if (!linkUniforms(mInfoLog, data.getCaps(), mUniformBindings))
Jamie Madillea918db2015-08-18 14:48:59 -0400483 {
484 return Error(GL_NO_ERROR);
485 }
486
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700487 if (!linkUniformBlocks(mInfoLog, data.getCaps()))
Jamie Madille473dee2015-08-18 14:49:01 -0400488 {
489 return Error(GL_NO_ERROR);
490 }
491
Jamie Madillccdf74b2015-08-18 10:46:12 -0400492 const auto &mergedVaryings = getMergedVaryings();
493
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700494 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, data.getCaps()))
Jamie Madillccdf74b2015-08-18 10:46:12 -0400495 {
496 return Error(GL_NO_ERROR);
497 }
498
Jamie Madill80a6fc02015-08-21 16:53:16 -0400499 linkOutputVariables();
500
Jamie Madillf5f4ad22015-09-02 18:32:38 +0000501 rx::LinkResult result = mProgram->link(data, mInfoLog);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500502 if (result.error.isError() || !result.linkSuccess)
503 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500504 return result.error;
505 }
506
Jamie Madillccdf74b2015-08-18 10:46:12 -0400507 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill4a3c2342015-10-08 12:58:45 -0400508 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400509
Geoff Lang7dd2e102014-11-10 15:19:26 -0500510 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400511 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000512}
513
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000514// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515void Program::unlink(bool destroy)
516{
517 if (destroy) // Object being destructed
518 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400519 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400521 mState.mAttachedFragmentShader->release();
522 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523 }
524
Jamie Madill48ef11b2016-04-27 15:21:52 -0400525 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400527 mState.mAttachedVertexShader->release();
528 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530 }
531
Jamie Madill48ef11b2016-04-27 15:21:52 -0400532 mState.mAttributes.clear();
533 mState.mActiveAttribLocationsMask.reset();
534 mState.mTransformFeedbackVaryingVars.clear();
535 mState.mUniforms.clear();
536 mState.mUniformLocations.clear();
537 mState.mUniformBlocks.clear();
538 mState.mOutputVariables.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500539
Geoff Lang7dd2e102014-11-10 15:19:26 -0500540 mValidated = false;
541
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000542 mLinked = false;
543}
544
Geoff Lange1a27752015-10-05 13:16:04 -0400545bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000546{
547 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548}
549
Geoff Lang7dd2e102014-11-10 15:19:26 -0500550Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000551{
552 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000553
Geoff Lang7dd2e102014-11-10 15:19:26 -0500554#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
555 return Error(GL_NO_ERROR);
556#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400557 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
558 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000559 {
Jamie Madillf6113162015-05-07 11:49:21 -0400560 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500561 return Error(GL_NO_ERROR);
562 }
563
Geoff Langc46cc2f2015-10-01 17:16:20 -0400564 BinaryInputStream stream(binary, length);
565
Geoff Lang7dd2e102014-11-10 15:19:26 -0500566 int majorVersion = stream.readInt<int>();
567 int minorVersion = stream.readInt<int>();
568 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
569 {
Jamie Madillf6113162015-05-07 11:49:21 -0400570 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500571 return Error(GL_NO_ERROR);
572 }
573
574 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
575 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
576 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
577 {
Jamie Madillf6113162015-05-07 11:49:21 -0400578 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500579 return Error(GL_NO_ERROR);
580 }
581
Jamie Madill63805b42015-08-25 13:17:39 -0400582 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
583 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400584 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500585
Jamie Madill3da79b72015-04-27 11:09:17 -0400586 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400587 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400588 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
589 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400590 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400591 LoadShaderVar(&stream, &attrib);
592 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400593 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400594 }
595
Jamie Madill62d31cb2015-09-11 13:25:51 -0400596 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400597 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400598 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
599 {
600 LinkedUniform uniform;
601 LoadShaderVar(&stream, &uniform);
602
603 uniform.blockIndex = stream.readInt<int>();
604 uniform.blockInfo.offset = stream.readInt<int>();
605 uniform.blockInfo.arrayStride = stream.readInt<int>();
606 uniform.blockInfo.matrixStride = stream.readInt<int>();
607 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
608
Jamie Madill48ef11b2016-04-27 15:21:52 -0400609 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400610 }
611
612 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400613 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400614 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
615 uniformIndexIndex++)
616 {
617 VariableLocation variable;
618 stream.readString(&variable.name);
619 stream.readInt(&variable.element);
620 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400621 stream.readBool(&variable.used);
622 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400623
Jamie Madill48ef11b2016-04-27 15:21:52 -0400624 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400625 }
626
627 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400628 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400629 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
630 ++uniformBlockIndex)
631 {
632 UniformBlock uniformBlock;
633 stream.readString(&uniformBlock.name);
634 stream.readBool(&uniformBlock.isArray);
635 stream.readInt(&uniformBlock.arrayElement);
636 stream.readInt(&uniformBlock.dataSize);
637 stream.readBool(&uniformBlock.vertexStaticUse);
638 stream.readBool(&uniformBlock.fragmentStaticUse);
639
640 unsigned int numMembers = stream.readInt<unsigned int>();
641 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
642 {
643 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
644 }
645
Jamie Madill48ef11b2016-04-27 15:21:52 -0400646 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400647 }
648
Brandon Jones1048ea72015-10-06 15:34:52 -0700649 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400650 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700651 for (unsigned int transformFeedbackVaryingIndex = 0;
652 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
653 ++transformFeedbackVaryingIndex)
654 {
655 sh::Varying varying;
656 stream.readInt(&varying.arraySize);
657 stream.readInt(&varying.type);
658 stream.readString(&varying.name);
659
Jamie Madill48ef11b2016-04-27 15:21:52 -0400660 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700661 }
662
Jamie Madill48ef11b2016-04-27 15:21:52 -0400663 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400664
Jamie Madill80a6fc02015-08-21 16:53:16 -0400665 unsigned int outputVarCount = stream.readInt<unsigned int>();
666 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
667 {
668 int locationIndex = stream.readInt<int>();
669 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400670 stream.readInt(&locationData.element);
671 stream.readInt(&locationData.index);
672 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400673 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400674 }
675
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400676 stream.readInt(&mSamplerUniformRange.start);
677 stream.readInt(&mSamplerUniformRange.end);
678
Geoff Lang7dd2e102014-11-10 15:19:26 -0500679 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
680 if (result.error.isError() || !result.linkSuccess)
681 {
Geoff Langb543aff2014-09-30 14:52:54 -0400682 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000683 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000684
Geoff Lang7dd2e102014-11-10 15:19:26 -0500685 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400686 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500687#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
688}
689
690Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
691{
692 if (binaryFormat)
693 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400694 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500695 }
696
697 BinaryOutputStream stream;
698
Geoff Lang7dd2e102014-11-10 15:19:26 -0500699 stream.writeInt(ANGLE_MAJOR_VERSION);
700 stream.writeInt(ANGLE_MINOR_VERSION);
701 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
702
Jamie Madill48ef11b2016-04-27 15:21:52 -0400703 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500704
Jamie Madill48ef11b2016-04-27 15:21:52 -0400705 stream.writeInt(mState.mAttributes.size());
706 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400707 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400708 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400709 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400710 }
711
Jamie Madill48ef11b2016-04-27 15:21:52 -0400712 stream.writeInt(mState.mUniforms.size());
713 for (const gl::LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400714 {
715 WriteShaderVar(&stream, uniform);
716
717 // FIXME: referenced
718
719 stream.writeInt(uniform.blockIndex);
720 stream.writeInt(uniform.blockInfo.offset);
721 stream.writeInt(uniform.blockInfo.arrayStride);
722 stream.writeInt(uniform.blockInfo.matrixStride);
723 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
724 }
725
Jamie Madill48ef11b2016-04-27 15:21:52 -0400726 stream.writeInt(mState.mUniformLocations.size());
727 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400728 {
729 stream.writeString(variable.name);
730 stream.writeInt(variable.element);
731 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400732 stream.writeInt(variable.used);
733 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400734 }
735
Jamie Madill48ef11b2016-04-27 15:21:52 -0400736 stream.writeInt(mState.mUniformBlocks.size());
737 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400738 {
739 stream.writeString(uniformBlock.name);
740 stream.writeInt(uniformBlock.isArray);
741 stream.writeInt(uniformBlock.arrayElement);
742 stream.writeInt(uniformBlock.dataSize);
743
744 stream.writeInt(uniformBlock.vertexStaticUse);
745 stream.writeInt(uniformBlock.fragmentStaticUse);
746
747 stream.writeInt(uniformBlock.memberUniformIndexes.size());
748 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
749 {
750 stream.writeInt(memberUniformIndex);
751 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400752 }
753
Jamie Madill48ef11b2016-04-27 15:21:52 -0400754 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
755 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700756 {
757 stream.writeInt(varying.arraySize);
758 stream.writeInt(varying.type);
759 stream.writeString(varying.name);
760 }
761
Jamie Madill48ef11b2016-04-27 15:21:52 -0400762 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400763
Jamie Madill48ef11b2016-04-27 15:21:52 -0400764 stream.writeInt(mState.mOutputVariables.size());
765 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -0400766 {
767 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -0400768 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400769 stream.writeInt(outputPair.second.index);
770 stream.writeString(outputPair.second.name);
771 }
772
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400773 stream.writeInt(mSamplerUniformRange.start);
774 stream.writeInt(mSamplerUniformRange.end);
775
Geoff Lang7dd2e102014-11-10 15:19:26 -0500776 gl::Error error = mProgram->save(&stream);
777 if (error.isError())
778 {
779 return error;
780 }
781
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700782 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -0400783 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500784
785 if (streamLength > bufSize)
786 {
787 if (length)
788 {
789 *length = 0;
790 }
791
792 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
793 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
794 // sizes and then copy it.
795 return Error(GL_INVALID_OPERATION);
796 }
797
798 if (binary)
799 {
800 char *ptr = reinterpret_cast<char*>(binary);
801
Jamie Madill48ef11b2016-04-27 15:21:52 -0400802 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500803 ptr += streamLength;
804
805 ASSERT(ptr - streamLength == binary);
806 }
807
808 if (length)
809 {
810 *length = streamLength;
811 }
812
813 return Error(GL_NO_ERROR);
814}
815
816GLint Program::getBinaryLength() const
817{
818 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400819 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500820 if (error.isError())
821 {
822 return 0;
823 }
824
825 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000826}
827
Geoff Langc5629752015-12-07 16:29:04 -0500828void Program::setBinaryRetrievableHint(bool retrievable)
829{
830 // TODO(jmadill) : replace with dirty bits
831 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400832 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -0500833}
834
835bool Program::getBinaryRetrievableHint() const
836{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400837 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -0500838}
839
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000840void Program::release()
841{
842 mRefCount--;
843
844 if (mRefCount == 0 && mDeleteStatus)
845 {
846 mResourceManager->deleteProgram(mHandle);
847 }
848}
849
850void Program::addRef()
851{
852 mRefCount++;
853}
854
855unsigned int Program::getRefCount() const
856{
857 return mRefCount;
858}
859
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000860int Program::getInfoLogLength() const
861{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400862 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000863}
864
Geoff Lange1a27752015-10-05 13:16:04 -0400865void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000866{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000867 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000868}
869
Geoff Lange1a27752015-10-05 13:16:04 -0400870void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000871{
872 int total = 0;
873
Jamie Madill48ef11b2016-04-27 15:21:52 -0400874 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000875 {
876 if (total < maxCount)
877 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400878 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200879 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000880 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000881 }
882
Jamie Madill48ef11b2016-04-27 15:21:52 -0400883 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000884 {
885 if (total < maxCount)
886 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400887 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200888 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000889 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000890 }
891
892 if (count)
893 {
894 *count = total;
895 }
896}
897
Geoff Lange1a27752015-10-05 13:16:04 -0400898GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500899{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400900 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500901 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400902 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500903 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400904 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500905 }
906 }
907
Austin Kinrossb8af7232015-03-16 22:33:25 -0700908 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500909}
910
Jamie Madill63805b42015-08-25 13:17:39 -0400911bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400912{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400913 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
914 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500915}
916
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000917void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
918{
Jamie Madillc349ec02015-08-21 16:53:12 -0400919 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000920 {
921 if (bufsize > 0)
922 {
923 name[0] = '\0';
924 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500925
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000926 if (length)
927 {
928 *length = 0;
929 }
930
931 *type = GL_NONE;
932 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -0400933 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000934 }
Jamie Madillc349ec02015-08-21 16:53:12 -0400935
936 size_t attributeIndex = 0;
937
Jamie Madill48ef11b2016-04-27 15:21:52 -0400938 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400939 {
940 // Skip over inactive attributes
941 if (attribute.staticUse)
942 {
943 if (static_cast<size_t>(index) == attributeIndex)
944 {
945 break;
946 }
947 attributeIndex++;
948 }
949 }
950
Jamie Madill48ef11b2016-04-27 15:21:52 -0400951 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
952 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -0400953
954 if (bufsize > 0)
955 {
956 const char *string = attrib.name.c_str();
957
958 strncpy(name, string, bufsize);
959 name[bufsize - 1] = '\0';
960
961 if (length)
962 {
963 *length = static_cast<GLsizei>(strlen(name));
964 }
965 }
966
967 // Always a single 'type' instance
968 *size = 1;
969 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000970}
971
Geoff Lange1a27752015-10-05 13:16:04 -0400972GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000973{
Jamie Madillc349ec02015-08-21 16:53:12 -0400974 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400975 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400976 return 0;
977 }
978
979 GLint count = 0;
980
Jamie Madill48ef11b2016-04-27 15:21:52 -0400981 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400982 {
983 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000984 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500985
986 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000987}
988
Geoff Lange1a27752015-10-05 13:16:04 -0400989GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000990{
Jamie Madillc349ec02015-08-21 16:53:12 -0400991 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400992 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400993 return 0;
994 }
995
996 size_t maxLength = 0;
997
Jamie Madill48ef11b2016-04-27 15:21:52 -0400998 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400999 {
1000 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001002 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001003 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001004 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001005
Jamie Madillc349ec02015-08-21 16:53:12 -04001006 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001007}
1008
Geoff Lang7dd2e102014-11-10 15:19:26 -05001009GLint Program::getFragDataLocation(const std::string &name) const
1010{
1011 std::string baseName(name);
1012 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001013 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001014 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001015 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001016 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1017 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001018 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001019 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001020 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001021 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001022}
1023
Geoff Lange1a27752015-10-05 13:16:04 -04001024void Program::getActiveUniform(GLuint index,
1025 GLsizei bufsize,
1026 GLsizei *length,
1027 GLint *size,
1028 GLenum *type,
1029 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001030{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001031 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001032 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001033 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001034 ASSERT(index < mState.mUniforms.size());
1035 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001036
1037 if (bufsize > 0)
1038 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001039 std::string string = uniform.name;
1040 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001041 {
1042 string += "[0]";
1043 }
1044
1045 strncpy(name, string.c_str(), bufsize);
1046 name[bufsize - 1] = '\0';
1047
1048 if (length)
1049 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001050 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001051 }
1052 }
1053
Jamie Madill62d31cb2015-09-11 13:25:51 -04001054 *size = uniform.elementCount();
1055 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001056 }
1057 else
1058 {
1059 if (bufsize > 0)
1060 {
1061 name[0] = '\0';
1062 }
1063
1064 if (length)
1065 {
1066 *length = 0;
1067 }
1068
1069 *size = 0;
1070 *type = GL_NONE;
1071 }
1072}
1073
Geoff Lange1a27752015-10-05 13:16:04 -04001074GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001075{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001076 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001077 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001078 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001079 }
1080 else
1081 {
1082 return 0;
1083 }
1084}
1085
Geoff Lange1a27752015-10-05 13:16:04 -04001086GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001087{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001088 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001089
1090 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001091 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001092 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001093 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001094 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001095 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001096 size_t length = uniform.name.length() + 1u;
1097 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001098 {
1099 length += 3; // Counting in "[0]".
1100 }
1101 maxLength = std::max(length, maxLength);
1102 }
1103 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001104 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001105
Jamie Madill62d31cb2015-09-11 13:25:51 -04001106 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001107}
1108
1109GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1110{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001111 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
1112 const gl::LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001113 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001114 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001115 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1116 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1117 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1118 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1119 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1120 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1121 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1122 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1123 default:
1124 UNREACHABLE();
1125 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001126 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001127 return 0;
1128}
1129
1130bool Program::isValidUniformLocation(GLint location) const
1131{
Jamie Madille2e406c2016-06-02 13:04:10 -04001132 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001133 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1134 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001135}
1136
1137bool Program::isIgnoredUniformLocation(GLint location) const
1138{
1139 // Location is ignored if it is -1 or it was bound but non-existant in the shader or optimized
1140 // out
1141 return location == -1 ||
Jamie Madill48ef11b2016-04-27 15:21:52 -04001142 (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1143 mState.mUniformLocations[static_cast<size_t>(location)].ignored);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001144}
1145
Jamie Madill62d31cb2015-09-11 13:25:51 -04001146const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001147{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001148 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1149 return mState.mUniforms[mState.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001150}
1151
Jamie Madill62d31cb2015-09-11 13:25:51 -04001152GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001153{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001154 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001155}
1156
Jamie Madill62d31cb2015-09-11 13:25:51 -04001157GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001158{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001159 return mState.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160}
1161
1162void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1163{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001164 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001165 mProgram->setUniform1fv(location, count, v);
1166}
1167
1168void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1169{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001170 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001171 mProgram->setUniform2fv(location, count, v);
1172}
1173
1174void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1175{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001176 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001177 mProgram->setUniform3fv(location, count, v);
1178}
1179
1180void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1181{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001182 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001183 mProgram->setUniform4fv(location, count, v);
1184}
1185
1186void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1187{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001188 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001189 mProgram->setUniform1iv(location, count, v);
1190}
1191
1192void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1193{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001194 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001195 mProgram->setUniform2iv(location, count, v);
1196}
1197
1198void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1199{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001200 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001201 mProgram->setUniform3iv(location, count, v);
1202}
1203
1204void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1205{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001206 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001207 mProgram->setUniform4iv(location, count, v);
1208}
1209
1210void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1211{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001212 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001213 mProgram->setUniform1uiv(location, count, v);
1214}
1215
1216void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1217{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001218 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001219 mProgram->setUniform2uiv(location, count, v);
1220}
1221
1222void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1223{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001224 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001225 mProgram->setUniform3uiv(location, count, v);
1226}
1227
1228void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1229{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001230 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001231 mProgram->setUniform4uiv(location, count, v);
1232}
1233
1234void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1235{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001236 setMatrixUniformInternal<2, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001237 mProgram->setUniformMatrix2fv(location, count, transpose, v);
1238}
1239
1240void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1241{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001242 setMatrixUniformInternal<3, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001243 mProgram->setUniformMatrix3fv(location, count, transpose, v);
1244}
1245
1246void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1247{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001248 setMatrixUniformInternal<4, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001249 mProgram->setUniformMatrix4fv(location, count, transpose, v);
1250}
1251
1252void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1253{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001254 setMatrixUniformInternal<2, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001255 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
1256}
1257
1258void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1259{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001260 setMatrixUniformInternal<2, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001261 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
1262}
1263
1264void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1265{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001266 setMatrixUniformInternal<3, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001267 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
1268}
1269
1270void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1271{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001272 setMatrixUniformInternal<3, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001273 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
1274}
1275
1276void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1277{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001278 setMatrixUniformInternal<4, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001279 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
1280}
1281
1282void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1283{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001284 setMatrixUniformInternal<4, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001285 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
1286}
1287
Geoff Lange1a27752015-10-05 13:16:04 -04001288void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001290 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001291}
1292
Geoff Lange1a27752015-10-05 13:16:04 -04001293void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001294{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001295 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001296}
1297
Geoff Lange1a27752015-10-05 13:16:04 -04001298void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001299{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001300 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001301}
1302
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001303void Program::flagForDeletion()
1304{
1305 mDeleteStatus = true;
1306}
1307
1308bool Program::isFlaggedForDeletion() const
1309{
1310 return mDeleteStatus;
1311}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001312
Brandon Jones43a53e22014-08-28 16:23:22 -07001313void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001314{
1315 mInfoLog.reset();
1316
Geoff Lang7dd2e102014-11-10 15:19:26 -05001317 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001318 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001319 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001320 }
1321 else
1322 {
Jamie Madillf6113162015-05-07 11:49:21 -04001323 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001324 }
1325}
1326
Geoff Lang7dd2e102014-11-10 15:19:26 -05001327bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1328{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001329 // Skip cache if we're using an infolog, so we get the full error.
1330 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1331 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1332 {
1333 return mCachedValidateSamplersResult.value();
1334 }
1335
1336 if (mTextureUnitTypesCache.empty())
1337 {
1338 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1339 }
1340 else
1341 {
1342 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1343 }
1344
1345 // if any two active samplers in a program are of different types, but refer to the same
1346 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1347 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1348 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1349 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1350 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001351 const LinkedUniform &uniform = mState.mUniforms[samplerIndex];
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001352 ASSERT(uniform.isSampler());
1353
1354 if (!uniform.staticUse)
1355 continue;
1356
1357 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1358 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1359
1360 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1361 {
1362 GLuint textureUnit = dataPtr[arrayElement];
1363
1364 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1365 {
1366 if (infoLog)
1367 {
1368 (*infoLog) << "Sampler uniform (" << textureUnit
1369 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1370 << caps.maxCombinedTextureImageUnits << ")";
1371 }
1372
1373 mCachedValidateSamplersResult = false;
1374 return false;
1375 }
1376
1377 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1378 {
1379 if (textureType != mTextureUnitTypesCache[textureUnit])
1380 {
1381 if (infoLog)
1382 {
1383 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1384 "image unit ("
1385 << textureUnit << ").";
1386 }
1387
1388 mCachedValidateSamplersResult = false;
1389 return false;
1390 }
1391 }
1392 else
1393 {
1394 mTextureUnitTypesCache[textureUnit] = textureType;
1395 }
1396 }
1397 }
1398
1399 mCachedValidateSamplersResult = true;
1400 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001401}
1402
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001403bool Program::isValidated() const
1404{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001405 return mValidated;
1406}
1407
Geoff Lange1a27752015-10-05 13:16:04 -04001408GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001409{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001410 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411}
1412
1413void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1414{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001415 ASSERT(
1416 uniformBlockIndex <
1417 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001418
Jamie Madill48ef11b2016-04-27 15:21:52 -04001419 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001420
1421 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001422 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001423 std::string string = uniformBlock.name;
1424
Jamie Madill62d31cb2015-09-11 13:25:51 -04001425 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001426 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001427 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001428 }
1429
1430 strncpy(uniformBlockName, string.c_str(), bufSize);
1431 uniformBlockName[bufSize - 1] = '\0';
1432
1433 if (length)
1434 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001435 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001436 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001437 }
1438}
1439
Geoff Lang7dd2e102014-11-10 15:19:26 -05001440void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001441{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001442 ASSERT(
1443 uniformBlockIndex <
1444 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001445
Jamie Madill48ef11b2016-04-27 15:21:52 -04001446 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001447
1448 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001449 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001450 case GL_UNIFORM_BLOCK_DATA_SIZE:
1451 *params = static_cast<GLint>(uniformBlock.dataSize);
1452 break;
1453 case GL_UNIFORM_BLOCK_NAME_LENGTH:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001454 *params =
1455 static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001456 break;
1457 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1458 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1459 break;
1460 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1461 {
1462 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1463 {
1464 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1465 }
1466 }
1467 break;
1468 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001469 *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001470 break;
1471 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001472 *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473 break;
1474 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001475 }
1476}
1477
Geoff Lange1a27752015-10-05 13:16:04 -04001478GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001479{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001480 int maxLength = 0;
1481
1482 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001483 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001484 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1486 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001487 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001488 if (!uniformBlock.name.empty())
1489 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001490 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491
1492 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001493 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494
1495 maxLength = std::max(length + arrayLength, maxLength);
1496 }
1497 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001498 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001499
1500 return maxLength;
1501}
1502
Geoff Lange1a27752015-10-05 13:16:04 -04001503GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001505 size_t subscript = GL_INVALID_INDEX;
1506 std::string baseName = gl::ParseUniformName(name, &subscript);
1507
Jamie Madill48ef11b2016-04-27 15:21:52 -04001508 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001509 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1510 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001511 const gl::UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001512 if (uniformBlock.name == baseName)
1513 {
1514 const bool arrayElementZero =
1515 (subscript == GL_INVALID_INDEX &&
1516 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1517 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1518 {
1519 return blockIndex;
1520 }
1521 }
1522 }
1523
1524 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001525}
1526
Jamie Madill62d31cb2015-09-11 13:25:51 -04001527const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001528{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001529 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1530 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001531}
1532
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001533void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1534{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001535 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Geoff Lang5d124a62015-09-15 13:03:27 -04001536 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001537}
1538
1539GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1540{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001541 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001542}
1543
1544void Program::resetUniformBlockBindings()
1545{
1546 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1547 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001548 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001549 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001550 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001551}
1552
Geoff Lang48dcae72014-02-05 16:28:24 -05001553void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1554{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001555 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001556 for (GLsizei i = 0; i < count; i++)
1557 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001558 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001559 }
1560
Jamie Madill48ef11b2016-04-27 15:21:52 -04001561 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001562}
1563
1564void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1565{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001566 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001567 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001568 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1569 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001570 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1571 if (length)
1572 {
1573 *length = lastNameIdx;
1574 }
1575 if (size)
1576 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001577 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001578 }
1579 if (type)
1580 {
1581 *type = varying.type;
1582 }
1583 if (name)
1584 {
1585 memcpy(name, varying.name.c_str(), lastNameIdx);
1586 name[lastNameIdx] = '\0';
1587 }
1588 }
1589}
1590
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001591GLsizei Program::getTransformFeedbackVaryingCount() const
1592{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001593 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001594 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001595 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001596 }
1597 else
1598 {
1599 return 0;
1600 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001601}
1602
1603GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1604{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001605 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001606 {
1607 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001608 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001609 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001610 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1611 }
1612
1613 return maxSize;
1614 }
1615 else
1616 {
1617 return 0;
1618 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001619}
1620
1621GLenum Program::getTransformFeedbackBufferMode() const
1622{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001623 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001624}
1625
Jamie Madillada9ecc2015-08-17 12:53:37 -04001626// static
1627bool Program::linkVaryings(InfoLog &infoLog,
1628 const Shader *vertexShader,
1629 const Shader *fragmentShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001630{
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001631 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1632
Jamie Madill4cff2472015-08-21 16:53:18 -04001633 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1634 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001635
Jamie Madill4cff2472015-08-21 16:53:18 -04001636 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001637 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638 bool matched = false;
1639
1640 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001641 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001642 {
1643 continue;
1644 }
1645
Jamie Madill4cff2472015-08-21 16:53:18 -04001646 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001648 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001649 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001650 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001651 if (!linkValidateVaryings(infoLog, output.name, input, output,
1652 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001653 {
1654 return false;
1655 }
1656
Geoff Lang7dd2e102014-11-10 15:19:26 -05001657 matched = true;
1658 break;
1659 }
1660 }
1661
1662 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001663 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001664 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001665 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001666 return false;
1667 }
1668 }
1669
Jamie Madillada9ecc2015-08-17 12:53:37 -04001670 // TODO(jmadill): verify no unmatched vertex varyings?
1671
Geoff Lang7dd2e102014-11-10 15:19:26 -05001672 return true;
1673}
1674
Geoff Langd8605522016-04-13 10:19:12 -04001675bool Program::linkUniforms(gl::InfoLog &infoLog,
1676 const gl::Caps &caps,
1677 const Bindings &uniformBindings)
Jamie Madillea918db2015-08-18 14:48:59 -04001678{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001679 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1680 const std::vector<sh::Uniform> &fragmentUniforms =
1681 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001682
1683 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill62d31cb2015-09-11 13:25:51 -04001684 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madillea918db2015-08-18 14:48:59 -04001685
1686 for (const sh::Uniform &vertexUniform : vertexUniforms)
1687 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001688 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001689 }
1690
1691 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1692 {
1693 auto entry = linkedUniforms.find(fragmentUniform.name);
1694 if (entry != linkedUniforms.end())
1695 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001696 LinkedUniform *vertexUniform = &entry->second;
1697 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1698 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001699 {
1700 return false;
1701 }
1702 }
1703 }
1704
Jamie Madill62d31cb2015-09-11 13:25:51 -04001705 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1706 // Also check the maximum uniform vector and sampler counts.
1707 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1708 {
1709 return false;
1710 }
1711
Geoff Langd8605522016-04-13 10:19:12 -04001712 if (!indexUniforms(infoLog, caps, uniformBindings))
1713 {
1714 return false;
1715 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001716
Jamie Madillea918db2015-08-18 14:48:59 -04001717 return true;
1718}
1719
Geoff Langd8605522016-04-13 10:19:12 -04001720bool Program::indexUniforms(gl::InfoLog &infoLog,
1721 const gl::Caps &caps,
1722 const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001723{
Geoff Langd8605522016-04-13 10:19:12 -04001724 // Uniforms awaiting a location
1725 std::vector<VariableLocation> unboundUniforms;
1726 std::map<GLuint, VariableLocation> boundUniforms;
1727 int maxUniformLocation = -1;
1728
1729 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001730 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001731 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001732 const gl::LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001733
Geoff Langd8605522016-04-13 10:19:12 -04001734 if (uniform.isBuiltIn())
1735 {
1736 continue;
1737 }
1738
1739 int bindingLocation = uniformBindings.getBinding(uniform.name);
1740
1741 // Verify that this location isn't bound twice
1742 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1743 {
1744 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1745 return false;
1746 }
1747
Jamie Madill62d31cb2015-09-11 13:25:51 -04001748 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1749 {
Geoff Langd8605522016-04-13 10:19:12 -04001750 VariableLocation location(uniform.name, arrayIndex,
1751 static_cast<unsigned int>(uniformIndex));
1752
1753 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001754 {
Geoff Langd8605522016-04-13 10:19:12 -04001755 boundUniforms[bindingLocation] = location;
1756 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1757 }
1758 else
1759 {
1760 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001761 }
1762 }
1763 }
Geoff Langd8605522016-04-13 10:19:12 -04001764
1765 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1766 // not be assigned to those locations.
1767 std::set<GLuint> reservedLocations;
1768 for (const auto &binding : uniformBindings)
1769 {
1770 GLuint location = binding.second;
1771 if (boundUniforms.find(location) == boundUniforms.end())
1772 {
1773 reservedLocations.insert(location);
1774 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1775 }
1776 }
1777
1778 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04001779 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04001780 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
1781 static_cast<size_t>(maxUniformLocation + 1)));
1782
1783 // Assign bound uniforms
1784 for (const auto &boundUniform : boundUniforms)
1785 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04001787 }
1788
1789 // Assign reserved uniforms
1790 for (const auto &reservedLocation : reservedLocations)
1791 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001792 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04001793 }
1794
1795 // Assign unbound uniforms
1796 size_t nextUniformLocation = 0;
1797 for (const auto &unboundUniform : unboundUniforms)
1798 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001799 while (mState.mUniformLocations[nextUniformLocation].used ||
1800 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04001801 {
1802 nextUniformLocation++;
1803 }
1804
Jamie Madill48ef11b2016-04-27 15:21:52 -04001805 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
1806 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04001807 nextUniformLocation++;
1808 }
1809
1810 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04001811}
1812
Geoff Lang7dd2e102014-11-10 15:19:26 -05001813bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1814{
Jamie Madillc4c744222015-11-04 09:39:47 -05001815 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1816 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001817 {
1818 return false;
1819 }
1820
1821 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1822 {
Jamie Madillf6113162015-05-07 11:49:21 -04001823 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001824 return false;
1825 }
1826
1827 return true;
1828}
1829
1830// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill9082b982016-04-27 15:21:51 -04001831bool Program::linkAttributes(const ContextState &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001832 InfoLog &infoLog,
Geoff Langd8605522016-04-13 10:19:12 -04001833 const Bindings &attributeBindings,
Jamie Madill3da79b72015-04-27 11:09:17 -04001834 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001835{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001837 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001838 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04001839
1840 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001841 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001842 {
Jamie Madillf6113162015-05-07 11:49:21 -04001843 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001844 return false;
1845 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001846
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001847 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001848
Jamie Madillc349ec02015-08-21 16:53:12 -04001849 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001850 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001851 {
1852 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05001853 ASSERT(attribute.staticUse);
1854
Geoff Langd8605522016-04-13 10:19:12 -04001855 int bindingLocation = attributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04001856 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04001857 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001858 attribute.location = bindingLocation;
1859 }
1860
1861 if (attribute.location != -1)
1862 {
1863 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04001864 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001865
Jamie Madill63805b42015-08-25 13:17:39 -04001866 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001867 {
Jamie Madillf6113162015-05-07 11:49:21 -04001868 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04001869 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001870
1871 return false;
1872 }
1873
Jamie Madill63805b42015-08-25 13:17:39 -04001874 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 {
Jamie Madill63805b42015-08-25 13:17:39 -04001876 const int regLocation = attribute.location + reg;
1877 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878
1879 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001880 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04001881 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001883 // TODO(jmadill): fix aliasing on ES2
1884 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001886 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04001887 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001888 return false;
1889 }
1890 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001891 else
1892 {
Jamie Madill63805b42015-08-25 13:17:39 -04001893 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04001894 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001895
Jamie Madill63805b42015-08-25 13:17:39 -04001896 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001897 }
1898 }
1899 }
1900
1901 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001902 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001903 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904 ASSERT(attribute.staticUse);
1905
Jamie Madillc349ec02015-08-21 16:53:12 -04001906 // Not set by glBindAttribLocation or by location layout qualifier
1907 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001908 {
Jamie Madill63805b42015-08-25 13:17:39 -04001909 int regs = VariableRegisterCount(attribute.type);
1910 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001911
Jamie Madill63805b42015-08-25 13:17:39 -04001912 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001913 {
Jamie Madillf6113162015-05-07 11:49:21 -04001914 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04001915 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001916 }
1917
Jamie Madillc349ec02015-08-21 16:53:12 -04001918 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001919 }
1920 }
1921
Jamie Madill48ef11b2016-04-27 15:21:52 -04001922 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001923 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001924 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04001925 ASSERT(attribute.location != -1);
1926 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04001927
Jamie Madill63805b42015-08-25 13:17:39 -04001928 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001929 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001930 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931 }
1932 }
1933
Geoff Lang7dd2e102014-11-10 15:19:26 -05001934 return true;
1935}
1936
Jamie Madille473dee2015-08-18 14:49:01 -04001937bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001939 const Shader &vertexShader = *mState.mAttachedVertexShader;
1940 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
Jamie Madille473dee2015-08-18 14:49:01 -04001941
Geoff Lang7dd2e102014-11-10 15:19:26 -05001942 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1943 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madille473dee2015-08-18 14:49:01 -04001944
Geoff Lang7dd2e102014-11-10 15:19:26 -05001945 // Check that interface blocks defined in the vertex and fragment shaders are identical
1946 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1947 UniformBlockMap linkedUniformBlocks;
Jamie Madille473dee2015-08-18 14:49:01 -04001948
1949 GLuint vertexBlockCount = 0;
1950 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001952 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jamie Madille473dee2015-08-18 14:49:01 -04001953
1954 // Note: shared and std140 layouts are always considered active
1955 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1956 {
1957 if (++vertexBlockCount > caps.maxVertexUniformBlocks)
1958 {
1959 infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
1960 << caps.maxVertexUniformBlocks << ")";
1961 return false;
1962 }
1963 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001964 }
Jamie Madille473dee2015-08-18 14:49:01 -04001965
1966 GLuint fragmentBlockCount = 0;
1967 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001968 {
Jamie Madille473dee2015-08-18 14:49:01 -04001969 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001970 if (entry != linkedUniformBlocks.end())
1971 {
1972 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1973 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1974 {
1975 return false;
1976 }
1977 }
Jamie Madille473dee2015-08-18 14:49:01 -04001978
Geoff Lang7dd2e102014-11-10 15:19:26 -05001979 // Note: shared and std140 layouts are always considered active
Jamie Madille473dee2015-08-18 14:49:01 -04001980 if (fragmentInterfaceBlock.staticUse ||
1981 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001982 {
Jamie Madille473dee2015-08-18 14:49:01 -04001983 if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001984 {
Jamie Madille473dee2015-08-18 14:49:01 -04001985 infoLog
1986 << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
1987 << caps.maxFragmentUniformBlocks << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001988 return false;
1989 }
1990 }
1991 }
Jamie Madille473dee2015-08-18 14:49:01 -04001992
Geoff Lang7dd2e102014-11-10 15:19:26 -05001993 return true;
1994}
1995
1996bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1997 const sh::InterfaceBlock &fragmentInterfaceBlock)
1998{
1999 const char* blockName = vertexInterfaceBlock.name.c_str();
2000 // validate blocks for the same member types
2001 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2002 {
Jamie Madillf6113162015-05-07 11:49:21 -04002003 infoLog << "Types for interface block '" << blockName
2004 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002005 return false;
2006 }
2007 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2008 {
Jamie Madillf6113162015-05-07 11:49:21 -04002009 infoLog << "Array sizes differ for interface block '" << blockName
2010 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002011 return false;
2012 }
2013 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2014 {
Jamie Madillf6113162015-05-07 11:49:21 -04002015 infoLog << "Layout qualifiers differ for interface block '" << blockName
2016 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017 return false;
2018 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002019 const unsigned int numBlockMembers =
2020 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002021 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2022 {
2023 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2024 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2025 if (vertexMember.name != fragmentMember.name)
2026 {
Jamie Madillf6113162015-05-07 11:49:21 -04002027 infoLog << "Name mismatch for field " << blockMemberIndex
2028 << " of interface block '" << blockName
2029 << "': (in vertex: '" << vertexMember.name
2030 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002031 return false;
2032 }
2033 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2034 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2035 {
2036 return false;
2037 }
2038 }
2039 return true;
2040}
2041
2042bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2043 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2044{
2045 if (vertexVariable.type != fragmentVariable.type)
2046 {
Jamie Madillf6113162015-05-07 11:49:21 -04002047 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002048 return false;
2049 }
2050 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2051 {
Jamie Madillf6113162015-05-07 11:49:21 -04002052 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002053 return false;
2054 }
2055 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2056 {
Jamie Madillf6113162015-05-07 11:49:21 -04002057 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002058 return false;
2059 }
2060
2061 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2062 {
Jamie Madillf6113162015-05-07 11:49:21 -04002063 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064 return false;
2065 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002066 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002067 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2068 {
2069 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2070 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2071
2072 if (vertexMember.name != fragmentMember.name)
2073 {
Jamie Madillf6113162015-05-07 11:49:21 -04002074 infoLog << "Name mismatch for field '" << memberIndex
2075 << "' of " << variableName
2076 << ": (in vertex: '" << vertexMember.name
2077 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002078 return false;
2079 }
2080
2081 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2082 vertexMember.name + "'";
2083
2084 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2085 {
2086 return false;
2087 }
2088 }
2089
2090 return true;
2091}
2092
2093bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2094{
Cooper Partin1acf4382015-06-12 12:38:57 -07002095#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2096 const bool validatePrecision = true;
2097#else
2098 const bool validatePrecision = false;
2099#endif
2100
2101 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002102 {
2103 return false;
2104 }
2105
2106 return true;
2107}
2108
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002109bool Program::linkValidateVaryings(InfoLog &infoLog,
2110 const std::string &varyingName,
2111 const sh::Varying &vertexVarying,
2112 const sh::Varying &fragmentVarying,
2113 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002114{
2115 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2116 {
2117 return false;
2118 }
2119
Jamie Madille9cc4692015-02-19 16:00:13 -05002120 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002121 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002122 infoLog << "Interpolation types for " << varyingName
2123 << " differ between vertex and fragment shaders.";
2124 return false;
2125 }
2126
2127 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2128 {
2129 infoLog << "Invariance for " << varyingName
2130 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 return false;
2132 }
2133
2134 return true;
2135}
2136
Jamie Madillccdf74b2015-08-18 10:46:12 -04002137bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2138 const std::vector<const sh::Varying *> &varyings,
2139 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002140{
2141 size_t totalComponents = 0;
2142
Jamie Madillccdf74b2015-08-18 10:46:12 -04002143 std::set<std::string> uniqueNames;
2144
Jamie Madill48ef11b2016-04-27 15:21:52 -04002145 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 {
2147 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002148 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002149 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002150 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002151 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002152 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002153 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002154 infoLog << "Two transform feedback varyings specify the same output variable ("
2155 << tfVaryingName << ").";
2156 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002157 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002158 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159
Geoff Lang1a683462015-09-29 15:09:59 -04002160 if (varying->isArray())
2161 {
2162 infoLog << "Capture of arrays is undefined and not supported.";
2163 return false;
2164 }
2165
Jamie Madillccdf74b2015-08-18 10:46:12 -04002166 // TODO(jmadill): Investigate implementation limits on D3D11
2167 size_t componentCount = gl::VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002168 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002169 componentCount > caps.maxTransformFeedbackSeparateComponents)
2170 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002171 infoLog << "Transform feedback varying's " << varying->name << " components ("
2172 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002173 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 return false;
2175 }
2176
2177 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 found = true;
2179 break;
2180 }
2181 }
2182
Jamie Madill89bb70e2015-08-31 14:18:39 -04002183 if (tfVaryingName.find('[') != std::string::npos)
2184 {
Geoff Lang1a683462015-09-29 15:09:59 -04002185 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002186 return false;
2187 }
2188
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2190 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04002191 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002192 }
2193
Jamie Madill48ef11b2016-04-27 15:21:52 -04002194 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002195 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002196 {
Jamie Madillf6113162015-05-07 11:49:21 -04002197 infoLog << "Transform feedback varying total components (" << totalComponents
2198 << ") exceed the maximum interleaved components ("
2199 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002200 return false;
2201 }
2202
2203 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002204}
2205
Jamie Madillccdf74b2015-08-18 10:46:12 -04002206void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2207{
2208 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002209 mState.mTransformFeedbackVaryingVars.clear();
2210 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002211 {
2212 for (const sh::Varying *varying : varyings)
2213 {
2214 if (tfVaryingName == varying->name)
2215 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002216 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002217 break;
2218 }
2219 }
2220 }
2221}
2222
2223std::vector<const sh::Varying *> Program::getMergedVaryings() const
2224{
2225 std::set<std::string> uniqueNames;
2226 std::vector<const sh::Varying *> varyings;
2227
Jamie Madill48ef11b2016-04-27 15:21:52 -04002228 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002229 {
2230 if (uniqueNames.count(varying.name) == 0)
2231 {
2232 uniqueNames.insert(varying.name);
2233 varyings.push_back(&varying);
2234 }
2235 }
2236
Jamie Madill48ef11b2016-04-27 15:21:52 -04002237 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002238 {
2239 if (uniqueNames.count(varying.name) == 0)
2240 {
2241 uniqueNames.insert(varying.name);
2242 varyings.push_back(&varying);
2243 }
2244 }
2245
2246 return varyings;
2247}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002248
2249void Program::linkOutputVariables()
2250{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002251 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002252 ASSERT(fragmentShader != nullptr);
2253
2254 // Skip this step for GLES2 shaders.
2255 if (fragmentShader->getShaderVersion() == 100)
2256 return;
2257
Jamie Madilla0a9e122015-09-02 15:54:30 -04002258 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002259
2260 // TODO(jmadill): any caps validation here?
2261
2262 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2263 outputVariableIndex++)
2264 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002265 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002266
2267 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2268 if (outputVariable.isBuiltIn())
2269 continue;
2270
2271 // Since multiple output locations must be specified, use 0 for non-specified locations.
2272 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2273
2274 ASSERT(outputVariable.staticUse);
2275
2276 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2277 elementIndex++)
2278 {
2279 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002280 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002281 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002282 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002283 VariableLocation(outputVariable.name, element, outputVariableIndex);
2284 }
2285 }
2286}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002287
2288bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2289{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002290 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002291 VectorAndSamplerCount vsCounts;
2292
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002293 std::vector<LinkedUniform> samplerUniforms;
2294
Jamie Madill62d31cb2015-09-11 13:25:51 -04002295 for (const sh::Uniform &uniform : vertexShader->getUniforms())
2296 {
2297 if (uniform.staticUse)
2298 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002299 vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002300 }
2301 }
2302
2303 if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
2304 {
2305 infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
2306 << caps.maxVertexUniformVectors << ").";
2307 return false;
2308 }
2309
2310 if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
2311 {
2312 infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
2313 << caps.maxVertexTextureImageUnits << ").";
2314 return false;
2315 }
2316
Jamie Madill48ef11b2016-04-27 15:21:52 -04002317 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002318 VectorAndSamplerCount fsCounts;
2319
2320 for (const sh::Uniform &uniform : fragmentShader->getUniforms())
2321 {
2322 if (uniform.staticUse)
2323 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002324 fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002325 }
2326 }
2327
2328 if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
2329 {
2330 infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
2331 << caps.maxFragmentUniformVectors << ").";
2332 return false;
2333 }
2334
2335 if (fsCounts.samplerCount > caps.maxTextureImageUnits)
2336 {
2337 infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
2338 << caps.maxTextureImageUnits << ").";
2339 return false;
2340 }
2341
Jamie Madill48ef11b2016-04-27 15:21:52 -04002342 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002343 mSamplerUniformRange.end =
2344 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2345
Jamie Madill48ef11b2016-04-27 15:21:52 -04002346 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002347
Jamie Madill62d31cb2015-09-11 13:25:51 -04002348 return true;
2349}
2350
2351Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002352 const std::string &fullName,
2353 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002354{
2355 VectorAndSamplerCount vectorAndSamplerCount;
2356
2357 if (uniform.isStruct())
2358 {
2359 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2360 {
2361 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2362
2363 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2364 {
2365 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2366 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2367
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002368 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002369 }
2370 }
2371
2372 return vectorAndSamplerCount;
2373 }
2374
2375 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002376 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002377 if (!UniformInList(mState.getUniforms(), fullName) &&
2378 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002379 {
2380 gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
2381 uniform.arraySize, -1,
2382 sh::BlockMemberInfo::getDefaultBlockInfo());
2383 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002384
2385 // Store sampler uniforms separately, so we'll append them to the end of the list.
2386 if (isSampler)
2387 {
2388 samplerUniforms->push_back(linkedUniform);
2389 }
2390 else
2391 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002392 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002393 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002394 }
2395
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002396 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002397
2398 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2399 // Likewise, don't count "real" uniforms towards sampler count.
2400 vectorAndSamplerCount.vectorCount =
2401 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002402 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002403
2404 return vectorAndSamplerCount;
2405}
2406
2407void Program::gatherInterfaceBlockInfo()
2408{
2409 std::set<std::string> visitedList;
2410
Jamie Madill48ef11b2016-04-27 15:21:52 -04002411 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002412
Jamie Madill48ef11b2016-04-27 15:21:52 -04002413 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002414 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2415 {
2416 // Only 'packed' blocks are allowed to be considered inacive.
2417 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2418 continue;
2419
2420 if (visitedList.count(vertexBlock.name) > 0)
2421 continue;
2422
2423 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2424 visitedList.insert(vertexBlock.name);
2425 }
2426
Jamie Madill48ef11b2016-04-27 15:21:52 -04002427 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002428
2429 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2430 {
2431 // Only 'packed' blocks are allowed to be considered inacive.
2432 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2433 continue;
2434
2435 if (visitedList.count(fragmentBlock.name) > 0)
2436 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002437 for (gl::UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002438 {
2439 if (block.name == fragmentBlock.name)
2440 {
2441 block.fragmentStaticUse = fragmentBlock.staticUse;
2442 }
2443 }
2444
2445 continue;
2446 }
2447
2448 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2449 visitedList.insert(fragmentBlock.name);
2450 }
2451}
2452
Jamie Madill4a3c2342015-10-08 12:58:45 -04002453template <typename VarT>
2454void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2455 const std::string &prefix,
2456 int blockIndex)
2457{
2458 for (const VarT &field : fields)
2459 {
2460 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2461
2462 if (field.isStruct())
2463 {
2464 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2465 {
2466 const std::string uniformElementName =
2467 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2468 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2469 }
2470 }
2471 else
2472 {
2473 // If getBlockMemberInfo returns false, the uniform is optimized out.
2474 sh::BlockMemberInfo memberInfo;
2475 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2476 {
2477 continue;
2478 }
2479
2480 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2481 blockIndex, memberInfo);
2482
2483 // Since block uniforms have no location, we don't need to store them in the uniform
2484 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002485 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002486 }
2487 }
2488}
2489
Jamie Madill62d31cb2015-09-11 13:25:51 -04002490void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2491{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002492 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002493 size_t blockSize = 0;
2494
2495 // Don't define this block at all if it's not active in the implementation.
2496 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2497 {
2498 return;
2499 }
2500
2501 // Track the first and last uniform index to determine the range of active uniforms in the
2502 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002503 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002504 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002505 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002506
2507 std::vector<unsigned int> blockUniformIndexes;
2508 for (size_t blockUniformIndex = firstBlockUniformIndex;
2509 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2510 {
2511 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2512 }
2513
2514 if (interfaceBlock.arraySize > 0)
2515 {
2516 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2517 {
2518 UniformBlock block(interfaceBlock.name, true, arrayElement);
2519 block.memberUniformIndexes = blockUniformIndexes;
2520
2521 if (shaderType == GL_VERTEX_SHADER)
2522 {
2523 block.vertexStaticUse = interfaceBlock.staticUse;
2524 }
2525 else
2526 {
2527 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2528 block.fragmentStaticUse = interfaceBlock.staticUse;
2529 }
2530
Jamie Madill4a3c2342015-10-08 12:58:45 -04002531 // TODO(jmadill): Determine if we can ever have an inactive array element block.
2532 size_t blockElementSize = 0;
2533 if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
2534 {
2535 continue;
2536 }
2537
2538 ASSERT(blockElementSize == blockSize);
2539 block.dataSize = static_cast<unsigned int>(blockElementSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002540 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002541 }
2542 }
2543 else
2544 {
2545 UniformBlock block(interfaceBlock.name, false, 0);
2546 block.memberUniformIndexes = blockUniformIndexes;
2547
2548 if (shaderType == GL_VERTEX_SHADER)
2549 {
2550 block.vertexStaticUse = interfaceBlock.staticUse;
2551 }
2552 else
2553 {
2554 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2555 block.fragmentStaticUse = interfaceBlock.staticUse;
2556 }
2557
Jamie Madill4a3c2342015-10-08 12:58:45 -04002558 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002559 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002560 }
2561}
2562
2563template <typename T>
2564void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
2565{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002566 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2567 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002568 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2569
2570 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2571 {
2572 // Do a cast conversion for boolean types. From the spec:
2573 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2574 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
2575 for (GLsizei component = 0; component < count; ++component)
2576 {
2577 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2578 }
2579 }
2580 else
2581 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002582 // Invalide the validation cache if we modify the sampler data.
2583 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
2584 {
2585 mCachedValidateSamplersResult.reset();
2586 }
2587
Jamie Madill62d31cb2015-09-11 13:25:51 -04002588 memcpy(destPointer, v, sizeof(T) * count);
2589 }
2590}
2591
2592template <size_t cols, size_t rows, typename T>
2593void Program::setMatrixUniformInternal(GLint location,
2594 GLsizei count,
2595 GLboolean transpose,
2596 const T *v)
2597{
2598 if (!transpose)
2599 {
2600 setUniformInternal(location, count * cols * rows, v);
2601 return;
2602 }
2603
2604 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002605 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2606 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002607 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
2608 for (GLsizei element = 0; element < count; ++element)
2609 {
2610 size_t elementOffset = element * rows * cols;
2611
2612 for (size_t row = 0; row < rows; ++row)
2613 {
2614 for (size_t col = 0; col < cols; ++col)
2615 {
2616 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2617 }
2618 }
2619 }
2620}
2621
2622template <typename DestT>
2623void Program::getUniformInternal(GLint location, DestT *dataOut) const
2624{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002625 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2626 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002627
2628 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2629
2630 GLenum componentType = VariableComponentType(uniform.type);
2631 if (componentType == GLTypeToGLenum<DestT>::value)
2632 {
2633 memcpy(dataOut, srcPointer, uniform.getElementSize());
2634 return;
2635 }
2636
Corentin Wallez6596c462016-03-17 17:26:58 -04002637 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002638
2639 switch (componentType)
2640 {
2641 case GL_INT:
2642 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2643 break;
2644 case GL_UNSIGNED_INT:
2645 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2646 break;
2647 case GL_BOOL:
2648 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2649 break;
2650 case GL_FLOAT:
2651 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2652 break;
2653 default:
2654 UNREACHABLE();
2655 }
2656}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002657}