blob: 407ab56ab2c56b49757fbf1d8eef11e94572b1ef [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill80a6fc02015-08-21 16:53:16 -040014#include "common/BitSetIterator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
17#include "common/utilities.h"
18#include "common/version.h"
19#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill437d2662014-12-05 14:23:35 -050021#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050022#include "libANGLE/features.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040023#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040025#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040026#include "libANGLE/Uniform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050027
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028namespace gl
29{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000030
Geoff Lang7dd2e102014-11-10 15:19:26 -050031namespace
32{
33
Jamie Madill62d31cb2015-09-11 13:25:51 -040034void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
35{
36 stream->writeInt(var.type);
37 stream->writeInt(var.precision);
38 stream->writeString(var.name);
39 stream->writeString(var.mappedName);
40 stream->writeInt(var.arraySize);
41 stream->writeInt(var.staticUse);
42 stream->writeString(var.structName);
43 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050044}
45
Jamie Madill62d31cb2015-09-11 13:25:51 -040046void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
47{
48 var->type = stream->readInt<GLenum>();
49 var->precision = stream->readInt<GLenum>();
50 var->name = stream->readString();
51 var->mappedName = stream->readString();
52 var->arraySize = stream->readInt<unsigned int>();
53 var->staticUse = stream->readBool();
54 var->structName = stream->readString();
55}
56
Jamie Madill62d31cb2015-09-11 13:25:51 -040057// This simplified cast function doesn't need to worry about advanced concepts like
58// depth range values, or casting to bool.
59template <typename DestT, typename SrcT>
60DestT UniformStateQueryCast(SrcT value);
61
62// From-Float-To-Integer Casts
63template <>
64GLint UniformStateQueryCast(GLfloat value)
65{
66 return clampCast<GLint>(roundf(value));
67}
68
69template <>
70GLuint UniformStateQueryCast(GLfloat value)
71{
72 return clampCast<GLuint>(roundf(value));
73}
74
75// From-Integer-to-Integer Casts
76template <>
77GLint UniformStateQueryCast(GLuint value)
78{
79 return clampCast<GLint>(value);
80}
81
82template <>
83GLuint UniformStateQueryCast(GLint value)
84{
85 return clampCast<GLuint>(value);
86}
87
88// From-Boolean-to-Anything Casts
89template <>
90GLfloat UniformStateQueryCast(GLboolean value)
91{
92 return (value == GL_TRUE ? 1.0f : 0.0f);
93}
94
95template <>
96GLint UniformStateQueryCast(GLboolean value)
97{
98 return (value == GL_TRUE ? 1 : 0);
99}
100
101template <>
102GLuint UniformStateQueryCast(GLboolean value)
103{
104 return (value == GL_TRUE ? 1u : 0u);
105}
106
107// Default to static_cast
108template <typename DestT, typename SrcT>
109DestT UniformStateQueryCast(SrcT value)
110{
111 return static_cast<DestT>(value);
112}
113
114template <typename SrcT, typename DestT>
115void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
116{
117 for (int comp = 0; comp < components; ++comp)
118 {
119 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
120 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
121 size_t offset = comp * 4;
122 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
123 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
124 }
125}
126
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400127bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
128{
129 for (const LinkedUniform &uniform : list)
130 {
131 if (uniform.name == name)
132 return true;
133 }
134
135 return false;
136}
137
Jamie Madill62d31cb2015-09-11 13:25:51 -0400138} // anonymous namespace
139
Jamie Madill4a3c2342015-10-08 12:58:45 -0400140const char *const g_fakepath = "C:\\fakepath";
141
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400142InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000143{
144}
145
146InfoLog::~InfoLog()
147{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000148}
149
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400150size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000151{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400152 const std::string &logString = mStream.str();
153 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000154}
155
Geoff Lange1a27752015-10-05 13:16:04 -0400156void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000157{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400158 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000159
160 if (bufSize > 0)
161 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400162 const std::string str(mStream.str());
163
164 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000165 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400166 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
167 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000168 }
169
170 infoLog[index] = '\0';
171 }
172
173 if (length)
174 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400175 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000176 }
177}
178
179// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300180// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000181// messages, so lets remove all occurrences of this fake file path from the log.
182void InfoLog::appendSanitized(const char *message)
183{
184 std::string msg(message);
185
186 size_t found;
187 do
188 {
189 found = msg.find(g_fakepath);
190 if (found != std::string::npos)
191 {
192 msg.erase(found, strlen(g_fakepath));
193 }
194 }
195 while (found != std::string::npos);
196
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400197 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000198}
199
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000200void InfoLog::reset()
201{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000202}
203
Geoff Langd8605522016-04-13 10:19:12 -0400204VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000205{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500206}
207
Geoff Langd8605522016-04-13 10:19:12 -0400208VariableLocation::VariableLocation(const std::string &name,
209 unsigned int element,
210 unsigned int index)
211 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500212{
213}
214
Geoff Langd8605522016-04-13 10:19:12 -0400215void Program::Bindings::bindLocation(GLuint index, const std::string &name)
216{
217 mBindings[name] = index;
218}
219
220int Program::Bindings::getBinding(const std::string &name) const
221{
222 auto iter = mBindings.find(name);
223 return (iter != mBindings.end()) ? iter->second : -1;
224}
225
226Program::Bindings::const_iterator Program::Bindings::begin() const
227{
228 return mBindings.begin();
229}
230
231Program::Bindings::const_iterator Program::Bindings::end() const
232{
233 return mBindings.end();
234}
235
Jamie Madill48ef11b2016-04-27 15:21:52 -0400236ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500237 : mLabel(),
238 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400239 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300240 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500241 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
242 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400243{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300244 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400245}
246
Jamie Madill48ef11b2016-04-27 15:21:52 -0400247ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400248{
249 if (mAttachedVertexShader != nullptr)
250 {
251 mAttachedVertexShader->release();
252 }
253
254 if (mAttachedFragmentShader != nullptr)
255 {
256 mAttachedFragmentShader->release();
257 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300258
259 if (mAttachedComputeShader != nullptr)
260 {
261 mAttachedComputeShader->release();
262 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400263}
264
Jamie Madill48ef11b2016-04-27 15:21:52 -0400265const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500266{
267 return mLabel;
268}
269
Jamie Madill48ef11b2016-04-27 15:21:52 -0400270const LinkedUniform *ProgramState::getUniformByName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400271{
272 for (const LinkedUniform &linkedUniform : mUniforms)
273 {
274 if (linkedUniform.name == name)
275 {
276 return &linkedUniform;
277 }
278 }
279
280 return nullptr;
281}
282
Jamie Madill48ef11b2016-04-27 15:21:52 -0400283GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400284{
285 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500286 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400287
288 for (size_t location = 0; location < mUniformLocations.size(); ++location)
289 {
290 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400291 if (!uniformLocation.used)
292 {
293 continue;
294 }
295
296 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400297
298 if (uniform.name == baseName)
299 {
Geoff Langd8605522016-04-13 10:19:12 -0400300 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400301 {
Geoff Langd8605522016-04-13 10:19:12 -0400302 if (uniformLocation.element == subscript ||
303 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
304 {
305 return static_cast<GLint>(location);
306 }
307 }
308 else
309 {
310 if (subscript == GL_INVALID_INDEX)
311 {
312 return static_cast<GLint>(location);
313 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400314 }
315 }
316 }
317
318 return -1;
319}
320
Jamie Madill48ef11b2016-04-27 15:21:52 -0400321GLuint ProgramState::getUniformIndex(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400322{
323 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500324 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400325
326 // The app is not allowed to specify array indices other than 0 for arrays of basic types
327 if (subscript != 0 && subscript != GL_INVALID_INDEX)
328 {
329 return GL_INVALID_INDEX;
330 }
331
332 for (size_t index = 0; index < mUniforms.size(); index++)
333 {
334 const LinkedUniform &uniform = mUniforms[index];
335 if (uniform.name == baseName)
336 {
337 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
338 {
339 return static_cast<GLuint>(index);
340 }
341 }
342 }
343
344 return GL_INVALID_INDEX;
345}
346
Jamie Madill7aea7e02016-05-10 10:39:45 -0400347Program::Program(rx::GLImplFactory *factory, ResourceManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400348 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400349 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500350 mLinked(false),
351 mDeleteStatus(false),
352 mRefCount(0),
353 mResourceManager(manager),
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400354 mHandle(handle),
355 mSamplerUniformRange(0, 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500356{
357 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000358
359 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500360 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361}
362
363Program::~Program()
364{
365 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000366
Geoff Lang7dd2e102014-11-10 15:19:26 -0500367 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368}
369
Geoff Lang70d0f492015-12-10 17:45:46 -0500370void Program::setLabel(const std::string &label)
371{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400372 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500373}
374
375const std::string &Program::getLabel() const
376{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400377 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500378}
379
Jamie Madillef300b12016-10-07 15:12:09 -0400380void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300382 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300384 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 {
Jamie Madillef300b12016-10-07 15:12:09 -0400386 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300387 mState.mAttachedVertexShader = shader;
388 mState.mAttachedVertexShader->addRef();
389 break;
390 }
391 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
Jamie Madillef300b12016-10-07 15:12:09 -0400393 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300394 mState.mAttachedFragmentShader = shader;
395 mState.mAttachedFragmentShader->addRef();
396 break;
397 }
398 case GL_COMPUTE_SHADER:
399 {
Jamie Madillef300b12016-10-07 15:12:09 -0400400 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300401 mState.mAttachedComputeShader = shader;
402 mState.mAttachedComputeShader->addRef();
403 break;
404 }
405 default:
406 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000408}
409
410bool Program::detachShader(Shader *shader)
411{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300412 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300414 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300416 if (mState.mAttachedVertexShader != shader)
417 {
418 return false;
419 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420
Martin Radev4c4c8e72016-08-04 12:25:34 +0300421 shader->release();
422 mState.mAttachedVertexShader = nullptr;
423 break;
424 }
425 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300427 if (mState.mAttachedFragmentShader != shader)
428 {
429 return false;
430 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431
Martin Radev4c4c8e72016-08-04 12:25:34 +0300432 shader->release();
433 mState.mAttachedFragmentShader = nullptr;
434 break;
435 }
436 case GL_COMPUTE_SHADER:
437 {
438 if (mState.mAttachedComputeShader != shader)
439 {
440 return false;
441 }
442
443 shader->release();
444 mState.mAttachedComputeShader = nullptr;
445 break;
446 }
447 default:
448 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451 return true;
452}
453
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000454int Program::getAttachedShadersCount() const
455{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300456 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
457 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000458}
459
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460void Program::bindAttributeLocation(GLuint index, const char *name)
461{
Geoff Langd8605522016-04-13 10:19:12 -0400462 mAttributeBindings.bindLocation(index, name);
463}
464
465void Program::bindUniformLocation(GLuint index, const char *name)
466{
467 // Bind the base uniform name only since array indices other than 0 cannot be bound
468 mUniformBindings.bindLocation(index, ParseUniformName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469}
470
Sami Väisänen46eaa942016-06-29 10:26:37 +0300471void Program::bindFragmentInputLocation(GLint index, const char *name)
472{
473 mFragmentInputBindings.bindLocation(index, name);
474}
475
476BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
477{
478 BindingInfo ret;
479 ret.type = GL_NONE;
480 ret.valid = false;
481
482 const Shader *fragmentShader = mState.getAttachedFragmentShader();
483 ASSERT(fragmentShader);
484
485 // Find the actual fragment shader varying we're interested in
486 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
487
488 for (const auto &binding : mFragmentInputBindings)
489 {
490 if (binding.second != static_cast<GLuint>(index))
491 continue;
492
493 ret.valid = true;
494
495 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400496 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300497
498 for (const auto &in : inputs)
499 {
500 if (in.name == originalName)
501 {
502 if (in.isArray())
503 {
504 // The client wants to bind either "name" or "name[0]".
505 // GL ES 3.1 spec refers to active array names with language such as:
506 // "if the string identifies the base name of an active array, where the
507 // string would exactly match the name of the variable if the suffix "[0]"
508 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400509 if (arrayIndex == GL_INVALID_INDEX)
510 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300511
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400512 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300513 }
514 else
515 {
516 ret.name = in.mappedName;
517 }
518 ret.type = in.type;
519 return ret;
520 }
521 }
522 }
523
524 return ret;
525}
526
527void Program::pathFragmentInputGen(GLint index,
528 GLenum genMode,
529 GLint components,
530 const GLfloat *coeffs)
531{
532 // If the location is -1 then the command is silently ignored
533 if (index == -1)
534 return;
535
536 const auto &binding = getFragmentInputBindingInfo(index);
537
538 // If the input doesn't exist then then the command is silently ignored
539 // This could happen through optimization for example, the shader translator
540 // decides that a variable is not actually being used and optimizes it away.
541 if (binding.name.empty())
542 return;
543
544 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
545}
546
Martin Radev4c4c8e72016-08-04 12:25:34 +0300547// The attached shaders are checked for linking errors by matching up their variables.
548// Uniform, input and output variables get collected.
549// The code gets compiled into binaries.
Jamie Madill9082b982016-04-27 15:21:51 -0400550Error Program::link(const ContextState &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000551{
552 unlink(false);
553
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000554 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000555 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000556
Martin Radev4c4c8e72016-08-04 12:25:34 +0300557 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500558
Martin Radev4c4c8e72016-08-04 12:25:34 +0300559 bool isComputeShaderAttached = (mState.mAttachedComputeShader != nullptr);
560 bool nonComputeShadersAttached =
561 (mState.mAttachedVertexShader != nullptr || mState.mAttachedFragmentShader != nullptr);
562 // Check whether we both have a compute and non-compute shaders attached.
563 // If there are of both types attached, then linking should fail.
564 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
565 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500566 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300567 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
568 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400569 }
570
Martin Radev4c4c8e72016-08-04 12:25:34 +0300571 if (mState.mAttachedComputeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500572 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300573 if (!mState.mAttachedComputeShader->isCompiled())
574 {
575 mInfoLog << "Attached compute shader is not compiled.";
576 return NoError();
577 }
578 ASSERT(mState.mAttachedComputeShader->getType() == GL_COMPUTE_SHADER);
579
580 mState.mComputeShaderLocalSize = mState.mAttachedComputeShader->getWorkGroupSize();
581
582 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
583 // If the work group size is not specified, a link time error should occur.
584 if (!mState.mComputeShaderLocalSize.isDeclared())
585 {
586 mInfoLog << "Work group size is not specified.";
587 return NoError();
588 }
589
590 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
591 {
592 return NoError();
593 }
594
595 if (!linkUniformBlocks(mInfoLog, caps))
596 {
597 return NoError();
598 }
599
Jamie Madillb0a838b2016-11-13 20:02:12 -0500600 ANGLE_TRY_RESULT(mProgram->link(data, mInfoLog), mLinked);
601 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300602 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500603 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300604 }
605 }
606 else
607 {
608 if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled())
609 {
610 return NoError();
611 }
612 ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
613
614 if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled())
615 {
616 return NoError();
617 }
618 ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
619
620 if (mState.mAttachedFragmentShader->getShaderVersion() !=
621 mState.mAttachedVertexShader->getShaderVersion())
622 {
623 mInfoLog << "Fragment shader version does not match vertex shader version.";
624 return NoError();
625 }
626
Jamie Madilleb979bf2016-11-15 12:28:46 -0500627 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300628 {
629 return NoError();
630 }
631
632 if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
633 {
634 return NoError();
635 }
636
637 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
638 {
639 return NoError();
640 }
641
642 if (!linkUniformBlocks(mInfoLog, caps))
643 {
644 return NoError();
645 }
646
647 const auto &mergedVaryings = getMergedVaryings();
648
649 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
650 {
651 return NoError();
652 }
653
654 linkOutputVariables();
655
Jamie Madillb0a838b2016-11-13 20:02:12 -0500656 ANGLE_TRY_RESULT(mProgram->link(data, mInfoLog), mLinked);
657 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300658 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500659 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300660 }
661
662 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500663 }
664
Jamie Madill4a3c2342015-10-08 12:58:45 -0400665 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400666
Martin Radev4c4c8e72016-08-04 12:25:34 +0300667 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000668}
669
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000670// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000671void Program::unlink(bool destroy)
672{
673 if (destroy) // Object being destructed
674 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400675 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000676 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400677 mState.mAttachedFragmentShader->release();
678 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679 }
680
Jamie Madill48ef11b2016-04-27 15:21:52 -0400681 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400683 mState.mAttachedVertexShader->release();
684 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000685 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300686
687 if (mState.mAttachedComputeShader)
688 {
689 mState.mAttachedComputeShader->release();
690 mState.mAttachedComputeShader = nullptr;
691 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692 }
693
Jamie Madill48ef11b2016-04-27 15:21:52 -0400694 mState.mAttributes.clear();
695 mState.mActiveAttribLocationsMask.reset();
696 mState.mTransformFeedbackVaryingVars.clear();
697 mState.mUniforms.clear();
698 mState.mUniformLocations.clear();
699 mState.mUniformBlocks.clear();
700 mState.mOutputVariables.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300701 mState.mComputeShaderLocalSize.fill(1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500702
Geoff Lang7dd2e102014-11-10 15:19:26 -0500703 mValidated = false;
704
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000705 mLinked = false;
706}
707
Geoff Lange1a27752015-10-05 13:16:04 -0400708bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000709{
710 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000711}
712
Jamie Madilla2c74982016-12-12 11:20:42 -0500713Error Program::loadBinary(const Context *context,
714 GLenum binaryFormat,
715 const void *binary,
716 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000717{
718 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000719
Geoff Lang7dd2e102014-11-10 15:19:26 -0500720#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
721 return Error(GL_NO_ERROR);
722#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400723 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
724 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000725 {
Jamie Madillf6113162015-05-07 11:49:21 -0400726 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500727 return Error(GL_NO_ERROR);
728 }
729
Geoff Langc46cc2f2015-10-01 17:16:20 -0400730 BinaryInputStream stream(binary, length);
731
Jamie Madilla2c74982016-12-12 11:20:42 -0500732 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
733 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
734 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
735 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500736 {
Jamie Madillf6113162015-05-07 11:49:21 -0400737 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500738 return Error(GL_NO_ERROR);
739 }
740
Jamie Madilla2c74982016-12-12 11:20:42 -0500741 int majorVersion = stream.readInt<int>();
742 int minorVersion = stream.readInt<int>();
743 if (majorVersion != context->getClientMajorVersion() ||
744 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500745 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500746 mInfoLog << "Cannot load program binaries across different ES context versions.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500747 return Error(GL_NO_ERROR);
748 }
749
Martin Radev4c4c8e72016-08-04 12:25:34 +0300750 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
751 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
752 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
753
Jamie Madill63805b42015-08-25 13:17:39 -0400754 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
755 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400756 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500757
Jamie Madill3da79b72015-04-27 11:09:17 -0400758 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400759 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400760 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
761 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400762 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400763 LoadShaderVar(&stream, &attrib);
764 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400765 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400766 }
767
Jamie Madill62d31cb2015-09-11 13:25:51 -0400768 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400769 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400770 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
771 {
772 LinkedUniform uniform;
773 LoadShaderVar(&stream, &uniform);
774
775 uniform.blockIndex = stream.readInt<int>();
776 uniform.blockInfo.offset = stream.readInt<int>();
777 uniform.blockInfo.arrayStride = stream.readInt<int>();
778 uniform.blockInfo.matrixStride = stream.readInt<int>();
779 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
780
Jamie Madill48ef11b2016-04-27 15:21:52 -0400781 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400782 }
783
784 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400785 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400786 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
787 uniformIndexIndex++)
788 {
789 VariableLocation variable;
790 stream.readString(&variable.name);
791 stream.readInt(&variable.element);
792 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400793 stream.readBool(&variable.used);
794 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400795
Jamie Madill48ef11b2016-04-27 15:21:52 -0400796 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400797 }
798
799 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400800 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400801 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
802 ++uniformBlockIndex)
803 {
804 UniformBlock uniformBlock;
805 stream.readString(&uniformBlock.name);
806 stream.readBool(&uniformBlock.isArray);
807 stream.readInt(&uniformBlock.arrayElement);
808 stream.readInt(&uniformBlock.dataSize);
809 stream.readBool(&uniformBlock.vertexStaticUse);
810 stream.readBool(&uniformBlock.fragmentStaticUse);
811
812 unsigned int numMembers = stream.readInt<unsigned int>();
813 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
814 {
815 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
816 }
817
Jamie Madill48ef11b2016-04-27 15:21:52 -0400818 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400819 }
820
Brandon Jones1048ea72015-10-06 15:34:52 -0700821 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400822 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700823 for (unsigned int transformFeedbackVaryingIndex = 0;
824 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
825 ++transformFeedbackVaryingIndex)
826 {
827 sh::Varying varying;
828 stream.readInt(&varying.arraySize);
829 stream.readInt(&varying.type);
830 stream.readString(&varying.name);
831
Jamie Madill48ef11b2016-04-27 15:21:52 -0400832 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700833 }
834
Jamie Madill48ef11b2016-04-27 15:21:52 -0400835 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400836
Jamie Madill80a6fc02015-08-21 16:53:16 -0400837 unsigned int outputVarCount = stream.readInt<unsigned int>();
838 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
839 {
840 int locationIndex = stream.readInt<int>();
841 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400842 stream.readInt(&locationData.element);
843 stream.readInt(&locationData.index);
844 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400845 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400846 }
847
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400848 stream.readInt(&mSamplerUniformRange.start);
849 stream.readInt(&mSamplerUniformRange.end);
850
Jamie Madillb0a838b2016-11-13 20:02:12 -0500851 ANGLE_TRY_RESULT(mProgram->load(mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000852
Jamie Madillb0a838b2016-11-13 20:02:12 -0500853 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500854#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500855}
856
Jamie Madilla2c74982016-12-12 11:20:42 -0500857Error Program::saveBinary(const Context *context,
858 GLenum *binaryFormat,
859 void *binary,
860 GLsizei bufSize,
861 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500862{
863 if (binaryFormat)
864 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400865 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500866 }
867
868 BinaryOutputStream stream;
869
Geoff Lang7dd2e102014-11-10 15:19:26 -0500870 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
871
Jamie Madilla2c74982016-12-12 11:20:42 -0500872 // nullptr context is supported when computing binary length.
873 if (context)
874 {
875 stream.writeInt(context->getClientVersion().major);
876 stream.writeInt(context->getClientVersion().minor);
877 }
878 else
879 {
880 stream.writeInt(2);
881 stream.writeInt(0);
882 }
883
Martin Radev4c4c8e72016-08-04 12:25:34 +0300884 stream.writeInt(mState.mComputeShaderLocalSize[0]);
885 stream.writeInt(mState.mComputeShaderLocalSize[1]);
886 stream.writeInt(mState.mComputeShaderLocalSize[2]);
887
Jamie Madill48ef11b2016-04-27 15:21:52 -0400888 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500889
Jamie Madill48ef11b2016-04-27 15:21:52 -0400890 stream.writeInt(mState.mAttributes.size());
891 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400892 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400893 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400894 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400895 }
896
Jamie Madill48ef11b2016-04-27 15:21:52 -0400897 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500898 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400899 {
900 WriteShaderVar(&stream, uniform);
901
902 // FIXME: referenced
903
904 stream.writeInt(uniform.blockIndex);
905 stream.writeInt(uniform.blockInfo.offset);
906 stream.writeInt(uniform.blockInfo.arrayStride);
907 stream.writeInt(uniform.blockInfo.matrixStride);
908 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
909 }
910
Jamie Madill48ef11b2016-04-27 15:21:52 -0400911 stream.writeInt(mState.mUniformLocations.size());
912 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400913 {
914 stream.writeString(variable.name);
915 stream.writeInt(variable.element);
916 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400917 stream.writeInt(variable.used);
918 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400919 }
920
Jamie Madill48ef11b2016-04-27 15:21:52 -0400921 stream.writeInt(mState.mUniformBlocks.size());
922 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400923 {
924 stream.writeString(uniformBlock.name);
925 stream.writeInt(uniformBlock.isArray);
926 stream.writeInt(uniformBlock.arrayElement);
927 stream.writeInt(uniformBlock.dataSize);
928
929 stream.writeInt(uniformBlock.vertexStaticUse);
930 stream.writeInt(uniformBlock.fragmentStaticUse);
931
932 stream.writeInt(uniformBlock.memberUniformIndexes.size());
933 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
934 {
935 stream.writeInt(memberUniformIndex);
936 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400937 }
938
Jamie Madill48ef11b2016-04-27 15:21:52 -0400939 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
940 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700941 {
942 stream.writeInt(varying.arraySize);
943 stream.writeInt(varying.type);
944 stream.writeString(varying.name);
945 }
946
Jamie Madill48ef11b2016-04-27 15:21:52 -0400947 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400948
Jamie Madill48ef11b2016-04-27 15:21:52 -0400949 stream.writeInt(mState.mOutputVariables.size());
950 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -0400951 {
952 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -0400953 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400954 stream.writeInt(outputPair.second.index);
955 stream.writeString(outputPair.second.name);
956 }
957
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400958 stream.writeInt(mSamplerUniformRange.start);
959 stream.writeInt(mSamplerUniformRange.end);
960
Jamie Madilla2c74982016-12-12 11:20:42 -0500961 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -0500962
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700963 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -0400964 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500965
966 if (streamLength > bufSize)
967 {
968 if (length)
969 {
970 *length = 0;
971 }
972
973 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
974 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
975 // sizes and then copy it.
976 return Error(GL_INVALID_OPERATION);
977 }
978
979 if (binary)
980 {
981 char *ptr = reinterpret_cast<char*>(binary);
982
Jamie Madill48ef11b2016-04-27 15:21:52 -0400983 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500984 ptr += streamLength;
985
986 ASSERT(ptr - streamLength == binary);
987 }
988
989 if (length)
990 {
991 *length = streamLength;
992 }
993
994 return Error(GL_NO_ERROR);
995}
996
997GLint Program::getBinaryLength() const
998{
999 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001000 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001 if (error.isError())
1002 {
1003 return 0;
1004 }
1005
1006 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001007}
1008
Geoff Langc5629752015-12-07 16:29:04 -05001009void Program::setBinaryRetrievableHint(bool retrievable)
1010{
1011 // TODO(jmadill) : replace with dirty bits
1012 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001013 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001014}
1015
1016bool Program::getBinaryRetrievableHint() const
1017{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001018 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001019}
1020
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001021void Program::release()
1022{
1023 mRefCount--;
1024
1025 if (mRefCount == 0 && mDeleteStatus)
1026 {
1027 mResourceManager->deleteProgram(mHandle);
1028 }
1029}
1030
1031void Program::addRef()
1032{
1033 mRefCount++;
1034}
1035
1036unsigned int Program::getRefCount() const
1037{
1038 return mRefCount;
1039}
1040
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001041int Program::getInfoLogLength() const
1042{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001043 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001044}
1045
Geoff Lange1a27752015-10-05 13:16:04 -04001046void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001047{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001048 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001049}
1050
Geoff Lange1a27752015-10-05 13:16:04 -04001051void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001052{
1053 int total = 0;
1054
Martin Radev4c4c8e72016-08-04 12:25:34 +03001055 if (mState.mAttachedComputeShader)
1056 {
1057 if (total < maxCount)
1058 {
1059 shaders[total] = mState.mAttachedComputeShader->getHandle();
1060 total++;
1061 }
1062 }
1063
Jamie Madill48ef11b2016-04-27 15:21:52 -04001064 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001065 {
1066 if (total < maxCount)
1067 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001068 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001069 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001070 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001071 }
1072
Jamie Madill48ef11b2016-04-27 15:21:52 -04001073 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001074 {
1075 if (total < maxCount)
1076 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001077 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001078 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001079 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001080 }
1081
1082 if (count)
1083 {
1084 *count = total;
1085 }
1086}
1087
Geoff Lange1a27752015-10-05 13:16:04 -04001088GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001089{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001090 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001091 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001092 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001093 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001094 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001095 }
1096 }
1097
Austin Kinrossb8af7232015-03-16 22:33:25 -07001098 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001099}
1100
Jamie Madill63805b42015-08-25 13:17:39 -04001101bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001102{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001103 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1104 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001105}
1106
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001107void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1108{
Jamie Madillc349ec02015-08-21 16:53:12 -04001109 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001110 {
1111 if (bufsize > 0)
1112 {
1113 name[0] = '\0';
1114 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001115
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001116 if (length)
1117 {
1118 *length = 0;
1119 }
1120
1121 *type = GL_NONE;
1122 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001123 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001124 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001125
1126 size_t attributeIndex = 0;
1127
Jamie Madill48ef11b2016-04-27 15:21:52 -04001128 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001129 {
1130 // Skip over inactive attributes
1131 if (attribute.staticUse)
1132 {
1133 if (static_cast<size_t>(index) == attributeIndex)
1134 {
1135 break;
1136 }
1137 attributeIndex++;
1138 }
1139 }
1140
Jamie Madill48ef11b2016-04-27 15:21:52 -04001141 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
1142 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -04001143
1144 if (bufsize > 0)
1145 {
1146 const char *string = attrib.name.c_str();
1147
1148 strncpy(name, string, bufsize);
1149 name[bufsize - 1] = '\0';
1150
1151 if (length)
1152 {
1153 *length = static_cast<GLsizei>(strlen(name));
1154 }
1155 }
1156
1157 // Always a single 'type' instance
1158 *size = 1;
1159 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001160}
1161
Geoff Lange1a27752015-10-05 13:16:04 -04001162GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001163{
Jamie Madillc349ec02015-08-21 16:53:12 -04001164 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001165 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001166 return 0;
1167 }
1168
1169 GLint count = 0;
1170
Jamie Madill48ef11b2016-04-27 15:21:52 -04001171 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001172 {
1173 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001174 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001175
1176 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001177}
1178
Geoff Lange1a27752015-10-05 13:16:04 -04001179GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001180{
Jamie Madillc349ec02015-08-21 16:53:12 -04001181 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001182 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001183 return 0;
1184 }
1185
1186 size_t maxLength = 0;
1187
Jamie Madill48ef11b2016-04-27 15:21:52 -04001188 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001189 {
1190 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001191 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001192 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001193 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001194 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001195
Jamie Madillc349ec02015-08-21 16:53:12 -04001196 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001197}
1198
Geoff Lang7dd2e102014-11-10 15:19:26 -05001199GLint Program::getFragDataLocation(const std::string &name) const
1200{
1201 std::string baseName(name);
1202 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001203 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001204 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001205 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001206 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1207 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001208 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001209 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001210 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001211 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001212}
1213
Geoff Lange1a27752015-10-05 13:16:04 -04001214void Program::getActiveUniform(GLuint index,
1215 GLsizei bufsize,
1216 GLsizei *length,
1217 GLint *size,
1218 GLenum *type,
1219 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001220{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001221 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001222 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001223 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001224 ASSERT(index < mState.mUniforms.size());
1225 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001226
1227 if (bufsize > 0)
1228 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001229 std::string string = uniform.name;
1230 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001231 {
1232 string += "[0]";
1233 }
1234
1235 strncpy(name, string.c_str(), bufsize);
1236 name[bufsize - 1] = '\0';
1237
1238 if (length)
1239 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001240 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001241 }
1242 }
1243
Jamie Madill62d31cb2015-09-11 13:25:51 -04001244 *size = uniform.elementCount();
1245 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001246 }
1247 else
1248 {
1249 if (bufsize > 0)
1250 {
1251 name[0] = '\0';
1252 }
1253
1254 if (length)
1255 {
1256 *length = 0;
1257 }
1258
1259 *size = 0;
1260 *type = GL_NONE;
1261 }
1262}
1263
Geoff Lange1a27752015-10-05 13:16:04 -04001264GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001265{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001266 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001267 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001268 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001269 }
1270 else
1271 {
1272 return 0;
1273 }
1274}
1275
Geoff Lange1a27752015-10-05 13:16:04 -04001276GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001277{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001278 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001279
1280 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001281 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001282 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001283 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001284 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001285 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001286 size_t length = uniform.name.length() + 1u;
1287 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001288 {
1289 length += 3; // Counting in "[0]".
1290 }
1291 maxLength = std::max(length, maxLength);
1292 }
1293 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001294 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001295
Jamie Madill62d31cb2015-09-11 13:25:51 -04001296 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001297}
1298
1299GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1300{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001301 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001302 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001303 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001304 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001305 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1306 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1307 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1308 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1309 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1310 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1311 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1312 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1313 default:
1314 UNREACHABLE();
1315 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001316 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001317 return 0;
1318}
1319
1320bool Program::isValidUniformLocation(GLint location) const
1321{
Jamie Madille2e406c2016-06-02 13:04:10 -04001322 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001323 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1324 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001325}
1326
1327bool Program::isIgnoredUniformLocation(GLint location) const
1328{
1329 // Location is ignored if it is -1 or it was bound but non-existant in the shader or optimized
1330 // out
1331 return location == -1 ||
Jamie Madill48ef11b2016-04-27 15:21:52 -04001332 (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1333 mState.mUniformLocations[static_cast<size_t>(location)].ignored);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001334}
1335
Jamie Madill62d31cb2015-09-11 13:25:51 -04001336const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001337{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001338 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1339 return mState.mUniforms[mState.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001340}
1341
Jamie Madill62d31cb2015-09-11 13:25:51 -04001342GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001343{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001344 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001345}
1346
Jamie Madill62d31cb2015-09-11 13:25:51 -04001347GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001348{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001349 return mState.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001350}
1351
1352void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1353{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001354 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1355 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001356}
1357
1358void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1359{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001360 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1361 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001362}
1363
1364void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1365{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001366 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1367 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001368}
1369
1370void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1371{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001372 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1373 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001374}
1375
1376void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1377{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001378 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1379 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380}
1381
1382void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1383{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001384 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1385 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386}
1387
1388void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1389{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001390 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1391 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392}
1393
1394void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1395{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001396 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1397 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398}
1399
1400void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1401{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001402 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1403 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001404}
1405
1406void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1407{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001408 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1409 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001410}
1411
1412void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1413{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001414 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1415 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416}
1417
1418void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1419{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001420 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1421 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001422}
1423
1424void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1425{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001426 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1427 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001428}
1429
1430void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1431{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001432 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1433 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001434}
1435
1436void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1437{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001438 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1439 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001440}
1441
1442void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1443{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001444 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1445 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446}
1447
1448void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1449{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001450 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1451 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001452}
1453
1454void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1455{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001456 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1457 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001458}
1459
1460void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1461{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001462 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1463 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001464}
1465
1466void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1467{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001468 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1469 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001470}
1471
1472void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1473{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001474 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1475 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001476}
1477
Geoff Lange1a27752015-10-05 13:16:04 -04001478void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001480 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481}
1482
Geoff Lange1a27752015-10-05 13:16:04 -04001483void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001484{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001485 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001486}
1487
Geoff Lange1a27752015-10-05 13:16:04 -04001488void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001489{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001490 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493void Program::flagForDeletion()
1494{
1495 mDeleteStatus = true;
1496}
1497
1498bool Program::isFlaggedForDeletion() const
1499{
1500 return mDeleteStatus;
1501}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001502
Brandon Jones43a53e22014-08-28 16:23:22 -07001503void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001504{
1505 mInfoLog.reset();
1506
Geoff Lang7dd2e102014-11-10 15:19:26 -05001507 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001508 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001509 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001510 }
1511 else
1512 {
Jamie Madillf6113162015-05-07 11:49:21 -04001513 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001514 }
1515}
1516
Geoff Lang7dd2e102014-11-10 15:19:26 -05001517bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1518{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001519 // Skip cache if we're using an infolog, so we get the full error.
1520 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1521 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1522 {
1523 return mCachedValidateSamplersResult.value();
1524 }
1525
1526 if (mTextureUnitTypesCache.empty())
1527 {
1528 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1529 }
1530 else
1531 {
1532 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1533 }
1534
1535 // if any two active samplers in a program are of different types, but refer to the same
1536 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1537 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1538 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1539 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1540 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001541 const LinkedUniform &uniform = mState.mUniforms[samplerIndex];
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001542 ASSERT(uniform.isSampler());
1543
1544 if (!uniform.staticUse)
1545 continue;
1546
1547 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1548 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1549
1550 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1551 {
1552 GLuint textureUnit = dataPtr[arrayElement];
1553
1554 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1555 {
1556 if (infoLog)
1557 {
1558 (*infoLog) << "Sampler uniform (" << textureUnit
1559 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1560 << caps.maxCombinedTextureImageUnits << ")";
1561 }
1562
1563 mCachedValidateSamplersResult = false;
1564 return false;
1565 }
1566
1567 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1568 {
1569 if (textureType != mTextureUnitTypesCache[textureUnit])
1570 {
1571 if (infoLog)
1572 {
1573 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1574 "image unit ("
1575 << textureUnit << ").";
1576 }
1577
1578 mCachedValidateSamplersResult = false;
1579 return false;
1580 }
1581 }
1582 else
1583 {
1584 mTextureUnitTypesCache[textureUnit] = textureType;
1585 }
1586 }
1587 }
1588
1589 mCachedValidateSamplersResult = true;
1590 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001591}
1592
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001593bool Program::isValidated() const
1594{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001595 return mValidated;
1596}
1597
Geoff Lange1a27752015-10-05 13:16:04 -04001598GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001599{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001600 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001601}
1602
1603void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1604{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001605 ASSERT(
1606 uniformBlockIndex <
1607 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001608
Jamie Madill48ef11b2016-04-27 15:21:52 -04001609 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001610
1611 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001612 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001613 std::string string = uniformBlock.name;
1614
Jamie Madill62d31cb2015-09-11 13:25:51 -04001615 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001616 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001617 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001618 }
1619
1620 strncpy(uniformBlockName, string.c_str(), bufSize);
1621 uniformBlockName[bufSize - 1] = '\0';
1622
1623 if (length)
1624 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001625 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001627 }
1628}
1629
Geoff Lange1a27752015-10-05 13:16:04 -04001630GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001631{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001632 int maxLength = 0;
1633
1634 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001635 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001636 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001637 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1638 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001639 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001640 if (!uniformBlock.name.empty())
1641 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001642 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001643
1644 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001645 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001646
1647 maxLength = std::max(length + arrayLength, maxLength);
1648 }
1649 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001650 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001651
1652 return maxLength;
1653}
1654
Geoff Lange1a27752015-10-05 13:16:04 -04001655GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001657 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -05001658 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001659
Jamie Madill48ef11b2016-04-27 15:21:52 -04001660 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001661 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1662 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001663 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001664 if (uniformBlock.name == baseName)
1665 {
1666 const bool arrayElementZero =
1667 (subscript == GL_INVALID_INDEX &&
1668 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1669 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1670 {
1671 return blockIndex;
1672 }
1673 }
1674 }
1675
1676 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001677}
1678
Jamie Madill62d31cb2015-09-11 13:25:51 -04001679const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001680{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001681 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1682 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001683}
1684
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001685void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1686{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001687 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Geoff Lang5d124a62015-09-15 13:03:27 -04001688 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001689}
1690
1691GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1692{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001693 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001694}
1695
1696void Program::resetUniformBlockBindings()
1697{
1698 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1699 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001700 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001701 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001702 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001703}
1704
Geoff Lang48dcae72014-02-05 16:28:24 -05001705void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1706{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001707 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001708 for (GLsizei i = 0; i < count; i++)
1709 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001710 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001711 }
1712
Jamie Madill48ef11b2016-04-27 15:21:52 -04001713 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001714}
1715
1716void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1717{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001718 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001719 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001720 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1721 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001722 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1723 if (length)
1724 {
1725 *length = lastNameIdx;
1726 }
1727 if (size)
1728 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001729 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001730 }
1731 if (type)
1732 {
1733 *type = varying.type;
1734 }
1735 if (name)
1736 {
1737 memcpy(name, varying.name.c_str(), lastNameIdx);
1738 name[lastNameIdx] = '\0';
1739 }
1740 }
1741}
1742
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001743GLsizei Program::getTransformFeedbackVaryingCount() const
1744{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001745 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001746 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001747 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001748 }
1749 else
1750 {
1751 return 0;
1752 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001753}
1754
1755GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1756{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001757 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001758 {
1759 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001760 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001761 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001762 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1763 }
1764
1765 return maxSize;
1766 }
1767 else
1768 {
1769 return 0;
1770 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001771}
1772
1773GLenum Program::getTransformFeedbackBufferMode() const
1774{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001775 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001776}
1777
Jamie Madillada9ecc2015-08-17 12:53:37 -04001778bool Program::linkVaryings(InfoLog &infoLog,
1779 const Shader *vertexShader,
Sami Väisänen46eaa942016-06-29 10:26:37 +03001780 const Shader *fragmentShader) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001781{
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001782 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1783
Jamie Madill4cff2472015-08-21 16:53:18 -04001784 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1785 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786
Sami Väisänen46eaa942016-06-29 10:26:37 +03001787 std::map<GLuint, std::string> staticFragmentInputLocations;
1788
Jamie Madill4cff2472015-08-21 16:53:18 -04001789 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001790 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001791 bool matched = false;
1792
1793 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001794 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001795 {
1796 continue;
1797 }
1798
Jamie Madill4cff2472015-08-21 16:53:18 -04001799 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001800 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001801 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001803 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001804 if (!linkValidateVaryings(infoLog, output.name, input, output,
1805 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001806 {
1807 return false;
1808 }
1809
Geoff Lang7dd2e102014-11-10 15:19:26 -05001810 matched = true;
1811 break;
1812 }
1813 }
1814
1815 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001816 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001817 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001818 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001819 return false;
1820 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001821
1822 // Check for aliased path rendering input bindings (if any).
1823 // If more than one binding refer statically to the same
1824 // location the link must fail.
1825
1826 if (!output.staticUse)
1827 continue;
1828
1829 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1830 if (inputBinding == -1)
1831 continue;
1832
1833 const auto it = staticFragmentInputLocations.find(inputBinding);
1834 if (it == std::end(staticFragmentInputLocations))
1835 {
1836 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1837 }
1838 else
1839 {
1840 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1841 << it->second;
1842 return false;
1843 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001844 }
1845
Jamie Madillada9ecc2015-08-17 12:53:37 -04001846 // TODO(jmadill): verify no unmatched vertex varyings?
1847
Geoff Lang7dd2e102014-11-10 15:19:26 -05001848 return true;
1849}
1850
Martin Radev4c4c8e72016-08-04 12:25:34 +03001851bool Program::validateVertexAndFragmentUniforms(InfoLog &infoLog) const
Jamie Madillea918db2015-08-18 14:48:59 -04001852{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001853 // Check that uniforms defined in the vertex and fragment shaders are identical
1854 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001855 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1856 const std::vector<sh::Uniform> &fragmentUniforms =
1857 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001858
Jamie Madillea918db2015-08-18 14:48:59 -04001859 for (const sh::Uniform &vertexUniform : vertexUniforms)
1860 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001861 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001862 }
1863
1864 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1865 {
1866 auto entry = linkedUniforms.find(fragmentUniform.name);
1867 if (entry != linkedUniforms.end())
1868 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001869 LinkedUniform *vertexUniform = &entry->second;
1870 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1871 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001872 {
1873 return false;
1874 }
1875 }
1876 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03001877 return true;
1878}
1879
Jamie Madilla2c74982016-12-12 11:20:42 -05001880bool Program::linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001881{
1882 if (mState.mAttachedVertexShader && mState.mAttachedFragmentShader)
1883 {
1884 ASSERT(mState.mAttachedComputeShader == nullptr);
1885 if (!validateVertexAndFragmentUniforms(infoLog))
1886 {
1887 return false;
1888 }
1889 }
Jamie Madillea918db2015-08-18 14:48:59 -04001890
Jamie Madill62d31cb2015-09-11 13:25:51 -04001891 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1892 // Also check the maximum uniform vector and sampler counts.
1893 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1894 {
1895 return false;
1896 }
1897
Geoff Langd8605522016-04-13 10:19:12 -04001898 if (!indexUniforms(infoLog, caps, uniformBindings))
1899 {
1900 return false;
1901 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001902
Jamie Madillea918db2015-08-18 14:48:59 -04001903 return true;
1904}
1905
Jamie Madilla2c74982016-12-12 11:20:42 -05001906bool Program::indexUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001907{
Geoff Langd8605522016-04-13 10:19:12 -04001908 // Uniforms awaiting a location
1909 std::vector<VariableLocation> unboundUniforms;
1910 std::map<GLuint, VariableLocation> boundUniforms;
1911 int maxUniformLocation = -1;
1912
1913 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001914 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001915 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001916 const LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001917
Geoff Langd8605522016-04-13 10:19:12 -04001918 if (uniform.isBuiltIn())
1919 {
1920 continue;
1921 }
1922
1923 int bindingLocation = uniformBindings.getBinding(uniform.name);
1924
1925 // Verify that this location isn't bound twice
1926 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
1927 {
1928 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
1929 return false;
1930 }
1931
Jamie Madill62d31cb2015-09-11 13:25:51 -04001932 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1933 {
Geoff Langd8605522016-04-13 10:19:12 -04001934 VariableLocation location(uniform.name, arrayIndex,
1935 static_cast<unsigned int>(uniformIndex));
1936
1937 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001938 {
Geoff Langd8605522016-04-13 10:19:12 -04001939 boundUniforms[bindingLocation] = location;
1940 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
1941 }
1942 else
1943 {
1944 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001945 }
1946 }
1947 }
Geoff Langd8605522016-04-13 10:19:12 -04001948
1949 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
1950 // not be assigned to those locations.
1951 std::set<GLuint> reservedLocations;
1952 for (const auto &binding : uniformBindings)
1953 {
1954 GLuint location = binding.second;
1955 if (boundUniforms.find(location) == boundUniforms.end())
1956 {
1957 reservedLocations.insert(location);
1958 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
1959 }
1960 }
1961
1962 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04001963 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04001964 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
1965 static_cast<size_t>(maxUniformLocation + 1)));
1966
1967 // Assign bound uniforms
1968 for (const auto &boundUniform : boundUniforms)
1969 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001970 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04001971 }
1972
1973 // Assign reserved uniforms
1974 for (const auto &reservedLocation : reservedLocations)
1975 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001976 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04001977 }
1978
1979 // Assign unbound uniforms
1980 size_t nextUniformLocation = 0;
1981 for (const auto &unboundUniform : unboundUniforms)
1982 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001983 while (mState.mUniformLocations[nextUniformLocation].used ||
1984 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04001985 {
1986 nextUniformLocation++;
1987 }
1988
Jamie Madill48ef11b2016-04-27 15:21:52 -04001989 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
1990 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04001991 nextUniformLocation++;
1992 }
1993
1994 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04001995}
1996
Martin Radev4c4c8e72016-08-04 12:25:34 +03001997bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
1998 const std::string &uniformName,
1999 const sh::InterfaceBlockField &vertexUniform,
2000 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002001{
Jamie Madillc4c744222015-11-04 09:39:47 -05002002 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
2003 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002004 {
2005 return false;
2006 }
2007
2008 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2009 {
Jamie Madillf6113162015-05-07 11:49:21 -04002010 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002011 return false;
2012 }
2013
2014 return true;
2015}
2016
Jamie Madilleb979bf2016-11-15 12:28:46 -05002017// Assigns locations to all attributes from the bindings and program locations.
2018bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002019{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002020 const auto *vertexShader = mState.getAttachedVertexShader();
2021
Geoff Lang7dd2e102014-11-10 15:19:26 -05002022 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002023 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002024 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002025
2026 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002027 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002028 {
Jamie Madillf6113162015-05-07 11:49:21 -04002029 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002030 return false;
2031 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002032
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002033 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002034
Jamie Madillc349ec02015-08-21 16:53:12 -04002035 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002036 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002037 {
2038 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05002039 ASSERT(attribute.staticUse);
2040
Jamie Madilleb979bf2016-11-15 12:28:46 -05002041 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002042 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002043 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002044 attribute.location = bindingLocation;
2045 }
2046
2047 if (attribute.location != -1)
2048 {
2049 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002050 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002051
Jamie Madill63805b42015-08-25 13:17:39 -04002052 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002053 {
Jamie Madillf6113162015-05-07 11:49:21 -04002054 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002055 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002056
2057 return false;
2058 }
2059
Jamie Madill63805b42015-08-25 13:17:39 -04002060 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002061 {
Jamie Madill63805b42015-08-25 13:17:39 -04002062 const int regLocation = attribute.location + reg;
2063 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064
2065 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002066 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002067 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002068 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002069 // TODO(jmadill): fix aliasing on ES2
2070 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002072 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002073 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002074 return false;
2075 }
2076 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002077 else
2078 {
Jamie Madill63805b42015-08-25 13:17:39 -04002079 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002080 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002081
Jamie Madill63805b42015-08-25 13:17:39 -04002082 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002083 }
2084 }
2085 }
2086
2087 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002088 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002089 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002090 ASSERT(attribute.staticUse);
2091
Jamie Madillc349ec02015-08-21 16:53:12 -04002092 // Not set by glBindAttribLocation or by location layout qualifier
2093 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002094 {
Jamie Madill63805b42015-08-25 13:17:39 -04002095 int regs = VariableRegisterCount(attribute.type);
2096 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002097
Jamie Madill63805b42015-08-25 13:17:39 -04002098 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002099 {
Jamie Madillf6113162015-05-07 11:49:21 -04002100 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002101 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002102 }
2103
Jamie Madillc349ec02015-08-21 16:53:12 -04002104 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002105 }
2106 }
2107
Jamie Madill48ef11b2016-04-27 15:21:52 -04002108 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002109 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002110 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04002111 ASSERT(attribute.location != -1);
2112 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002113
Jamie Madill63805b42015-08-25 13:17:39 -04002114 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002115 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002116 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002117 }
2118 }
2119
Geoff Lang7dd2e102014-11-10 15:19:26 -05002120 return true;
2121}
2122
Martin Radev4c4c8e72016-08-04 12:25:34 +03002123bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2124 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2125 const std::string &errorMessage,
2126 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002127{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002128 GLuint blockCount = 0;
2129 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002130 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002131 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002132 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002133 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002134 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002135 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002136 return false;
2137 }
2138 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002139 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002140 return true;
2141}
Jamie Madille473dee2015-08-18 14:49:01 -04002142
Martin Radev4c4c8e72016-08-04 12:25:34 +03002143bool Program::validateVertexAndFragmentInterfaceBlocks(
2144 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2145 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2146 InfoLog &infoLog) const
2147{
2148 // Check that interface blocks defined in the vertex and fragment shaders are identical
2149 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2150 UniformBlockMap linkedUniformBlocks;
2151
2152 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2153 {
2154 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2155 }
2156
Jamie Madille473dee2015-08-18 14:49:01 -04002157 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002158 {
Jamie Madille473dee2015-08-18 14:49:01 -04002159 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002160 if (entry != linkedUniformBlocks.end())
2161 {
2162 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2163 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2164 {
2165 return false;
2166 }
2167 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002168 }
2169 return true;
2170}
Jamie Madille473dee2015-08-18 14:49:01 -04002171
Martin Radev4c4c8e72016-08-04 12:25:34 +03002172bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2173{
2174 if (mState.mAttachedComputeShader)
2175 {
2176 const Shader &computeShader = *mState.mAttachedComputeShader;
2177 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2178
2179 if (!validateUniformBlocksCount(
2180 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2181 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2182 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002183 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002184 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002186 return true;
2187 }
2188
2189 const Shader &vertexShader = *mState.mAttachedVertexShader;
2190 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2191
2192 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2193 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2194
2195 if (!validateUniformBlocksCount(
2196 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2197 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2198 {
2199 return false;
2200 }
2201 if (!validateUniformBlocksCount(
2202 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2203 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2204 infoLog))
2205 {
2206
2207 return false;
2208 }
2209 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2210 infoLog))
2211 {
2212 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002213 }
Jamie Madille473dee2015-08-18 14:49:01 -04002214
Geoff Lang7dd2e102014-11-10 15:19:26 -05002215 return true;
2216}
2217
Jamie Madilla2c74982016-12-12 11:20:42 -05002218bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002219 const sh::InterfaceBlock &vertexInterfaceBlock,
2220 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221{
2222 const char* blockName = vertexInterfaceBlock.name.c_str();
2223 // validate blocks for the same member types
2224 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2225 {
Jamie Madillf6113162015-05-07 11:49:21 -04002226 infoLog << "Types for interface block '" << blockName
2227 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002228 return false;
2229 }
2230 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2231 {
Jamie Madillf6113162015-05-07 11:49:21 -04002232 infoLog << "Array sizes differ for interface block '" << blockName
2233 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002234 return false;
2235 }
2236 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2237 {
Jamie Madillf6113162015-05-07 11:49:21 -04002238 infoLog << "Layout qualifiers differ for interface block '" << blockName
2239 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002240 return false;
2241 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002242 const unsigned int numBlockMembers =
2243 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002244 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2245 {
2246 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2247 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2248 if (vertexMember.name != fragmentMember.name)
2249 {
Jamie Madillf6113162015-05-07 11:49:21 -04002250 infoLog << "Name mismatch for field " << blockMemberIndex
2251 << " of interface block '" << blockName
2252 << "': (in vertex: '" << vertexMember.name
2253 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002254 return false;
2255 }
2256 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2257 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2258 {
2259 return false;
2260 }
2261 }
2262 return true;
2263}
2264
2265bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2266 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2267{
2268 if (vertexVariable.type != fragmentVariable.type)
2269 {
Jamie Madillf6113162015-05-07 11:49:21 -04002270 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002271 return false;
2272 }
2273 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2274 {
Jamie Madillf6113162015-05-07 11:49:21 -04002275 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002276 return false;
2277 }
2278 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2279 {
Jamie Madillf6113162015-05-07 11:49:21 -04002280 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002281 return false;
2282 }
2283
2284 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2285 {
Jamie Madillf6113162015-05-07 11:49:21 -04002286 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002287 return false;
2288 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002289 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002290 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2291 {
2292 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2293 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2294
2295 if (vertexMember.name != fragmentMember.name)
2296 {
Jamie Madillf6113162015-05-07 11:49:21 -04002297 infoLog << "Name mismatch for field '" << memberIndex
2298 << "' of " << variableName
2299 << ": (in vertex: '" << vertexMember.name
2300 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002301 return false;
2302 }
2303
2304 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2305 vertexMember.name + "'";
2306
2307 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2308 {
2309 return false;
2310 }
2311 }
2312
2313 return true;
2314}
2315
2316bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2317{
Cooper Partin1acf4382015-06-12 12:38:57 -07002318#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2319 const bool validatePrecision = true;
2320#else
2321 const bool validatePrecision = false;
2322#endif
2323
2324 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002325 {
2326 return false;
2327 }
2328
2329 return true;
2330}
2331
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002332bool Program::linkValidateVaryings(InfoLog &infoLog,
2333 const std::string &varyingName,
2334 const sh::Varying &vertexVarying,
2335 const sh::Varying &fragmentVarying,
2336 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002337{
2338 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2339 {
2340 return false;
2341 }
2342
Jamie Madille9cc4692015-02-19 16:00:13 -05002343 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002344 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002345 infoLog << "Interpolation types for " << varyingName
2346 << " differ between vertex and fragment shaders.";
2347 return false;
2348 }
2349
2350 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2351 {
2352 infoLog << "Invariance for " << varyingName
2353 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002354 return false;
2355 }
2356
2357 return true;
2358}
2359
Jamie Madillccdf74b2015-08-18 10:46:12 -04002360bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2361 const std::vector<const sh::Varying *> &varyings,
2362 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002363{
2364 size_t totalComponents = 0;
2365
Jamie Madillccdf74b2015-08-18 10:46:12 -04002366 std::set<std::string> uniqueNames;
2367
Jamie Madill48ef11b2016-04-27 15:21:52 -04002368 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002369 {
2370 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002371 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002372 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002373 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002374 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002375 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002376 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002377 infoLog << "Two transform feedback varyings specify the same output variable ("
2378 << tfVaryingName << ").";
2379 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002380 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002381 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002382
Geoff Lang1a683462015-09-29 15:09:59 -04002383 if (varying->isArray())
2384 {
2385 infoLog << "Capture of arrays is undefined and not supported.";
2386 return false;
2387 }
2388
Jamie Madillccdf74b2015-08-18 10:46:12 -04002389 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002390 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002391 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 componentCount > caps.maxTransformFeedbackSeparateComponents)
2393 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002394 infoLog << "Transform feedback varying's " << varying->name << " components ("
2395 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002396 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002397 return false;
2398 }
2399
2400 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002401 found = true;
2402 break;
2403 }
2404 }
2405
Jamie Madill89bb70e2015-08-31 14:18:39 -04002406 if (tfVaryingName.find('[') != std::string::npos)
2407 {
Geoff Lang1a683462015-09-29 15:09:59 -04002408 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002409 return false;
2410 }
2411
Geoff Lang7dd2e102014-11-10 15:19:26 -05002412 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2413 ASSERT(found);
2414 }
2415
Jamie Madill48ef11b2016-04-27 15:21:52 -04002416 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002417 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002418 {
Jamie Madillf6113162015-05-07 11:49:21 -04002419 infoLog << "Transform feedback varying total components (" << totalComponents
2420 << ") exceed the maximum interleaved components ("
2421 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002422 return false;
2423 }
2424
2425 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002426}
2427
Jamie Madillccdf74b2015-08-18 10:46:12 -04002428void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2429{
2430 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002431 mState.mTransformFeedbackVaryingVars.clear();
2432 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002433 {
2434 for (const sh::Varying *varying : varyings)
2435 {
2436 if (tfVaryingName == varying->name)
2437 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002438 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002439 break;
2440 }
2441 }
2442 }
2443}
2444
2445std::vector<const sh::Varying *> Program::getMergedVaryings() const
2446{
2447 std::set<std::string> uniqueNames;
2448 std::vector<const sh::Varying *> varyings;
2449
Jamie Madill48ef11b2016-04-27 15:21:52 -04002450 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002451 {
2452 if (uniqueNames.count(varying.name) == 0)
2453 {
2454 uniqueNames.insert(varying.name);
2455 varyings.push_back(&varying);
2456 }
2457 }
2458
Jamie Madill48ef11b2016-04-27 15:21:52 -04002459 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002460 {
2461 if (uniqueNames.count(varying.name) == 0)
2462 {
2463 uniqueNames.insert(varying.name);
2464 varyings.push_back(&varying);
2465 }
2466 }
2467
2468 return varyings;
2469}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002470
2471void Program::linkOutputVariables()
2472{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002473 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002474 ASSERT(fragmentShader != nullptr);
2475
2476 // Skip this step for GLES2 shaders.
2477 if (fragmentShader->getShaderVersion() == 100)
2478 return;
2479
Jamie Madilla0a9e122015-09-02 15:54:30 -04002480 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002481
2482 // TODO(jmadill): any caps validation here?
2483
2484 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2485 outputVariableIndex++)
2486 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002487 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002488
2489 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2490 if (outputVariable.isBuiltIn())
2491 continue;
2492
2493 // Since multiple output locations must be specified, use 0 for non-specified locations.
2494 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2495
2496 ASSERT(outputVariable.staticUse);
2497
2498 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2499 elementIndex++)
2500 {
2501 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002502 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002503 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002504 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002505 VariableLocation(outputVariable.name, element, outputVariableIndex);
2506 }
2507 }
2508}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002509
Jamie Madilla2c74982016-12-12 11:20:42 -05002510bool Program::flattenUniformsAndCheckCapsForShader(const Shader &shader,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002511 GLuint maxUniformComponents,
2512 GLuint maxTextureImageUnits,
2513 const std::string &componentsErrorMessage,
2514 const std::string &samplerErrorMessage,
2515 std::vector<LinkedUniform> &samplerUniforms,
2516 InfoLog &infoLog)
2517{
2518 VectorAndSamplerCount vasCount;
2519 for (const sh::Uniform &uniform : shader.getUniforms())
2520 {
2521 if (uniform.staticUse)
2522 {
2523 vasCount += flattenUniform(uniform, uniform.name, &samplerUniforms);
2524 }
2525 }
2526
2527 if (vasCount.vectorCount > maxUniformComponents)
2528 {
2529 infoLog << componentsErrorMessage << maxUniformComponents << ").";
2530 return false;
2531 }
2532
2533 if (vasCount.samplerCount > maxTextureImageUnits)
2534 {
2535 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
2536 return false;
2537 }
2538
2539 return true;
2540}
2541
Jamie Madill62d31cb2015-09-11 13:25:51 -04002542bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2543{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002544 std::vector<LinkedUniform> samplerUniforms;
2545
Martin Radev4c4c8e72016-08-04 12:25:34 +03002546 if (mState.mAttachedComputeShader)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002547 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002548 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002549
2550 // TODO (mradev): check whether we need finer-grained component counting
2551 if (!flattenUniformsAndCheckCapsForShader(
2552 *computeShader, caps.maxComputeUniformComponents / 4,
2553 caps.maxComputeTextureImageUnits,
2554 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
2555 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
2556 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002557 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002558 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002559 }
2560 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002561 else
Jamie Madill62d31cb2015-09-11 13:25:51 -04002562 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002563 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002564
Martin Radev4c4c8e72016-08-04 12:25:34 +03002565 if (!flattenUniformsAndCheckCapsForShader(
2566 *vertexShader, caps.maxVertexUniformVectors, caps.maxVertexTextureImageUnits,
2567 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
2568 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
2569 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002570 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002571 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002572 }
Jamie Madilla2c74982016-12-12 11:20:42 -05002573 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002574
Martin Radev4c4c8e72016-08-04 12:25:34 +03002575 if (!flattenUniformsAndCheckCapsForShader(
2576 *fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
2577 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
2578 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms,
2579 infoLog))
2580 {
2581 return false;
2582 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002583 }
2584
Jamie Madill48ef11b2016-04-27 15:21:52 -04002585 mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002586 mSamplerUniformRange.end =
2587 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2588
Jamie Madill48ef11b2016-04-27 15:21:52 -04002589 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002590
Jamie Madill62d31cb2015-09-11 13:25:51 -04002591 return true;
2592}
2593
2594Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002595 const std::string &fullName,
2596 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002597{
2598 VectorAndSamplerCount vectorAndSamplerCount;
2599
2600 if (uniform.isStruct())
2601 {
2602 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2603 {
2604 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2605
2606 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2607 {
2608 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2609 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2610
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002611 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002612 }
2613 }
2614
2615 return vectorAndSamplerCount;
2616 }
2617
2618 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002619 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002620 if (!UniformInList(mState.getUniforms(), fullName) &&
2621 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002622 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002623 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
2624 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002625 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002626
2627 // Store sampler uniforms separately, so we'll append them to the end of the list.
2628 if (isSampler)
2629 {
2630 samplerUniforms->push_back(linkedUniform);
2631 }
2632 else
2633 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002634 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002635 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002636 }
2637
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002638 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002639
2640 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2641 // Likewise, don't count "real" uniforms towards sampler count.
2642 vectorAndSamplerCount.vectorCount =
2643 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002644 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002645
2646 return vectorAndSamplerCount;
2647}
2648
2649void Program::gatherInterfaceBlockInfo()
2650{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002651 ASSERT(mState.mUniformBlocks.empty());
2652
2653 if (mState.mAttachedComputeShader)
2654 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002655 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002656
2657 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2658 {
2659
2660 // Only 'packed' blocks are allowed to be considered inactive.
2661 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2662 continue;
2663
Jamie Madilla2c74982016-12-12 11:20:42 -05002664 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002665 {
2666 if (block.name == computeBlock.name)
2667 {
2668 block.computeStaticUse = computeBlock.staticUse;
2669 }
2670 }
2671
2672 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2673 }
2674 return;
2675 }
2676
Jamie Madill62d31cb2015-09-11 13:25:51 -04002677 std::set<std::string> visitedList;
2678
Jamie Madilla2c74982016-12-12 11:20:42 -05002679 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002680
Jamie Madill62d31cb2015-09-11 13:25:51 -04002681 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2682 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002683 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002684 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2685 continue;
2686
2687 if (visitedList.count(vertexBlock.name) > 0)
2688 continue;
2689
2690 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2691 visitedList.insert(vertexBlock.name);
2692 }
2693
Jamie Madilla2c74982016-12-12 11:20:42 -05002694 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002695
2696 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2697 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002698 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002699 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2700 continue;
2701
2702 if (visitedList.count(fragmentBlock.name) > 0)
2703 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002704 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002705 {
2706 if (block.name == fragmentBlock.name)
2707 {
2708 block.fragmentStaticUse = fragmentBlock.staticUse;
2709 }
2710 }
2711
2712 continue;
2713 }
2714
2715 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2716 visitedList.insert(fragmentBlock.name);
2717 }
2718}
2719
Jamie Madill4a3c2342015-10-08 12:58:45 -04002720template <typename VarT>
2721void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2722 const std::string &prefix,
2723 int blockIndex)
2724{
2725 for (const VarT &field : fields)
2726 {
2727 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2728
2729 if (field.isStruct())
2730 {
2731 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2732 {
2733 const std::string uniformElementName =
2734 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2735 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2736 }
2737 }
2738 else
2739 {
2740 // If getBlockMemberInfo returns false, the uniform is optimized out.
2741 sh::BlockMemberInfo memberInfo;
2742 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2743 {
2744 continue;
2745 }
2746
2747 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2748 blockIndex, memberInfo);
2749
2750 // Since block uniforms have no location, we don't need to store them in the uniform
2751 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002752 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002753 }
2754 }
2755}
2756
Jamie Madill62d31cb2015-09-11 13:25:51 -04002757void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2758{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002759 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002760 size_t blockSize = 0;
2761
2762 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002763 std::stringstream blockNameStr;
2764 blockNameStr << interfaceBlock.name;
2765 if (interfaceBlock.arraySize > 0)
2766 {
2767 blockNameStr << "[0]";
2768 }
2769 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002770 {
2771 return;
2772 }
2773
2774 // Track the first and last uniform index to determine the range of active uniforms in the
2775 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002776 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002777 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002778 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002779
2780 std::vector<unsigned int> blockUniformIndexes;
2781 for (size_t blockUniformIndex = firstBlockUniformIndex;
2782 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2783 {
2784 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2785 }
2786
2787 if (interfaceBlock.arraySize > 0)
2788 {
2789 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2790 {
2791 UniformBlock block(interfaceBlock.name, true, arrayElement);
2792 block.memberUniformIndexes = blockUniformIndexes;
2793
Martin Radev4c4c8e72016-08-04 12:25:34 +03002794 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002795 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002796 case GL_VERTEX_SHADER:
2797 {
2798 block.vertexStaticUse = interfaceBlock.staticUse;
2799 break;
2800 }
2801 case GL_FRAGMENT_SHADER:
2802 {
2803 block.fragmentStaticUse = interfaceBlock.staticUse;
2804 break;
2805 }
2806 case GL_COMPUTE_SHADER:
2807 {
2808 block.computeStaticUse = interfaceBlock.staticUse;
2809 break;
2810 }
2811 default:
2812 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002813 }
2814
Qin Jiajia0350a642016-11-01 17:01:51 +08002815 // Since all block elements in an array share the same active uniforms, they will all be
2816 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2817 // here we will add every block element in the array.
2818 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002819 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002820 }
2821 }
2822 else
2823 {
2824 UniformBlock block(interfaceBlock.name, false, 0);
2825 block.memberUniformIndexes = blockUniformIndexes;
2826
Martin Radev4c4c8e72016-08-04 12:25:34 +03002827 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002828 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002829 case GL_VERTEX_SHADER:
2830 {
2831 block.vertexStaticUse = interfaceBlock.staticUse;
2832 break;
2833 }
2834 case GL_FRAGMENT_SHADER:
2835 {
2836 block.fragmentStaticUse = interfaceBlock.staticUse;
2837 break;
2838 }
2839 case GL_COMPUTE_SHADER:
2840 {
2841 block.computeStaticUse = interfaceBlock.staticUse;
2842 break;
2843 }
2844 default:
2845 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002846 }
2847
Jamie Madill4a3c2342015-10-08 12:58:45 -04002848 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002849 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002850 }
2851}
2852
2853template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002854GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002855{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002856 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2857 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002858 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2859
Corentin Wallez15ac5342016-11-03 17:06:39 -04002860 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2861 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2862 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002863 GLsizei maxElementCount =
2864 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2865
2866 GLsizei count = countIn;
2867 GLsizei clampedCount = count * vectorSize;
2868 if (clampedCount > maxElementCount)
2869 {
2870 clampedCount = maxElementCount;
2871 count = maxElementCount / vectorSize;
2872 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002873
Jamie Madill62d31cb2015-09-11 13:25:51 -04002874 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2875 {
2876 // Do a cast conversion for boolean types. From the spec:
2877 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2878 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002879 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002880 {
2881 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2882 }
2883 }
2884 else
2885 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002886 // Invalide the validation cache if we modify the sampler data.
Corentin Wallez15ac5342016-11-03 17:06:39 -04002887 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * clampedCount) != 0)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002888 {
2889 mCachedValidateSamplersResult.reset();
2890 }
2891
Corentin Wallez15ac5342016-11-03 17:06:39 -04002892 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002893 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002894
2895 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002896}
2897
2898template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002899GLsizei Program::setMatrixUniformInternal(GLint location,
2900 GLsizei count,
2901 GLboolean transpose,
2902 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002903{
2904 if (!transpose)
2905 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002906 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002907 }
2908
2909 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002910 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2911 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002912 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04002913
2914 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2915 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2916 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
2917 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
2918
2919 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002920 {
2921 size_t elementOffset = element * rows * cols;
2922
2923 for (size_t row = 0; row < rows; ++row)
2924 {
2925 for (size_t col = 0; col < cols; ++col)
2926 {
2927 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2928 }
2929 }
2930 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002931
2932 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002933}
2934
2935template <typename DestT>
2936void Program::getUniformInternal(GLint location, DestT *dataOut) const
2937{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002938 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2939 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002940
2941 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2942
2943 GLenum componentType = VariableComponentType(uniform.type);
2944 if (componentType == GLTypeToGLenum<DestT>::value)
2945 {
2946 memcpy(dataOut, srcPointer, uniform.getElementSize());
2947 return;
2948 }
2949
Corentin Wallez6596c462016-03-17 17:26:58 -04002950 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002951
2952 switch (componentType)
2953 {
2954 case GL_INT:
2955 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2956 break;
2957 case GL_UNSIGNED_INT:
2958 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2959 break;
2960 case GL_BOOL:
2961 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2962 break;
2963 case GL_FLOAT:
2964 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2965 break;
2966 default:
2967 UNREACHABLE();
2968 }
2969}
Jamie Madilla2c74982016-12-12 11:20:42 -05002970} // namespace gl