blob: 47c730b6c6c9a8f982add63841d9d73cdd60febf [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
Jamie Madill48ef11b2016-04-27 15:21:52 -0400465 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mState.mAttachedVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500466 {
467 return Error(GL_NO_ERROR);
468 }
469
Jamie Madill48ef11b2016-04-27 15:21:52 -0400470 if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
Jamie Madillada9ecc2015-08-17 12:53:37 -0400471 {
472 return Error(GL_NO_ERROR);
473 }
474
Geoff Langd8605522016-04-13 10:19:12 -0400475 if (!linkUniforms(mInfoLog, *data.caps, mUniformBindings))
Jamie Madillea918db2015-08-18 14:48:59 -0400476 {
477 return Error(GL_NO_ERROR);
478 }
479
Jamie Madille473dee2015-08-18 14:49:01 -0400480 if (!linkUniformBlocks(mInfoLog, *data.caps))
481 {
482 return Error(GL_NO_ERROR);
483 }
484
Jamie Madillccdf74b2015-08-18 10:46:12 -0400485 const auto &mergedVaryings = getMergedVaryings();
486
487 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps))
488 {
489 return Error(GL_NO_ERROR);
490 }
491
Jamie Madill80a6fc02015-08-21 16:53:16 -0400492 linkOutputVariables();
493
Jamie Madillf5f4ad22015-09-02 18:32:38 +0000494 rx::LinkResult result = mProgram->link(data, mInfoLog);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500495 if (result.error.isError() || !result.linkSuccess)
496 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500497 return result.error;
498 }
499
Jamie Madillccdf74b2015-08-18 10:46:12 -0400500 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill4a3c2342015-10-08 12:58:45 -0400501 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400502
Geoff Lang7dd2e102014-11-10 15:19:26 -0500503 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400504 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000505}
506
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000507// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508void Program::unlink(bool destroy)
509{
510 if (destroy) // Object being destructed
511 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400512 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400514 mState.mAttachedFragmentShader->release();
515 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516 }
517
Jamie Madill48ef11b2016-04-27 15:21:52 -0400518 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400520 mState.mAttachedVertexShader->release();
521 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523 }
524
Jamie Madill48ef11b2016-04-27 15:21:52 -0400525 mState.mAttributes.clear();
526 mState.mActiveAttribLocationsMask.reset();
527 mState.mTransformFeedbackVaryingVars.clear();
528 mState.mUniforms.clear();
529 mState.mUniformLocations.clear();
530 mState.mUniformBlocks.clear();
531 mState.mOutputVariables.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500532
Geoff Lang7dd2e102014-11-10 15:19:26 -0500533 mValidated = false;
534
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000535 mLinked = false;
536}
537
Geoff Lange1a27752015-10-05 13:16:04 -0400538bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000539{
540 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541}
542
Geoff Lang7dd2e102014-11-10 15:19:26 -0500543Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000544{
545 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000546
Geoff Lang7dd2e102014-11-10 15:19:26 -0500547#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
548 return Error(GL_NO_ERROR);
549#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400550 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
551 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000552 {
Jamie Madillf6113162015-05-07 11:49:21 -0400553 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500554 return Error(GL_NO_ERROR);
555 }
556
Geoff Langc46cc2f2015-10-01 17:16:20 -0400557 BinaryInputStream stream(binary, length);
558
Geoff Lang7dd2e102014-11-10 15:19:26 -0500559 int majorVersion = stream.readInt<int>();
560 int minorVersion = stream.readInt<int>();
561 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
562 {
Jamie Madillf6113162015-05-07 11:49:21 -0400563 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500564 return Error(GL_NO_ERROR);
565 }
566
567 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
568 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
569 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
570 {
Jamie Madillf6113162015-05-07 11:49:21 -0400571 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500572 return Error(GL_NO_ERROR);
573 }
574
Jamie Madill63805b42015-08-25 13:17:39 -0400575 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
576 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400577 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500578
Jamie Madill3da79b72015-04-27 11:09:17 -0400579 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400580 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400581 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
582 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400583 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400584 LoadShaderVar(&stream, &attrib);
585 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400586 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400587 }
588
Jamie Madill62d31cb2015-09-11 13:25:51 -0400589 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400590 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400591 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
592 {
593 LinkedUniform uniform;
594 LoadShaderVar(&stream, &uniform);
595
596 uniform.blockIndex = stream.readInt<int>();
597 uniform.blockInfo.offset = stream.readInt<int>();
598 uniform.blockInfo.arrayStride = stream.readInt<int>();
599 uniform.blockInfo.matrixStride = stream.readInt<int>();
600 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
601
Jamie Madill48ef11b2016-04-27 15:21:52 -0400602 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400603 }
604
605 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400606 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400607 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
608 uniformIndexIndex++)
609 {
610 VariableLocation variable;
611 stream.readString(&variable.name);
612 stream.readInt(&variable.element);
613 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400614 stream.readBool(&variable.used);
615 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400616
Jamie Madill48ef11b2016-04-27 15:21:52 -0400617 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400618 }
619
620 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400621 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400622 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
623 ++uniformBlockIndex)
624 {
625 UniformBlock uniformBlock;
626 stream.readString(&uniformBlock.name);
627 stream.readBool(&uniformBlock.isArray);
628 stream.readInt(&uniformBlock.arrayElement);
629 stream.readInt(&uniformBlock.dataSize);
630 stream.readBool(&uniformBlock.vertexStaticUse);
631 stream.readBool(&uniformBlock.fragmentStaticUse);
632
633 unsigned int numMembers = stream.readInt<unsigned int>();
634 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
635 {
636 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
637 }
638
Jamie Madill48ef11b2016-04-27 15:21:52 -0400639 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400640 }
641
Brandon Jones1048ea72015-10-06 15:34:52 -0700642 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400643 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700644 for (unsigned int transformFeedbackVaryingIndex = 0;
645 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
646 ++transformFeedbackVaryingIndex)
647 {
648 sh::Varying varying;
649 stream.readInt(&varying.arraySize);
650 stream.readInt(&varying.type);
651 stream.readString(&varying.name);
652
Jamie Madill48ef11b2016-04-27 15:21:52 -0400653 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700654 }
655
Jamie Madill48ef11b2016-04-27 15:21:52 -0400656 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400657
Jamie Madill80a6fc02015-08-21 16:53:16 -0400658 unsigned int outputVarCount = stream.readInt<unsigned int>();
659 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
660 {
661 int locationIndex = stream.readInt<int>();
662 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400663 stream.readInt(&locationData.element);
664 stream.readInt(&locationData.index);
665 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400666 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400667 }
668
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400669 stream.readInt(&mSamplerUniformRange.start);
670 stream.readInt(&mSamplerUniformRange.end);
671
Geoff Lang7dd2e102014-11-10 15:19:26 -0500672 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
673 if (result.error.isError() || !result.linkSuccess)
674 {
Geoff Langb543aff2014-09-30 14:52:54 -0400675 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000676 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000677
Geoff Lang7dd2e102014-11-10 15:19:26 -0500678 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400679 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500680#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
681}
682
683Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
684{
685 if (binaryFormat)
686 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400687 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500688 }
689
690 BinaryOutputStream stream;
691
Geoff Lang7dd2e102014-11-10 15:19:26 -0500692 stream.writeInt(ANGLE_MAJOR_VERSION);
693 stream.writeInt(ANGLE_MINOR_VERSION);
694 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
695
Jamie Madill48ef11b2016-04-27 15:21:52 -0400696 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500697
Jamie Madill48ef11b2016-04-27 15:21:52 -0400698 stream.writeInt(mState.mAttributes.size());
699 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400700 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400701 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400702 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400703 }
704
Jamie Madill48ef11b2016-04-27 15:21:52 -0400705 stream.writeInt(mState.mUniforms.size());
706 for (const gl::LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400707 {
708 WriteShaderVar(&stream, uniform);
709
710 // FIXME: referenced
711
712 stream.writeInt(uniform.blockIndex);
713 stream.writeInt(uniform.blockInfo.offset);
714 stream.writeInt(uniform.blockInfo.arrayStride);
715 stream.writeInt(uniform.blockInfo.matrixStride);
716 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
717 }
718
Jamie Madill48ef11b2016-04-27 15:21:52 -0400719 stream.writeInt(mState.mUniformLocations.size());
720 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400721 {
722 stream.writeString(variable.name);
723 stream.writeInt(variable.element);
724 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400725 stream.writeInt(variable.used);
726 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400727 }
728
Jamie Madill48ef11b2016-04-27 15:21:52 -0400729 stream.writeInt(mState.mUniformBlocks.size());
730 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400731 {
732 stream.writeString(uniformBlock.name);
733 stream.writeInt(uniformBlock.isArray);
734 stream.writeInt(uniformBlock.arrayElement);
735 stream.writeInt(uniformBlock.dataSize);
736
737 stream.writeInt(uniformBlock.vertexStaticUse);
738 stream.writeInt(uniformBlock.fragmentStaticUse);
739
740 stream.writeInt(uniformBlock.memberUniformIndexes.size());
741 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
742 {
743 stream.writeInt(memberUniformIndex);
744 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400745 }
746
Jamie Madill48ef11b2016-04-27 15:21:52 -0400747 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
748 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700749 {
750 stream.writeInt(varying.arraySize);
751 stream.writeInt(varying.type);
752 stream.writeString(varying.name);
753 }
754
Jamie Madill48ef11b2016-04-27 15:21:52 -0400755 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400756
Jamie Madill48ef11b2016-04-27 15:21:52 -0400757 stream.writeInt(mState.mOutputVariables.size());
758 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -0400759 {
760 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -0400761 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400762 stream.writeInt(outputPair.second.index);
763 stream.writeString(outputPair.second.name);
764 }
765
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400766 stream.writeInt(mSamplerUniformRange.start);
767 stream.writeInt(mSamplerUniformRange.end);
768
Geoff Lang7dd2e102014-11-10 15:19:26 -0500769 gl::Error error = mProgram->save(&stream);
770 if (error.isError())
771 {
772 return error;
773 }
774
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700775 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -0400776 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777
778 if (streamLength > bufSize)
779 {
780 if (length)
781 {
782 *length = 0;
783 }
784
785 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
786 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
787 // sizes and then copy it.
788 return Error(GL_INVALID_OPERATION);
789 }
790
791 if (binary)
792 {
793 char *ptr = reinterpret_cast<char*>(binary);
794
Jamie Madill48ef11b2016-04-27 15:21:52 -0400795 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500796 ptr += streamLength;
797
798 ASSERT(ptr - streamLength == binary);
799 }
800
801 if (length)
802 {
803 *length = streamLength;
804 }
805
806 return Error(GL_NO_ERROR);
807}
808
809GLint Program::getBinaryLength() const
810{
811 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400812 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500813 if (error.isError())
814 {
815 return 0;
816 }
817
818 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000819}
820
Geoff Langc5629752015-12-07 16:29:04 -0500821void Program::setBinaryRetrievableHint(bool retrievable)
822{
823 // TODO(jmadill) : replace with dirty bits
824 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400825 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -0500826}
827
828bool Program::getBinaryRetrievableHint() const
829{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400830 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -0500831}
832
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000833void Program::release()
834{
835 mRefCount--;
836
837 if (mRefCount == 0 && mDeleteStatus)
838 {
839 mResourceManager->deleteProgram(mHandle);
840 }
841}
842
843void Program::addRef()
844{
845 mRefCount++;
846}
847
848unsigned int Program::getRefCount() const
849{
850 return mRefCount;
851}
852
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000853int Program::getInfoLogLength() const
854{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400855 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000856}
857
Geoff Lange1a27752015-10-05 13:16:04 -0400858void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000859{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000860 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000861}
862
Geoff Lange1a27752015-10-05 13:16:04 -0400863void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000864{
865 int total = 0;
866
Jamie Madill48ef11b2016-04-27 15:21:52 -0400867 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000868 {
869 if (total < maxCount)
870 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400871 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200872 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000873 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000874 }
875
Jamie Madill48ef11b2016-04-27 15:21:52 -0400876 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000877 {
878 if (total < maxCount)
879 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400880 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +0200881 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000882 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000883 }
884
885 if (count)
886 {
887 *count = total;
888 }
889}
890
Geoff Lange1a27752015-10-05 13:16:04 -0400891GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500892{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400893 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500894 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400895 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500896 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400897 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500898 }
899 }
900
Austin Kinrossb8af7232015-03-16 22:33:25 -0700901 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500902}
903
Jamie Madill63805b42015-08-25 13:17:39 -0400904bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400905{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400906 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
907 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500908}
909
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000910void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
911{
Jamie Madillc349ec02015-08-21 16:53:12 -0400912 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000913 {
914 if (bufsize > 0)
915 {
916 name[0] = '\0';
917 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500918
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000919 if (length)
920 {
921 *length = 0;
922 }
923
924 *type = GL_NONE;
925 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -0400926 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000927 }
Jamie Madillc349ec02015-08-21 16:53:12 -0400928
929 size_t attributeIndex = 0;
930
Jamie Madill48ef11b2016-04-27 15:21:52 -0400931 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400932 {
933 // Skip over inactive attributes
934 if (attribute.staticUse)
935 {
936 if (static_cast<size_t>(index) == attributeIndex)
937 {
938 break;
939 }
940 attributeIndex++;
941 }
942 }
943
Jamie Madill48ef11b2016-04-27 15:21:52 -0400944 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
945 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -0400946
947 if (bufsize > 0)
948 {
949 const char *string = attrib.name.c_str();
950
951 strncpy(name, string, bufsize);
952 name[bufsize - 1] = '\0';
953
954 if (length)
955 {
956 *length = static_cast<GLsizei>(strlen(name));
957 }
958 }
959
960 // Always a single 'type' instance
961 *size = 1;
962 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000963}
964
Geoff Lange1a27752015-10-05 13:16:04 -0400965GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000966{
Jamie Madillc349ec02015-08-21 16:53:12 -0400967 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400968 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400969 return 0;
970 }
971
972 GLint count = 0;
973
Jamie Madill48ef11b2016-04-27 15:21:52 -0400974 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400975 {
976 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000977 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500978
979 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000980}
981
Geoff Lange1a27752015-10-05 13:16:04 -0400982GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000983{
Jamie Madillc349ec02015-08-21 16:53:12 -0400984 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400985 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400986 return 0;
987 }
988
989 size_t maxLength = 0;
990
Jamie Madill48ef11b2016-04-27 15:21:52 -0400991 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -0400992 {
993 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500994 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400995 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500996 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000997 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500998
Jamie Madillc349ec02015-08-21 16:53:12 -0400999 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001000}
1001
Geoff Lang7dd2e102014-11-10 15:19:26 -05001002GLint Program::getFragDataLocation(const std::string &name) const
1003{
1004 std::string baseName(name);
1005 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001006 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001007 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001008 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001009 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1010 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001011 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001012 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001013 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001014 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001015}
1016
Geoff Lange1a27752015-10-05 13:16:04 -04001017void Program::getActiveUniform(GLuint index,
1018 GLsizei bufsize,
1019 GLsizei *length,
1020 GLint *size,
1021 GLenum *type,
1022 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001023{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001024 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001025 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001026 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001027 ASSERT(index < mState.mUniforms.size());
1028 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001029
1030 if (bufsize > 0)
1031 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001032 std::string string = uniform.name;
1033 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001034 {
1035 string += "[0]";
1036 }
1037
1038 strncpy(name, string.c_str(), bufsize);
1039 name[bufsize - 1] = '\0';
1040
1041 if (length)
1042 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001043 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001044 }
1045 }
1046
Jamie Madill62d31cb2015-09-11 13:25:51 -04001047 *size = uniform.elementCount();
1048 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001049 }
1050 else
1051 {
1052 if (bufsize > 0)
1053 {
1054 name[0] = '\0';
1055 }
1056
1057 if (length)
1058 {
1059 *length = 0;
1060 }
1061
1062 *size = 0;
1063 *type = GL_NONE;
1064 }
1065}
1066
Geoff Lange1a27752015-10-05 13:16:04 -04001067GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001068{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001069 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001070 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001071 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001072 }
1073 else
1074 {
1075 return 0;
1076 }
1077}
1078
Geoff Lange1a27752015-10-05 13:16:04 -04001079GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001080{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001081 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001082
1083 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001084 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001085 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001086 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001087 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001088 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001089 size_t length = uniform.name.length() + 1u;
1090 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001091 {
1092 length += 3; // Counting in "[0]".
1093 }
1094 maxLength = std::max(length, maxLength);
1095 }
1096 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001097 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001098
Jamie Madill62d31cb2015-09-11 13:25:51 -04001099 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001100}
1101
1102GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1103{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001104 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
1105 const gl::LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001106 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001107 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001108 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1109 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1110 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1111 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1112 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1113 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1114 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1115 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1116 default:
1117 UNREACHABLE();
1118 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001119 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001120 return 0;
1121}
1122
1123bool Program::isValidUniformLocation(GLint location) const
1124{
Jamie Madille2e406c2016-06-02 13:04:10 -04001125 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001126 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1127 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001128}
1129
1130bool Program::isIgnoredUniformLocation(GLint location) const
1131{
1132 // Location is ignored if it is -1 or it was bound but non-existant in the shader or optimized
1133 // out
1134 return location == -1 ||
Jamie Madill48ef11b2016-04-27 15:21:52 -04001135 (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1136 mState.mUniformLocations[static_cast<size_t>(location)].ignored);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001137}
1138
Jamie Madill62d31cb2015-09-11 13:25:51 -04001139const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001140{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001141 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1142 return mState.mUniforms[mState.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001143}
1144
Jamie Madill62d31cb2015-09-11 13:25:51 -04001145GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001146{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001147 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001148}
1149
Jamie Madill62d31cb2015-09-11 13:25:51 -04001150GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001151{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001152 return mState.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001153}
1154
1155void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1156{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001157 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001158 mProgram->setUniform1fv(location, count, v);
1159}
1160
1161void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1162{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001163 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001164 mProgram->setUniform2fv(location, count, v);
1165}
1166
1167void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1168{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001169 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001170 mProgram->setUniform3fv(location, count, v);
1171}
1172
1173void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1174{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001175 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176 mProgram->setUniform4fv(location, count, v);
1177}
1178
1179void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1180{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001181 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001182 mProgram->setUniform1iv(location, count, v);
1183}
1184
1185void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1186{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001187 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001188 mProgram->setUniform2iv(location, count, v);
1189}
1190
1191void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1192{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001193 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001194 mProgram->setUniform3iv(location, count, v);
1195}
1196
1197void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1198{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001199 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001200 mProgram->setUniform4iv(location, count, v);
1201}
1202
1203void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1204{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001205 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001206 mProgram->setUniform1uiv(location, count, v);
1207}
1208
1209void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1210{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001211 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001212 mProgram->setUniform2uiv(location, count, v);
1213}
1214
1215void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1216{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001217 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001218 mProgram->setUniform3uiv(location, count, v);
1219}
1220
1221void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1222{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001223 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001224 mProgram->setUniform4uiv(location, count, v);
1225}
1226
1227void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1228{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001229 setMatrixUniformInternal<2, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001230 mProgram->setUniformMatrix2fv(location, count, transpose, v);
1231}
1232
1233void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1234{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001235 setMatrixUniformInternal<3, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236 mProgram->setUniformMatrix3fv(location, count, transpose, v);
1237}
1238
1239void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1240{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001241 setMatrixUniformInternal<4, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001242 mProgram->setUniformMatrix4fv(location, count, transpose, v);
1243}
1244
1245void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1246{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001247 setMatrixUniformInternal<2, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001248 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
1249}
1250
1251void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1252{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001253 setMatrixUniformInternal<2, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001254 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
1255}
1256
1257void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1258{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001259 setMatrixUniformInternal<3, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001260 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
1261}
1262
1263void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1264{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001265 setMatrixUniformInternal<3, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001266 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
1267}
1268
1269void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1270{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001271 setMatrixUniformInternal<4, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001272 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
1273}
1274
1275void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1276{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001277 setMatrixUniformInternal<4, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001278 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
1279}
1280
Geoff Lange1a27752015-10-05 13:16:04 -04001281void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001282{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001283 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001284}
1285
Geoff Lange1a27752015-10-05 13:16:04 -04001286void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001287{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001288 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289}
1290
Geoff Lange1a27752015-10-05 13:16:04 -04001291void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001292{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001293 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001294}
1295
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001296void Program::flagForDeletion()
1297{
1298 mDeleteStatus = true;
1299}
1300
1301bool Program::isFlaggedForDeletion() const
1302{
1303 return mDeleteStatus;
1304}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001305
Brandon Jones43a53e22014-08-28 16:23:22 -07001306void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001307{
1308 mInfoLog.reset();
1309
Geoff Lang7dd2e102014-11-10 15:19:26 -05001310 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001311 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001312 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001313 }
1314 else
1315 {
Jamie Madillf6113162015-05-07 11:49:21 -04001316 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001317 }
1318}
1319
Geoff Lang7dd2e102014-11-10 15:19:26 -05001320bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1321{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001322 // Skip cache if we're using an infolog, so we get the full error.
1323 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1324 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1325 {
1326 return mCachedValidateSamplersResult.value();
1327 }
1328
1329 if (mTextureUnitTypesCache.empty())
1330 {
1331 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1332 }
1333 else
1334 {
1335 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1336 }
1337
1338 // if any two active samplers in a program are of different types, but refer to the same
1339 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1340 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1341 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1342 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1343 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001344 const LinkedUniform &uniform = mState.mUniforms[samplerIndex];
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001345 ASSERT(uniform.isSampler());
1346
1347 if (!uniform.staticUse)
1348 continue;
1349
1350 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1351 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1352
1353 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1354 {
1355 GLuint textureUnit = dataPtr[arrayElement];
1356
1357 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1358 {
1359 if (infoLog)
1360 {
1361 (*infoLog) << "Sampler uniform (" << textureUnit
1362 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1363 << caps.maxCombinedTextureImageUnits << ")";
1364 }
1365
1366 mCachedValidateSamplersResult = false;
1367 return false;
1368 }
1369
1370 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1371 {
1372 if (textureType != mTextureUnitTypesCache[textureUnit])
1373 {
1374 if (infoLog)
1375 {
1376 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1377 "image unit ("
1378 << textureUnit << ").";
1379 }
1380
1381 mCachedValidateSamplersResult = false;
1382 return false;
1383 }
1384 }
1385 else
1386 {
1387 mTextureUnitTypesCache[textureUnit] = textureType;
1388 }
1389 }
1390 }
1391
1392 mCachedValidateSamplersResult = true;
1393 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394}
1395
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001396bool Program::isValidated() const
1397{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398 return mValidated;
1399}
1400
Geoff Lange1a27752015-10-05 13:16:04 -04001401GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001402{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001403 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001404}
1405
1406void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1407{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001408 ASSERT(
1409 uniformBlockIndex <
1410 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411
Jamie Madill48ef11b2016-04-27 15:21:52 -04001412 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001413
1414 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001415 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416 std::string string = uniformBlock.name;
1417
Jamie Madill62d31cb2015-09-11 13:25:51 -04001418 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001419 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001420 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001421 }
1422
1423 strncpy(uniformBlockName, string.c_str(), bufSize);
1424 uniformBlockName[bufSize - 1] = '\0';
1425
1426 if (length)
1427 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001428 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001429 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001430 }
1431}
1432
Geoff Lang7dd2e102014-11-10 15:19:26 -05001433void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001434{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001435 ASSERT(
1436 uniformBlockIndex <
1437 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438
Jamie Madill48ef11b2016-04-27 15:21:52 -04001439 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001440
1441 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001442 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443 case GL_UNIFORM_BLOCK_DATA_SIZE:
1444 *params = static_cast<GLint>(uniformBlock.dataSize);
1445 break;
1446 case GL_UNIFORM_BLOCK_NAME_LENGTH:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001447 *params =
1448 static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001449 break;
1450 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1451 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1452 break;
1453 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1454 {
1455 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1456 {
1457 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1458 }
1459 }
1460 break;
1461 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001462 *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001463 break;
1464 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001465 *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001466 break;
1467 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001468 }
1469}
1470
Geoff Lange1a27752015-10-05 13:16:04 -04001471GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001472{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473 int maxLength = 0;
1474
1475 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001476 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001477 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1479 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001480 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481 if (!uniformBlock.name.empty())
1482 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001483 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001484
1485 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001486 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001487
1488 maxLength = std::max(length + arrayLength, maxLength);
1489 }
1490 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001491 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001492
1493 return maxLength;
1494}
1495
Geoff Lange1a27752015-10-05 13:16:04 -04001496GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001498 size_t subscript = GL_INVALID_INDEX;
1499 std::string baseName = gl::ParseUniformName(name, &subscript);
1500
Jamie Madill48ef11b2016-04-27 15:21:52 -04001501 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001502 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1503 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001504 const gl::UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001505 if (uniformBlock.name == baseName)
1506 {
1507 const bool arrayElementZero =
1508 (subscript == GL_INVALID_INDEX &&
1509 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1510 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1511 {
1512 return blockIndex;
1513 }
1514 }
1515 }
1516
1517 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001518}
1519
Jamie Madill62d31cb2015-09-11 13:25:51 -04001520const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001521{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001522 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1523 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001524}
1525
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001526void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1527{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001528 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Geoff Lang5d124a62015-09-15 13:03:27 -04001529 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001530}
1531
1532GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1533{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001534 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001535}
1536
1537void Program::resetUniformBlockBindings()
1538{
1539 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1540 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001541 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001542 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001543 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001544}
1545
Geoff Lang48dcae72014-02-05 16:28:24 -05001546void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1547{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001548 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001549 for (GLsizei i = 0; i < count; i++)
1550 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001551 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001552 }
1553
Jamie Madill48ef11b2016-04-27 15:21:52 -04001554 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001555}
1556
1557void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1558{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001559 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001560 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001561 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1562 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001563 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1564 if (length)
1565 {
1566 *length = lastNameIdx;
1567 }
1568 if (size)
1569 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001570 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001571 }
1572 if (type)
1573 {
1574 *type = varying.type;
1575 }
1576 if (name)
1577 {
1578 memcpy(name, varying.name.c_str(), lastNameIdx);
1579 name[lastNameIdx] = '\0';
1580 }
1581 }
1582}
1583
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001584GLsizei Program::getTransformFeedbackVaryingCount() const
1585{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001586 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001587 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001588 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001589 }
1590 else
1591 {
1592 return 0;
1593 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001594}
1595
1596GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1597{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001598 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001599 {
1600 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001601 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001602 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001603 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1604 }
1605
1606 return maxSize;
1607 }
1608 else
1609 {
1610 return 0;
1611 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001612}
1613
1614GLenum Program::getTransformFeedbackBufferMode() const
1615{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001616 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001617}
1618
Jamie Madillada9ecc2015-08-17 12:53:37 -04001619// static
1620bool Program::linkVaryings(InfoLog &infoLog,
1621 const Shader *vertexShader,
1622 const Shader *fragmentShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001623{
Jamie Madill4cff2472015-08-21 16:53:18 -04001624 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1625 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626
Jamie Madill4cff2472015-08-21 16:53:18 -04001627 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001628 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001629 bool matched = false;
1630
1631 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001632 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633 {
1634 continue;
1635 }
1636
Jamie Madill4cff2472015-08-21 16:53:18 -04001637 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001639 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001640 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001641 ASSERT(!input.isBuiltIn());
1642 if (!linkValidateVaryings(infoLog, output.name, input, output))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001643 {
1644 return false;
1645 }
1646
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647 matched = true;
1648 break;
1649 }
1650 }
1651
1652 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001653 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001654 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001655 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656 return false;
1657 }
1658 }
1659
Jamie Madillada9ecc2015-08-17 12:53:37 -04001660 // TODO(jmadill): verify no unmatched vertex varyings?
1661
Geoff Lang7dd2e102014-11-10 15:19:26 -05001662 return true;
1663}
1664
Geoff Langd8605522016-04-13 10:19:12 -04001665bool Program::linkUniforms(gl::InfoLog &infoLog,
1666 const gl::Caps &caps,
1667 const Bindings &uniformBindings)
Jamie Madillea918db2015-08-18 14:48:59 -04001668{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001669 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1670 const std::vector<sh::Uniform> &fragmentUniforms =
1671 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001672
1673 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill62d31cb2015-09-11 13:25:51 -04001674 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madillea918db2015-08-18 14:48:59 -04001675
1676 for (const sh::Uniform &vertexUniform : vertexUniforms)
1677 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001678 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001679 }
1680
1681 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1682 {
1683 auto entry = linkedUniforms.find(fragmentUniform.name);
1684 if (entry != linkedUniforms.end())
1685 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001686 LinkedUniform *vertexUniform = &entry->second;
1687 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1688 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001689 {
1690 return false;
1691 }
1692 }
1693 }
1694
Jamie Madill62d31cb2015-09-11 13:25:51 -04001695 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1696 // Also check the maximum uniform vector and sampler counts.
1697 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1698 {
1699 return false;
1700 }
1701
Geoff Langd8605522016-04-13 10:19:12 -04001702 if (!indexUniforms(infoLog, caps, uniformBindings))
1703 {
1704 return false;
1705 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001706
Jamie Madillea918db2015-08-18 14:48:59 -04001707 return true;
1708}
1709
Geoff Langd8605522016-04-13 10:19:12 -04001710bool Program::indexUniforms(gl::InfoLog &infoLog,
1711 const gl::Caps &caps,
1712 const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001713{
Geoff Langd8605522016-04-13 10:19:12 -04001714 // Uniforms awaiting a location
1715 std::vector<VariableLocation> unboundUniforms;
1716 std::map<GLuint, VariableLocation> boundUniforms;
1717 int maxUniformLocation = -1;
1718
1719 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001720 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001721 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001722 const gl::LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001723
Geoff Langd8605522016-04-13 10:19:12 -04001724 if (uniform.isBuiltIn())
1725 {
1726 continue;
1727 }
1728
1729 int bindingLocation = uniformBindings.getBinding(uniform.name);
1730
1731 // Verify that this location isn't bound twice
1732 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1733 {
1734 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1735 return false;
1736 }
1737
Jamie Madill62d31cb2015-09-11 13:25:51 -04001738 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1739 {
Geoff Langd8605522016-04-13 10:19:12 -04001740 VariableLocation location(uniform.name, arrayIndex,
1741 static_cast<unsigned int>(uniformIndex));
1742
1743 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001744 {
Geoff Langd8605522016-04-13 10:19:12 -04001745 boundUniforms[bindingLocation] = location;
1746 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1747 }
1748 else
1749 {
1750 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001751 }
1752 }
1753 }
Geoff Langd8605522016-04-13 10:19:12 -04001754
1755 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1756 // not be assigned to those locations.
1757 std::set<GLuint> reservedLocations;
1758 for (const auto &binding : uniformBindings)
1759 {
1760 GLuint location = binding.second;
1761 if (boundUniforms.find(location) == boundUniforms.end())
1762 {
1763 reservedLocations.insert(location);
1764 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1765 }
1766 }
1767
1768 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04001769 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04001770 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
1771 static_cast<size_t>(maxUniformLocation + 1)));
1772
1773 // Assign bound uniforms
1774 for (const auto &boundUniform : boundUniforms)
1775 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001776 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04001777 }
1778
1779 // Assign reserved uniforms
1780 for (const auto &reservedLocation : reservedLocations)
1781 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001782 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04001783 }
1784
1785 // Assign unbound uniforms
1786 size_t nextUniformLocation = 0;
1787 for (const auto &unboundUniform : unboundUniforms)
1788 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001789 while (mState.mUniformLocations[nextUniformLocation].used ||
1790 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04001791 {
1792 nextUniformLocation++;
1793 }
1794
Jamie Madill48ef11b2016-04-27 15:21:52 -04001795 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
1796 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04001797 nextUniformLocation++;
1798 }
1799
1800 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04001801}
1802
Geoff Lang7dd2e102014-11-10 15:19:26 -05001803bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1804{
Jamie Madillc4c744222015-11-04 09:39:47 -05001805 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1806 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001807 {
1808 return false;
1809 }
1810
1811 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1812 {
Jamie Madillf6113162015-05-07 11:49:21 -04001813 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001814 return false;
1815 }
1816
1817 return true;
1818}
1819
1820// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill9082b982016-04-27 15:21:51 -04001821bool Program::linkAttributes(const ContextState &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001822 InfoLog &infoLog,
Geoff Langd8605522016-04-13 10:19:12 -04001823 const Bindings &attributeBindings,
Jamie Madill3da79b72015-04-27 11:09:17 -04001824 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001825{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001826 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001827 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001828 GLuint maxAttribs = data.caps->maxVertexAttributes;
1829
1830 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001831 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001832 {
Jamie Madillf6113162015-05-07 11:49:21 -04001833 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001834 return false;
1835 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836
Jamie Madillc349ec02015-08-21 16:53:12 -04001837 std::vector<sh::Attribute *> usedAttribMap(data.caps->maxVertexAttributes, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001838
Jamie Madillc349ec02015-08-21 16:53:12 -04001839 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001840 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001841 {
1842 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05001843 ASSERT(attribute.staticUse);
1844
Geoff Langd8605522016-04-13 10:19:12 -04001845 int bindingLocation = attributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04001846 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04001847 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001848 attribute.location = bindingLocation;
1849 }
1850
1851 if (attribute.location != -1)
1852 {
1853 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04001854 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001855
Jamie Madill63805b42015-08-25 13:17:39 -04001856 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001857 {
Jamie Madillf6113162015-05-07 11:49:21 -04001858 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04001859 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860
1861 return false;
1862 }
1863
Jamie Madill63805b42015-08-25 13:17:39 -04001864 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001865 {
Jamie Madill63805b42015-08-25 13:17:39 -04001866 const int regLocation = attribute.location + reg;
1867 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001868
1869 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001870 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04001871 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001872 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001873 // TODO(jmadill): fix aliasing on ES2
1874 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001876 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04001877 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878 return false;
1879 }
1880 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001881 else
1882 {
Jamie Madill63805b42015-08-25 13:17:39 -04001883 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04001884 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885
Jamie Madill63805b42015-08-25 13:17:39 -04001886 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 }
1888 }
1889 }
1890
1891 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04001892 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001893 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 ASSERT(attribute.staticUse);
1895
Jamie Madillc349ec02015-08-21 16:53:12 -04001896 // Not set by glBindAttribLocation or by location layout qualifier
1897 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001898 {
Jamie Madill63805b42015-08-25 13:17:39 -04001899 int regs = VariableRegisterCount(attribute.type);
1900 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001901
Jamie Madill63805b42015-08-25 13:17:39 -04001902 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001903 {
Jamie Madillf6113162015-05-07 11:49:21 -04001904 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04001905 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001906 }
1907
Jamie Madillc349ec02015-08-21 16:53:12 -04001908 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001909 }
1910 }
1911
Jamie Madill48ef11b2016-04-27 15:21:52 -04001912 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001913 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001914 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04001915 ASSERT(attribute.location != -1);
1916 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04001917
Jamie Madill63805b42015-08-25 13:17:39 -04001918 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001919 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001920 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001921 }
1922 }
1923
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924 return true;
1925}
1926
Jamie Madille473dee2015-08-18 14:49:01 -04001927bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001928{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001929 const Shader &vertexShader = *mState.mAttachedVertexShader;
1930 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
Jamie Madille473dee2015-08-18 14:49:01 -04001931
Geoff Lang7dd2e102014-11-10 15:19:26 -05001932 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1933 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madille473dee2015-08-18 14:49:01 -04001934
Geoff Lang7dd2e102014-11-10 15:19:26 -05001935 // Check that interface blocks defined in the vertex and fragment shaders are identical
1936 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1937 UniformBlockMap linkedUniformBlocks;
Jamie Madille473dee2015-08-18 14:49:01 -04001938
1939 GLuint vertexBlockCount = 0;
1940 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001941 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001942 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jamie Madille473dee2015-08-18 14:49:01 -04001943
1944 // Note: shared and std140 layouts are always considered active
1945 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1946 {
1947 if (++vertexBlockCount > caps.maxVertexUniformBlocks)
1948 {
1949 infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
1950 << caps.maxVertexUniformBlocks << ")";
1951 return false;
1952 }
1953 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001954 }
Jamie Madille473dee2015-08-18 14:49:01 -04001955
1956 GLuint fragmentBlockCount = 0;
1957 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001958 {
Jamie Madille473dee2015-08-18 14:49:01 -04001959 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001960 if (entry != linkedUniformBlocks.end())
1961 {
1962 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1963 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1964 {
1965 return false;
1966 }
1967 }
Jamie Madille473dee2015-08-18 14:49:01 -04001968
Geoff Lang7dd2e102014-11-10 15:19:26 -05001969 // Note: shared and std140 layouts are always considered active
Jamie Madille473dee2015-08-18 14:49:01 -04001970 if (fragmentInterfaceBlock.staticUse ||
1971 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001972 {
Jamie Madille473dee2015-08-18 14:49:01 -04001973 if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001974 {
Jamie Madille473dee2015-08-18 14:49:01 -04001975 infoLog
1976 << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
1977 << caps.maxFragmentUniformBlocks << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001978 return false;
1979 }
1980 }
1981 }
Jamie Madille473dee2015-08-18 14:49:01 -04001982
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983 return true;
1984}
1985
1986bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1987 const sh::InterfaceBlock &fragmentInterfaceBlock)
1988{
1989 const char* blockName = vertexInterfaceBlock.name.c_str();
1990 // validate blocks for the same member types
1991 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1992 {
Jamie Madillf6113162015-05-07 11:49:21 -04001993 infoLog << "Types for interface block '" << blockName
1994 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001995 return false;
1996 }
1997 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1998 {
Jamie Madillf6113162015-05-07 11:49:21 -04001999 infoLog << "Array sizes differ for interface block '" << blockName
2000 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002001 return false;
2002 }
2003 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2004 {
Jamie Madillf6113162015-05-07 11:49:21 -04002005 infoLog << "Layout qualifiers differ for interface block '" << blockName
2006 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002007 return false;
2008 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002009 const unsigned int numBlockMembers =
2010 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002011 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2012 {
2013 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2014 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2015 if (vertexMember.name != fragmentMember.name)
2016 {
Jamie Madillf6113162015-05-07 11:49:21 -04002017 infoLog << "Name mismatch for field " << blockMemberIndex
2018 << " of interface block '" << blockName
2019 << "': (in vertex: '" << vertexMember.name
2020 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002021 return false;
2022 }
2023 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2024 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2025 {
2026 return false;
2027 }
2028 }
2029 return true;
2030}
2031
2032bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2033 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2034{
2035 if (vertexVariable.type != fragmentVariable.type)
2036 {
Jamie Madillf6113162015-05-07 11:49:21 -04002037 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002038 return false;
2039 }
2040 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2041 {
Jamie Madillf6113162015-05-07 11:49:21 -04002042 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002043 return false;
2044 }
2045 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2046 {
Jamie Madillf6113162015-05-07 11:49:21 -04002047 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002048 return false;
2049 }
2050
2051 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2052 {
Jamie Madillf6113162015-05-07 11:49:21 -04002053 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002054 return false;
2055 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002056 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002057 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2058 {
2059 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2060 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2061
2062 if (vertexMember.name != fragmentMember.name)
2063 {
Jamie Madillf6113162015-05-07 11:49:21 -04002064 infoLog << "Name mismatch for field '" << memberIndex
2065 << "' of " << variableName
2066 << ": (in vertex: '" << vertexMember.name
2067 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002068 return false;
2069 }
2070
2071 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2072 vertexMember.name + "'";
2073
2074 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2075 {
2076 return false;
2077 }
2078 }
2079
2080 return true;
2081}
2082
2083bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2084{
Cooper Partin1acf4382015-06-12 12:38:57 -07002085#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2086 const bool validatePrecision = true;
2087#else
2088 const bool validatePrecision = false;
2089#endif
2090
2091 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002092 {
2093 return false;
2094 }
2095
2096 return true;
2097}
2098
2099bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
2100{
2101 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2102 {
2103 return false;
2104 }
2105
Jamie Madille9cc4692015-02-19 16:00:13 -05002106 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002107 {
Jamie Madillf6113162015-05-07 11:49:21 -04002108 infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002109 return false;
2110 }
2111
2112 return true;
2113}
2114
Jamie Madillccdf74b2015-08-18 10:46:12 -04002115bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2116 const std::vector<const sh::Varying *> &varyings,
2117 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002118{
2119 size_t totalComponents = 0;
2120
Jamie Madillccdf74b2015-08-18 10:46:12 -04002121 std::set<std::string> uniqueNames;
2122
Jamie Madill48ef11b2016-04-27 15:21:52 -04002123 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002124 {
2125 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002126 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002127 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002128 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002129 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002130 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002132 infoLog << "Two transform feedback varyings specify the same output variable ("
2133 << tfVaryingName << ").";
2134 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002135 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002136 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002137
Geoff Lang1a683462015-09-29 15:09:59 -04002138 if (varying->isArray())
2139 {
2140 infoLog << "Capture of arrays is undefined and not supported.";
2141 return false;
2142 }
2143
Jamie Madillccdf74b2015-08-18 10:46:12 -04002144 // TODO(jmadill): Investigate implementation limits on D3D11
2145 size_t componentCount = gl::VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002146 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002147 componentCount > caps.maxTransformFeedbackSeparateComponents)
2148 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002149 infoLog << "Transform feedback varying's " << varying->name << " components ("
2150 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002151 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002152 return false;
2153 }
2154
2155 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002156 found = true;
2157 break;
2158 }
2159 }
2160
Jamie Madill89bb70e2015-08-31 14:18:39 -04002161 if (tfVaryingName.find('[') != std::string::npos)
2162 {
Geoff Lang1a683462015-09-29 15:09:59 -04002163 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002164 return false;
2165 }
2166
Geoff Lang7dd2e102014-11-10 15:19:26 -05002167 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2168 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04002169 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002170 }
2171
Jamie Madill48ef11b2016-04-27 15:21:52 -04002172 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002173 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 {
Jamie Madillf6113162015-05-07 11:49:21 -04002175 infoLog << "Transform feedback varying total components (" << totalComponents
2176 << ") exceed the maximum interleaved components ("
2177 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 return false;
2179 }
2180
2181 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002182}
2183
Jamie Madillccdf74b2015-08-18 10:46:12 -04002184void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2185{
2186 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002187 mState.mTransformFeedbackVaryingVars.clear();
2188 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002189 {
2190 for (const sh::Varying *varying : varyings)
2191 {
2192 if (tfVaryingName == varying->name)
2193 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002194 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002195 break;
2196 }
2197 }
2198 }
2199}
2200
2201std::vector<const sh::Varying *> Program::getMergedVaryings() const
2202{
2203 std::set<std::string> uniqueNames;
2204 std::vector<const sh::Varying *> varyings;
2205
Jamie Madill48ef11b2016-04-27 15:21:52 -04002206 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002207 {
2208 if (uniqueNames.count(varying.name) == 0)
2209 {
2210 uniqueNames.insert(varying.name);
2211 varyings.push_back(&varying);
2212 }
2213 }
2214
Jamie Madill48ef11b2016-04-27 15:21:52 -04002215 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002216 {
2217 if (uniqueNames.count(varying.name) == 0)
2218 {
2219 uniqueNames.insert(varying.name);
2220 varyings.push_back(&varying);
2221 }
2222 }
2223
2224 return varyings;
2225}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002226
2227void Program::linkOutputVariables()
2228{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002229 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002230 ASSERT(fragmentShader != nullptr);
2231
2232 // Skip this step for GLES2 shaders.
2233 if (fragmentShader->getShaderVersion() == 100)
2234 return;
2235
Jamie Madilla0a9e122015-09-02 15:54:30 -04002236 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002237
2238 // TODO(jmadill): any caps validation here?
2239
2240 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2241 outputVariableIndex++)
2242 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002243 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002244
2245 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2246 if (outputVariable.isBuiltIn())
2247 continue;
2248
2249 // Since multiple output locations must be specified, use 0 for non-specified locations.
2250 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2251
2252 ASSERT(outputVariable.staticUse);
2253
2254 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2255 elementIndex++)
2256 {
2257 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002258 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002259 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002260 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002261 VariableLocation(outputVariable.name, element, outputVariableIndex);
2262 }
2263 }
2264}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002265
2266bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2267{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002268 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002269 VectorAndSamplerCount vsCounts;
2270
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002271 std::vector<LinkedUniform> samplerUniforms;
2272
Jamie Madill62d31cb2015-09-11 13:25:51 -04002273 for (const sh::Uniform &uniform : vertexShader->getUniforms())
2274 {
2275 if (uniform.staticUse)
2276 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002277 vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002278 }
2279 }
2280
2281 if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
2282 {
2283 infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
2284 << caps.maxVertexUniformVectors << ").";
2285 return false;
2286 }
2287
2288 if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
2289 {
2290 infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
2291 << caps.maxVertexTextureImageUnits << ").";
2292 return false;
2293 }
2294
Jamie Madill48ef11b2016-04-27 15:21:52 -04002295 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002296 VectorAndSamplerCount fsCounts;
2297
2298 for (const sh::Uniform &uniform : fragmentShader->getUniforms())
2299 {
2300 if (uniform.staticUse)
2301 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002302 fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002303 }
2304 }
2305
2306 if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
2307 {
2308 infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
2309 << caps.maxFragmentUniformVectors << ").";
2310 return false;
2311 }
2312
2313 if (fsCounts.samplerCount > caps.maxTextureImageUnits)
2314 {
2315 infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
2316 << caps.maxTextureImageUnits << ").";
2317 return false;
2318 }
2319
Jamie Madill48ef11b2016-04-27 15:21:52 -04002320 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002321 mSamplerUniformRange.end =
2322 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2323
Jamie Madill48ef11b2016-04-27 15:21:52 -04002324 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002325
Jamie Madill62d31cb2015-09-11 13:25:51 -04002326 return true;
2327}
2328
2329Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002330 const std::string &fullName,
2331 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002332{
2333 VectorAndSamplerCount vectorAndSamplerCount;
2334
2335 if (uniform.isStruct())
2336 {
2337 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2338 {
2339 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2340
2341 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2342 {
2343 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2344 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2345
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002346 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002347 }
2348 }
2349
2350 return vectorAndSamplerCount;
2351 }
2352
2353 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002354 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002355 if (!UniformInList(mState.getUniforms(), fullName) &&
2356 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002357 {
2358 gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
2359 uniform.arraySize, -1,
2360 sh::BlockMemberInfo::getDefaultBlockInfo());
2361 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002362
2363 // Store sampler uniforms separately, so we'll append them to the end of the list.
2364 if (isSampler)
2365 {
2366 samplerUniforms->push_back(linkedUniform);
2367 }
2368 else
2369 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002370 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002371 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002372 }
2373
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002374 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002375
2376 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2377 // Likewise, don't count "real" uniforms towards sampler count.
2378 vectorAndSamplerCount.vectorCount =
2379 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002380 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002381
2382 return vectorAndSamplerCount;
2383}
2384
2385void Program::gatherInterfaceBlockInfo()
2386{
2387 std::set<std::string> visitedList;
2388
Jamie Madill48ef11b2016-04-27 15:21:52 -04002389 const gl::Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002390
Jamie Madill48ef11b2016-04-27 15:21:52 -04002391 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002392 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2393 {
2394 // Only 'packed' blocks are allowed to be considered inacive.
2395 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2396 continue;
2397
2398 if (visitedList.count(vertexBlock.name) > 0)
2399 continue;
2400
2401 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2402 visitedList.insert(vertexBlock.name);
2403 }
2404
Jamie Madill48ef11b2016-04-27 15:21:52 -04002405 const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002406
2407 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2408 {
2409 // Only 'packed' blocks are allowed to be considered inacive.
2410 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2411 continue;
2412
2413 if (visitedList.count(fragmentBlock.name) > 0)
2414 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002415 for (gl::UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002416 {
2417 if (block.name == fragmentBlock.name)
2418 {
2419 block.fragmentStaticUse = fragmentBlock.staticUse;
2420 }
2421 }
2422
2423 continue;
2424 }
2425
2426 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2427 visitedList.insert(fragmentBlock.name);
2428 }
2429}
2430
Jamie Madill4a3c2342015-10-08 12:58:45 -04002431template <typename VarT>
2432void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2433 const std::string &prefix,
2434 int blockIndex)
2435{
2436 for (const VarT &field : fields)
2437 {
2438 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2439
2440 if (field.isStruct())
2441 {
2442 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2443 {
2444 const std::string uniformElementName =
2445 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2446 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2447 }
2448 }
2449 else
2450 {
2451 // If getBlockMemberInfo returns false, the uniform is optimized out.
2452 sh::BlockMemberInfo memberInfo;
2453 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2454 {
2455 continue;
2456 }
2457
2458 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2459 blockIndex, memberInfo);
2460
2461 // Since block uniforms have no location, we don't need to store them in the uniform
2462 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002463 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002464 }
2465 }
2466}
2467
Jamie Madill62d31cb2015-09-11 13:25:51 -04002468void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2469{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002470 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002471 size_t blockSize = 0;
2472
2473 // Don't define this block at all if it's not active in the implementation.
2474 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2475 {
2476 return;
2477 }
2478
2479 // Track the first and last uniform index to determine the range of active uniforms in the
2480 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002481 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002482 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002483 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002484
2485 std::vector<unsigned int> blockUniformIndexes;
2486 for (size_t blockUniformIndex = firstBlockUniformIndex;
2487 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2488 {
2489 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2490 }
2491
2492 if (interfaceBlock.arraySize > 0)
2493 {
2494 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2495 {
2496 UniformBlock block(interfaceBlock.name, true, arrayElement);
2497 block.memberUniformIndexes = blockUniformIndexes;
2498
2499 if (shaderType == GL_VERTEX_SHADER)
2500 {
2501 block.vertexStaticUse = interfaceBlock.staticUse;
2502 }
2503 else
2504 {
2505 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2506 block.fragmentStaticUse = interfaceBlock.staticUse;
2507 }
2508
Jamie Madill4a3c2342015-10-08 12:58:45 -04002509 // TODO(jmadill): Determine if we can ever have an inactive array element block.
2510 size_t blockElementSize = 0;
2511 if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
2512 {
2513 continue;
2514 }
2515
2516 ASSERT(blockElementSize == blockSize);
2517 block.dataSize = static_cast<unsigned int>(blockElementSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002518 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002519 }
2520 }
2521 else
2522 {
2523 UniformBlock block(interfaceBlock.name, false, 0);
2524 block.memberUniformIndexes = blockUniformIndexes;
2525
2526 if (shaderType == GL_VERTEX_SHADER)
2527 {
2528 block.vertexStaticUse = interfaceBlock.staticUse;
2529 }
2530 else
2531 {
2532 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2533 block.fragmentStaticUse = interfaceBlock.staticUse;
2534 }
2535
Jamie Madill4a3c2342015-10-08 12:58:45 -04002536 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002537 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002538 }
2539}
2540
2541template <typename T>
2542void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
2543{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002544 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2545 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002546 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2547
2548 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2549 {
2550 // Do a cast conversion for boolean types. From the spec:
2551 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2552 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
2553 for (GLsizei component = 0; component < count; ++component)
2554 {
2555 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2556 }
2557 }
2558 else
2559 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002560 // Invalide the validation cache if we modify the sampler data.
2561 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
2562 {
2563 mCachedValidateSamplersResult.reset();
2564 }
2565
Jamie Madill62d31cb2015-09-11 13:25:51 -04002566 memcpy(destPointer, v, sizeof(T) * count);
2567 }
2568}
2569
2570template <size_t cols, size_t rows, typename T>
2571void Program::setMatrixUniformInternal(GLint location,
2572 GLsizei count,
2573 GLboolean transpose,
2574 const T *v)
2575{
2576 if (!transpose)
2577 {
2578 setUniformInternal(location, count * cols * rows, v);
2579 return;
2580 }
2581
2582 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002583 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2584 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002585 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
2586 for (GLsizei element = 0; element < count; ++element)
2587 {
2588 size_t elementOffset = element * rows * cols;
2589
2590 for (size_t row = 0; row < rows; ++row)
2591 {
2592 for (size_t col = 0; col < cols; ++col)
2593 {
2594 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2595 }
2596 }
2597 }
2598}
2599
2600template <typename DestT>
2601void Program::getUniformInternal(GLint location, DestT *dataOut) const
2602{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002603 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2604 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002605
2606 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2607
2608 GLenum componentType = VariableComponentType(uniform.type);
2609 if (componentType == GLTypeToGLenum<DestT>::value)
2610 {
2611 memcpy(dataOut, srcPointer, uniform.getElementSize());
2612 return;
2613 }
2614
Corentin Wallez6596c462016-03-17 17:26:58 -04002615 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002616
2617 switch (componentType)
2618 {
2619 case GL_INT:
2620 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2621 break;
2622 case GL_UNSIGNED_INT:
2623 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2624 break;
2625 case GL_BOOL:
2626 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2627 break;
2628 case GL_FLOAT:
2629 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2630 break;
2631 default:
2632 UNREACHABLE();
2633 }
2634}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002635}