blob: 65cde2fc7e37b90454eb9264f63a637ca327b8ea [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{
Jamie Madill4cff2472015-08-21 16:53:18 -04001631 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1632 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633
Jamie Madill4cff2472015-08-21 16:53:18 -04001634 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001635 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636 bool matched = false;
1637
1638 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001639 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001640 {
1641 continue;
1642 }
1643
Jamie Madill4cff2472015-08-21 16:53:18 -04001644 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001645 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001646 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001648 ASSERT(!input.isBuiltIn());
1649 if (!linkValidateVaryings(infoLog, output.name, input, output))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650 {
1651 return false;
1652 }
1653
Geoff Lang7dd2e102014-11-10 15:19:26 -05001654 matched = true;
1655 break;
1656 }
1657 }
1658
1659 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001660 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001661 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001662 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001663 return false;
1664 }
1665 }
1666
Jamie Madillada9ecc2015-08-17 12:53:37 -04001667 // TODO(jmadill): verify no unmatched vertex varyings?
1668
Geoff Lang7dd2e102014-11-10 15:19:26 -05001669 return true;
1670}
1671
Geoff Langd8605522016-04-13 10:19:12 -04001672bool Program::linkUniforms(gl::InfoLog &infoLog,
1673 const gl::Caps &caps,
1674 const Bindings &uniformBindings)
Jamie Madillea918db2015-08-18 14:48:59 -04001675{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001676 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1677 const std::vector<sh::Uniform> &fragmentUniforms =
1678 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001679
1680 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill62d31cb2015-09-11 13:25:51 -04001681 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madillea918db2015-08-18 14:48:59 -04001682
1683 for (const sh::Uniform &vertexUniform : vertexUniforms)
1684 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001685 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001686 }
1687
1688 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1689 {
1690 auto entry = linkedUniforms.find(fragmentUniform.name);
1691 if (entry != linkedUniforms.end())
1692 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001693 LinkedUniform *vertexUniform = &entry->second;
1694 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1695 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001696 {
1697 return false;
1698 }
1699 }
1700 }
1701
Jamie Madill62d31cb2015-09-11 13:25:51 -04001702 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1703 // Also check the maximum uniform vector and sampler counts.
1704 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1705 {
1706 return false;
1707 }
1708
Geoff Langd8605522016-04-13 10:19:12 -04001709 if (!indexUniforms(infoLog, caps, uniformBindings))
1710 {
1711 return false;
1712 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001713
Jamie Madillea918db2015-08-18 14:48:59 -04001714 return true;
1715}
1716
Geoff Langd8605522016-04-13 10:19:12 -04001717bool Program::indexUniforms(gl::InfoLog &infoLog,
1718 const gl::Caps &caps,
1719 const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001720{
Geoff Langd8605522016-04-13 10:19:12 -04001721 // Uniforms awaiting a location
1722 std::vector<VariableLocation> unboundUniforms;
1723 std::map<GLuint, VariableLocation> boundUniforms;
1724 int maxUniformLocation = -1;
1725
1726 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001727 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001728 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001729 const gl::LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001730
Geoff Langd8605522016-04-13 10:19:12 -04001731 if (uniform.isBuiltIn())
1732 {
1733 continue;
1734 }
1735
1736 int bindingLocation = uniformBindings.getBinding(uniform.name);
1737
1738 // Verify that this location isn't bound twice
1739 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1740 {
1741 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1742 return false;
1743 }
1744
Jamie Madill62d31cb2015-09-11 13:25:51 -04001745 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1746 {
Geoff Langd8605522016-04-13 10:19:12 -04001747 VariableLocation location(uniform.name, arrayIndex,
1748 static_cast<unsigned int>(uniformIndex));
1749
1750 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001751 {
Geoff Langd8605522016-04-13 10:19:12 -04001752 boundUniforms[bindingLocation] = location;
1753 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1754 }
1755 else
1756 {
1757 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001758 }
1759 }
1760 }
Geoff Langd8605522016-04-13 10:19:12 -04001761
1762 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1763 // not be assigned to those locations.
1764 std::set<GLuint> reservedLocations;
1765 for (const auto &binding : uniformBindings)
1766 {
1767 GLuint location = binding.second;
1768 if (boundUniforms.find(location) == boundUniforms.end())
1769 {
1770 reservedLocations.insert(location);
1771 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1772 }
1773 }
1774
1775 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04001776 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04001777 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
1778 static_cast<size_t>(maxUniformLocation + 1)));
1779
1780 // Assign bound uniforms
1781 for (const auto &boundUniform : boundUniforms)
1782 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001783 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04001784 }
1785
1786 // Assign reserved uniforms
1787 for (const auto &reservedLocation : reservedLocations)
1788 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001789 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04001790 }
1791
1792 // Assign unbound uniforms
1793 size_t nextUniformLocation = 0;
1794 for (const auto &unboundUniform : unboundUniforms)
1795 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001796 while (mState.mUniformLocations[nextUniformLocation].used ||
1797 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04001798 {
1799 nextUniformLocation++;
1800 }
1801
Jamie Madill48ef11b2016-04-27 15:21:52 -04001802 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
1803 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04001804 nextUniformLocation++;
1805 }
1806
1807 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04001808}
1809
Geoff Lang7dd2e102014-11-10 15:19:26 -05001810bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1811{
Jamie Madillc4c744222015-11-04 09:39:47 -05001812 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1813 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001814 {
1815 return false;
1816 }
1817
1818 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1819 {
Jamie Madillf6113162015-05-07 11:49:21 -04001820 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001821 return false;
1822 }
1823
1824 return true;
1825}
1826
1827// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill9082b982016-04-27 15:21:51 -04001828bool Program::linkAttributes(const ContextState &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001829 InfoLog &infoLog,
Geoff Langd8605522016-04-13 10:19:12 -04001830 const Bindings &attributeBindings,
Jamie Madill3da79b72015-04-27 11:09:17 -04001831 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001832{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001833 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001834 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001835 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04001836
1837 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001838 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001839 {
Jamie Madillf6113162015-05-07 11:49:21 -04001840 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001841 return false;
1842 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001843
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001844 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001845
Jamie Madillc349ec02015-08-21 16:53:12 -04001846 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001847 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001848 {
1849 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05001850 ASSERT(attribute.staticUse);
1851
Geoff Langd8605522016-04-13 10:19:12 -04001852 int bindingLocation = attributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04001853 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04001854 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001855 attribute.location = bindingLocation;
1856 }
1857
1858 if (attribute.location != -1)
1859 {
1860 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04001861 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001862
Jamie Madill63805b42015-08-25 13:17:39 -04001863 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001864 {
Jamie Madillf6113162015-05-07 11:49:21 -04001865 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04001866 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001867
1868 return false;
1869 }
1870
Jamie Madill63805b42015-08-25 13:17:39 -04001871 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001872 {
Jamie Madill63805b42015-08-25 13:17:39 -04001873 const int regLocation = attribute.location + reg;
1874 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875
1876 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001877 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04001878 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001879 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001880 // TODO(jmadill): fix aliasing on ES2
1881 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001883 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04001884 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885 return false;
1886 }
1887 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001888 else
1889 {
Jamie Madill63805b42015-08-25 13:17:39 -04001890 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04001891 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001892
Jamie Madill63805b42015-08-25 13:17:39 -04001893 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 }
1895 }
1896 }
1897
1898 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001899 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001900 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001901 ASSERT(attribute.staticUse);
1902
Jamie Madillc349ec02015-08-21 16:53:12 -04001903 // Not set by glBindAttribLocation or by location layout qualifier
1904 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001905 {
Jamie Madill63805b42015-08-25 13:17:39 -04001906 int regs = VariableRegisterCount(attribute.type);
1907 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001908
Jamie Madill63805b42015-08-25 13:17:39 -04001909 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001910 {
Jamie Madillf6113162015-05-07 11:49:21 -04001911 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04001912 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001913 }
1914
Jamie Madillc349ec02015-08-21 16:53:12 -04001915 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001916 }
1917 }
1918
Jamie Madill48ef11b2016-04-27 15:21:52 -04001919 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001920 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001921 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04001922 ASSERT(attribute.location != -1);
1923 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04001924
Jamie Madill63805b42015-08-25 13:17:39 -04001925 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001926 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001927 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001928 }
1929 }
1930
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931 return true;
1932}
1933
Jamie Madille473dee2015-08-18 14:49:01 -04001934bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001935{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001936 const Shader &vertexShader = *mState.mAttachedVertexShader;
1937 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
Jamie Madille473dee2015-08-18 14:49:01 -04001938
Geoff Lang7dd2e102014-11-10 15:19:26 -05001939 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1940 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madille473dee2015-08-18 14:49:01 -04001941
Geoff Lang7dd2e102014-11-10 15:19:26 -05001942 // Check that interface blocks defined in the vertex and fragment shaders are identical
1943 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1944 UniformBlockMap linkedUniformBlocks;
Jamie Madille473dee2015-08-18 14:49:01 -04001945
1946 GLuint vertexBlockCount = 0;
1947 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001948 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001949 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jamie Madille473dee2015-08-18 14:49:01 -04001950
1951 // Note: shared and std140 layouts are always considered active
1952 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1953 {
1954 if (++vertexBlockCount > caps.maxVertexUniformBlocks)
1955 {
1956 infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
1957 << caps.maxVertexUniformBlocks << ")";
1958 return false;
1959 }
1960 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001961 }
Jamie Madille473dee2015-08-18 14:49:01 -04001962
1963 GLuint fragmentBlockCount = 0;
1964 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001965 {
Jamie Madille473dee2015-08-18 14:49:01 -04001966 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001967 if (entry != linkedUniformBlocks.end())
1968 {
1969 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1970 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1971 {
1972 return false;
1973 }
1974 }
Jamie Madille473dee2015-08-18 14:49:01 -04001975
Geoff Lang7dd2e102014-11-10 15:19:26 -05001976 // Note: shared and std140 layouts are always considered active
Jamie Madille473dee2015-08-18 14:49:01 -04001977 if (fragmentInterfaceBlock.staticUse ||
1978 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001979 {
Jamie Madille473dee2015-08-18 14:49:01 -04001980 if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001981 {
Jamie Madille473dee2015-08-18 14:49:01 -04001982 infoLog
1983 << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
1984 << caps.maxFragmentUniformBlocks << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001985 return false;
1986 }
1987 }
1988 }
Jamie Madille473dee2015-08-18 14:49:01 -04001989
Geoff Lang7dd2e102014-11-10 15:19:26 -05001990 return true;
1991}
1992
1993bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1994 const sh::InterfaceBlock &fragmentInterfaceBlock)
1995{
1996 const char* blockName = vertexInterfaceBlock.name.c_str();
1997 // validate blocks for the same member types
1998 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1999 {
Jamie Madillf6113162015-05-07 11:49:21 -04002000 infoLog << "Types for interface block '" << blockName
2001 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002002 return false;
2003 }
2004 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2005 {
Jamie Madillf6113162015-05-07 11:49:21 -04002006 infoLog << "Array sizes differ for interface block '" << blockName
2007 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002008 return false;
2009 }
2010 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2011 {
Jamie Madillf6113162015-05-07 11:49:21 -04002012 infoLog << "Layout qualifiers differ for interface block '" << blockName
2013 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002014 return false;
2015 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002016 const unsigned int numBlockMembers =
2017 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002018 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2019 {
2020 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2021 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2022 if (vertexMember.name != fragmentMember.name)
2023 {
Jamie Madillf6113162015-05-07 11:49:21 -04002024 infoLog << "Name mismatch for field " << blockMemberIndex
2025 << " of interface block '" << blockName
2026 << "': (in vertex: '" << vertexMember.name
2027 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002028 return false;
2029 }
2030 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2031 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2032 {
2033 return false;
2034 }
2035 }
2036 return true;
2037}
2038
2039bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2040 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2041{
2042 if (vertexVariable.type != fragmentVariable.type)
2043 {
Jamie Madillf6113162015-05-07 11:49:21 -04002044 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045 return false;
2046 }
2047 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2048 {
Jamie Madillf6113162015-05-07 11:49:21 -04002049 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002050 return false;
2051 }
2052 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2053 {
Jamie Madillf6113162015-05-07 11:49:21 -04002054 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002055 return false;
2056 }
2057
2058 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2059 {
Jamie Madillf6113162015-05-07 11:49:21 -04002060 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002061 return false;
2062 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002063 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2065 {
2066 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2067 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2068
2069 if (vertexMember.name != fragmentMember.name)
2070 {
Jamie Madillf6113162015-05-07 11:49:21 -04002071 infoLog << "Name mismatch for field '" << memberIndex
2072 << "' of " << variableName
2073 << ": (in vertex: '" << vertexMember.name
2074 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002075 return false;
2076 }
2077
2078 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2079 vertexMember.name + "'";
2080
2081 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2082 {
2083 return false;
2084 }
2085 }
2086
2087 return true;
2088}
2089
2090bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2091{
Cooper Partin1acf4382015-06-12 12:38:57 -07002092#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2093 const bool validatePrecision = true;
2094#else
2095 const bool validatePrecision = false;
2096#endif
2097
2098 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002099 {
2100 return false;
2101 }
2102
2103 return true;
2104}
2105
2106bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
2107{
2108 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2109 {
2110 return false;
2111 }
2112
Jamie Madille9cc4692015-02-19 16:00:13 -05002113 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002114 {
Jamie Madillf6113162015-05-07 11:49:21 -04002115 infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002116 return false;
2117 }
2118
2119 return true;
2120}
2121
Jamie Madillccdf74b2015-08-18 10:46:12 -04002122bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2123 const std::vector<const sh::Varying *> &varyings,
2124 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002125{
2126 size_t totalComponents = 0;
2127
Jamie Madillccdf74b2015-08-18 10:46:12 -04002128 std::set<std::string> uniqueNames;
2129
Jamie Madill48ef11b2016-04-27 15:21:52 -04002130 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 {
2132 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002133 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002134 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002135 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002136 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002137 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002138 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002139 infoLog << "Two transform feedback varyings specify the same output variable ("
2140 << tfVaryingName << ").";
2141 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002142 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002143 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144
Geoff Lang1a683462015-09-29 15:09:59 -04002145 if (varying->isArray())
2146 {
2147 infoLog << "Capture of arrays is undefined and not supported.";
2148 return false;
2149 }
2150
Jamie Madillccdf74b2015-08-18 10:46:12 -04002151 // TODO(jmadill): Investigate implementation limits on D3D11
2152 size_t componentCount = gl::VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002153 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002154 componentCount > caps.maxTransformFeedbackSeparateComponents)
2155 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002156 infoLog << "Transform feedback varying's " << varying->name << " components ("
2157 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002158 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159 return false;
2160 }
2161
2162 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002163 found = true;
2164 break;
2165 }
2166 }
2167
Jamie Madill89bb70e2015-08-31 14:18:39 -04002168 if (tfVaryingName.find('[') != std::string::npos)
2169 {
Geoff Lang1a683462015-09-29 15:09:59 -04002170 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002171 return false;
2172 }
2173
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2175 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04002176 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002177 }
2178
Jamie Madill48ef11b2016-04-27 15:21:52 -04002179 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002180 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002181 {
Jamie Madillf6113162015-05-07 11:49:21 -04002182 infoLog << "Transform feedback varying total components (" << totalComponents
2183 << ") exceed the maximum interleaved components ("
2184 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185 return false;
2186 }
2187
2188 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002189}
2190
Jamie Madillccdf74b2015-08-18 10:46:12 -04002191void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2192{
2193 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002194 mState.mTransformFeedbackVaryingVars.clear();
2195 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002196 {
2197 for (const sh::Varying *varying : varyings)
2198 {
2199 if (tfVaryingName == varying->name)
2200 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002201 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002202 break;
2203 }
2204 }
2205 }
2206}
2207
2208std::vector<const sh::Varying *> Program::getMergedVaryings() const
2209{
2210 std::set<std::string> uniqueNames;
2211 std::vector<const sh::Varying *> varyings;
2212
Jamie Madill48ef11b2016-04-27 15:21:52 -04002213 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002214 {
2215 if (uniqueNames.count(varying.name) == 0)
2216 {
2217 uniqueNames.insert(varying.name);
2218 varyings.push_back(&varying);
2219 }
2220 }
2221
Jamie Madill48ef11b2016-04-27 15:21:52 -04002222 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002223 {
2224 if (uniqueNames.count(varying.name) == 0)
2225 {
2226 uniqueNames.insert(varying.name);
2227 varyings.push_back(&varying);
2228 }
2229 }
2230
2231 return varyings;
2232}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002233
2234void Program::linkOutputVariables()
2235{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002236 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002237 ASSERT(fragmentShader != nullptr);
2238
2239 // Skip this step for GLES2 shaders.
2240 if (fragmentShader->getShaderVersion() == 100)
2241 return;
2242
Jamie Madilla0a9e122015-09-02 15:54:30 -04002243 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002244
2245 // TODO(jmadill): any caps validation here?
2246
2247 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2248 outputVariableIndex++)
2249 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002250 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002251
2252 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2253 if (outputVariable.isBuiltIn())
2254 continue;
2255
2256 // Since multiple output locations must be specified, use 0 for non-specified locations.
2257 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2258
2259 ASSERT(outputVariable.staticUse);
2260
2261 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2262 elementIndex++)
2263 {
2264 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002265 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002266 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002267 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002268 VariableLocation(outputVariable.name, element, outputVariableIndex);
2269 }
2270 }
2271}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002272
2273bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2274{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002275 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002276 VectorAndSamplerCount vsCounts;
2277
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002278 std::vector<LinkedUniform> samplerUniforms;
2279
Jamie Madill62d31cb2015-09-11 13:25:51 -04002280 for (const sh::Uniform &uniform : vertexShader->getUniforms())
2281 {
2282 if (uniform.staticUse)
2283 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002284 vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002285 }
2286 }
2287
2288 if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
2289 {
2290 infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
2291 << caps.maxVertexUniformVectors << ").";
2292 return false;
2293 }
2294
2295 if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
2296 {
2297 infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
2298 << caps.maxVertexTextureImageUnits << ").";
2299 return false;
2300 }
2301
Jamie Madill48ef11b2016-04-27 15:21:52 -04002302 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002303 VectorAndSamplerCount fsCounts;
2304
2305 for (const sh::Uniform &uniform : fragmentShader->getUniforms())
2306 {
2307 if (uniform.staticUse)
2308 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002309 fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002310 }
2311 }
2312
2313 if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
2314 {
2315 infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
2316 << caps.maxFragmentUniformVectors << ").";
2317 return false;
2318 }
2319
2320 if (fsCounts.samplerCount > caps.maxTextureImageUnits)
2321 {
2322 infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
2323 << caps.maxTextureImageUnits << ").";
2324 return false;
2325 }
2326
Jamie Madill48ef11b2016-04-27 15:21:52 -04002327 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002328 mSamplerUniformRange.end =
2329 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2330
Jamie Madill48ef11b2016-04-27 15:21:52 -04002331 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002332
Jamie Madill62d31cb2015-09-11 13:25:51 -04002333 return true;
2334}
2335
2336Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002337 const std::string &fullName,
2338 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002339{
2340 VectorAndSamplerCount vectorAndSamplerCount;
2341
2342 if (uniform.isStruct())
2343 {
2344 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2345 {
2346 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2347
2348 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2349 {
2350 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2351 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2352
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002353 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002354 }
2355 }
2356
2357 return vectorAndSamplerCount;
2358 }
2359
2360 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002361 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002362 if (!UniformInList(mState.getUniforms(), fullName) &&
2363 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002364 {
2365 gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
2366 uniform.arraySize, -1,
2367 sh::BlockMemberInfo::getDefaultBlockInfo());
2368 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002369
2370 // Store sampler uniforms separately, so we'll append them to the end of the list.
2371 if (isSampler)
2372 {
2373 samplerUniforms->push_back(linkedUniform);
2374 }
2375 else
2376 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002377 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002378 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002379 }
2380
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002381 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002382
2383 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2384 // Likewise, don't count "real" uniforms towards sampler count.
2385 vectorAndSamplerCount.vectorCount =
2386 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002387 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002388
2389 return vectorAndSamplerCount;
2390}
2391
2392void Program::gatherInterfaceBlockInfo()
2393{
2394 std::set<std::string> visitedList;
2395
Jamie Madill48ef11b2016-04-27 15:21:52 -04002396 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002397
Jamie Madill48ef11b2016-04-27 15:21:52 -04002398 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002399 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2400 {
2401 // Only 'packed' blocks are allowed to be considered inacive.
2402 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2403 continue;
2404
2405 if (visitedList.count(vertexBlock.name) > 0)
2406 continue;
2407
2408 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2409 visitedList.insert(vertexBlock.name);
2410 }
2411
Jamie Madill48ef11b2016-04-27 15:21:52 -04002412 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002413
2414 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2415 {
2416 // Only 'packed' blocks are allowed to be considered inacive.
2417 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2418 continue;
2419
2420 if (visitedList.count(fragmentBlock.name) > 0)
2421 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002422 for (gl::UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002423 {
2424 if (block.name == fragmentBlock.name)
2425 {
2426 block.fragmentStaticUse = fragmentBlock.staticUse;
2427 }
2428 }
2429
2430 continue;
2431 }
2432
2433 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2434 visitedList.insert(fragmentBlock.name);
2435 }
2436}
2437
Jamie Madill4a3c2342015-10-08 12:58:45 -04002438template <typename VarT>
2439void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2440 const std::string &prefix,
2441 int blockIndex)
2442{
2443 for (const VarT &field : fields)
2444 {
2445 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2446
2447 if (field.isStruct())
2448 {
2449 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2450 {
2451 const std::string uniformElementName =
2452 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2453 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2454 }
2455 }
2456 else
2457 {
2458 // If getBlockMemberInfo returns false, the uniform is optimized out.
2459 sh::BlockMemberInfo memberInfo;
2460 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2461 {
2462 continue;
2463 }
2464
2465 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2466 blockIndex, memberInfo);
2467
2468 // Since block uniforms have no location, we don't need to store them in the uniform
2469 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002470 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002471 }
2472 }
2473}
2474
Jamie Madill62d31cb2015-09-11 13:25:51 -04002475void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2476{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002477 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002478 size_t blockSize = 0;
2479
2480 // Don't define this block at all if it's not active in the implementation.
2481 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2482 {
2483 return;
2484 }
2485
2486 // Track the first and last uniform index to determine the range of active uniforms in the
2487 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002488 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002489 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002490 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002491
2492 std::vector<unsigned int> blockUniformIndexes;
2493 for (size_t blockUniformIndex = firstBlockUniformIndex;
2494 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2495 {
2496 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2497 }
2498
2499 if (interfaceBlock.arraySize > 0)
2500 {
2501 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2502 {
2503 UniformBlock block(interfaceBlock.name, true, arrayElement);
2504 block.memberUniformIndexes = blockUniformIndexes;
2505
2506 if (shaderType == GL_VERTEX_SHADER)
2507 {
2508 block.vertexStaticUse = interfaceBlock.staticUse;
2509 }
2510 else
2511 {
2512 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2513 block.fragmentStaticUse = interfaceBlock.staticUse;
2514 }
2515
Jamie Madill4a3c2342015-10-08 12:58:45 -04002516 // TODO(jmadill): Determine if we can ever have an inactive array element block.
2517 size_t blockElementSize = 0;
2518 if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
2519 {
2520 continue;
2521 }
2522
2523 ASSERT(blockElementSize == blockSize);
2524 block.dataSize = static_cast<unsigned int>(blockElementSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002525 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002526 }
2527 }
2528 else
2529 {
2530 UniformBlock block(interfaceBlock.name, false, 0);
2531 block.memberUniformIndexes = blockUniformIndexes;
2532
2533 if (shaderType == GL_VERTEX_SHADER)
2534 {
2535 block.vertexStaticUse = interfaceBlock.staticUse;
2536 }
2537 else
2538 {
2539 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2540 block.fragmentStaticUse = interfaceBlock.staticUse;
2541 }
2542
Jamie Madill4a3c2342015-10-08 12:58:45 -04002543 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002544 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002545 }
2546}
2547
2548template <typename T>
2549void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
2550{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002551 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2552 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002553 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2554
2555 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2556 {
2557 // Do a cast conversion for boolean types. From the spec:
2558 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2559 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
2560 for (GLsizei component = 0; component < count; ++component)
2561 {
2562 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2563 }
2564 }
2565 else
2566 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002567 // Invalide the validation cache if we modify the sampler data.
2568 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
2569 {
2570 mCachedValidateSamplersResult.reset();
2571 }
2572
Jamie Madill62d31cb2015-09-11 13:25:51 -04002573 memcpy(destPointer, v, sizeof(T) * count);
2574 }
2575}
2576
2577template <size_t cols, size_t rows, typename T>
2578void Program::setMatrixUniformInternal(GLint location,
2579 GLsizei count,
2580 GLboolean transpose,
2581 const T *v)
2582{
2583 if (!transpose)
2584 {
2585 setUniformInternal(location, count * cols * rows, v);
2586 return;
2587 }
2588
2589 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002590 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2591 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002592 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
2593 for (GLsizei element = 0; element < count; ++element)
2594 {
2595 size_t elementOffset = element * rows * cols;
2596
2597 for (size_t row = 0; row < rows; ++row)
2598 {
2599 for (size_t col = 0; col < cols; ++col)
2600 {
2601 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2602 }
2603 }
2604 }
2605}
2606
2607template <typename DestT>
2608void Program::getUniformInternal(GLint location, DestT *dataOut) const
2609{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002610 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2611 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002612
2613 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2614
2615 GLenum componentType = VariableComponentType(uniform.type);
2616 if (componentType == GLTypeToGLenum<DestT>::value)
2617 {
2618 memcpy(dataOut, srcPointer, uniform.getElementSize());
2619 return;
2620 }
2621
Corentin Wallez6596c462016-03-17 17:26:58 -04002622 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002623
2624 switch (componentType)
2625 {
2626 case GL_INT:
2627 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2628 break;
2629 case GL_UNSIGNED_INT:
2630 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2631 break;
2632 case GL_BOOL:
2633 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2634 break;
2635 case GL_FLOAT:
2636 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2637 break;
2638 default:
2639 UNREACHABLE();
2640 }
2641}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002642}