blob: ab1203f18942318dd6aa5c0d8a947333fdcde0ae [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 Madill192745a2016-12-22 15:58:21 -050025#include "libANGLE/VaryingPacking.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040026#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040027#include "libANGLE/Uniform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050028
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000029namespace gl
30{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000031
Geoff Lang7dd2e102014-11-10 15:19:26 -050032namespace
33{
34
Jamie Madill62d31cb2015-09-11 13:25:51 -040035void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
36{
37 stream->writeInt(var.type);
38 stream->writeInt(var.precision);
39 stream->writeString(var.name);
40 stream->writeString(var.mappedName);
41 stream->writeInt(var.arraySize);
42 stream->writeInt(var.staticUse);
43 stream->writeString(var.structName);
44 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050045}
46
Jamie Madill62d31cb2015-09-11 13:25:51 -040047void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
48{
49 var->type = stream->readInt<GLenum>();
50 var->precision = stream->readInt<GLenum>();
51 var->name = stream->readString();
52 var->mappedName = stream->readString();
53 var->arraySize = stream->readInt<unsigned int>();
54 var->staticUse = stream->readBool();
55 var->structName = stream->readString();
56}
57
Jamie Madill62d31cb2015-09-11 13:25:51 -040058// This simplified cast function doesn't need to worry about advanced concepts like
59// depth range values, or casting to bool.
60template <typename DestT, typename SrcT>
61DestT UniformStateQueryCast(SrcT value);
62
63// From-Float-To-Integer Casts
64template <>
65GLint UniformStateQueryCast(GLfloat value)
66{
67 return clampCast<GLint>(roundf(value));
68}
69
70template <>
71GLuint UniformStateQueryCast(GLfloat value)
72{
73 return clampCast<GLuint>(roundf(value));
74}
75
76// From-Integer-to-Integer Casts
77template <>
78GLint UniformStateQueryCast(GLuint value)
79{
80 return clampCast<GLint>(value);
81}
82
83template <>
84GLuint UniformStateQueryCast(GLint value)
85{
86 return clampCast<GLuint>(value);
87}
88
89// From-Boolean-to-Anything Casts
90template <>
91GLfloat UniformStateQueryCast(GLboolean value)
92{
93 return (value == GL_TRUE ? 1.0f : 0.0f);
94}
95
96template <>
97GLint UniformStateQueryCast(GLboolean value)
98{
99 return (value == GL_TRUE ? 1 : 0);
100}
101
102template <>
103GLuint UniformStateQueryCast(GLboolean value)
104{
105 return (value == GL_TRUE ? 1u : 0u);
106}
107
108// Default to static_cast
109template <typename DestT, typename SrcT>
110DestT UniformStateQueryCast(SrcT value)
111{
112 return static_cast<DestT>(value);
113}
114
115template <typename SrcT, typename DestT>
116void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
117{
118 for (int comp = 0; comp < components; ++comp)
119 {
120 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
121 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
122 size_t offset = comp * 4;
123 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
124 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
125 }
126}
127
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400128bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
129{
130 for (const LinkedUniform &uniform : list)
131 {
132 if (uniform.name == name)
133 return true;
134 }
135
136 return false;
137}
138
Jamie Madill192745a2016-12-22 15:58:21 -0500139// true if varying x has a higher priority in packing than y
140bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
141{
142 return gl::CompareShaderVar(*x.varying, *y.varying);
143}
144
Jamie Madill62d31cb2015-09-11 13:25:51 -0400145} // anonymous namespace
146
Jamie Madill4a3c2342015-10-08 12:58:45 -0400147const char *const g_fakepath = "C:\\fakepath";
148
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400149InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000150{
151}
152
153InfoLog::~InfoLog()
154{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000155}
156
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400157size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000158{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400159 const std::string &logString = mStream.str();
160 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000161}
162
Geoff Lange1a27752015-10-05 13:16:04 -0400163void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000164{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400165 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000166
167 if (bufSize > 0)
168 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400169 const std::string str(mStream.str());
170
171 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000172 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400173 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
174 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000175 }
176
177 infoLog[index] = '\0';
178 }
179
180 if (length)
181 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000183 }
184}
185
186// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300187// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000188// messages, so lets remove all occurrences of this fake file path from the log.
189void InfoLog::appendSanitized(const char *message)
190{
191 std::string msg(message);
192
193 size_t found;
194 do
195 {
196 found = msg.find(g_fakepath);
197 if (found != std::string::npos)
198 {
199 msg.erase(found, strlen(g_fakepath));
200 }
201 }
202 while (found != std::string::npos);
203
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400204 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000205}
206
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000207void InfoLog::reset()
208{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000209}
210
Geoff Langd8605522016-04-13 10:19:12 -0400211VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000212{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500213}
214
Geoff Langd8605522016-04-13 10:19:12 -0400215VariableLocation::VariableLocation(const std::string &name,
216 unsigned int element,
217 unsigned int index)
218 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500219{
220}
221
Geoff Langd8605522016-04-13 10:19:12 -0400222void Program::Bindings::bindLocation(GLuint index, const std::string &name)
223{
224 mBindings[name] = index;
225}
226
227int Program::Bindings::getBinding(const std::string &name) const
228{
229 auto iter = mBindings.find(name);
230 return (iter != mBindings.end()) ? iter->second : -1;
231}
232
233Program::Bindings::const_iterator Program::Bindings::begin() const
234{
235 return mBindings.begin();
236}
237
238Program::Bindings::const_iterator Program::Bindings::end() const
239{
240 return mBindings.end();
241}
242
Jamie Madill48ef11b2016-04-27 15:21:52 -0400243ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500244 : mLabel(),
245 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400246 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300247 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500248 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madille7d84322017-01-10 18:21:59 -0500249 mSamplerUniformRange(0, 0),
Geoff Langc5629752015-12-07 16:29:04 -0500250 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400251{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300252 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400253}
254
Jamie Madill48ef11b2016-04-27 15:21:52 -0400255ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400256{
257 if (mAttachedVertexShader != nullptr)
258 {
259 mAttachedVertexShader->release();
260 }
261
262 if (mAttachedFragmentShader != nullptr)
263 {
264 mAttachedFragmentShader->release();
265 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300266
267 if (mAttachedComputeShader != nullptr)
268 {
269 mAttachedComputeShader->release();
270 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400271}
272
Jamie Madill48ef11b2016-04-27 15:21:52 -0400273const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500274{
275 return mLabel;
276}
277
Jamie Madill48ef11b2016-04-27 15:21:52 -0400278const LinkedUniform *ProgramState::getUniformByName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400279{
280 for (const LinkedUniform &linkedUniform : mUniforms)
281 {
282 if (linkedUniform.name == name)
283 {
284 return &linkedUniform;
285 }
286 }
287
288 return nullptr;
289}
290
Jamie Madill48ef11b2016-04-27 15:21:52 -0400291GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400292{
293 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500294 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400295
296 for (size_t location = 0; location < mUniformLocations.size(); ++location)
297 {
298 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400299 if (!uniformLocation.used)
300 {
301 continue;
302 }
303
304 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400305
306 if (uniform.name == baseName)
307 {
Geoff Langd8605522016-04-13 10:19:12 -0400308 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400309 {
Geoff Langd8605522016-04-13 10:19:12 -0400310 if (uniformLocation.element == subscript ||
311 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
312 {
313 return static_cast<GLint>(location);
314 }
315 }
316 else
317 {
318 if (subscript == GL_INVALID_INDEX)
319 {
320 return static_cast<GLint>(location);
321 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400322 }
323 }
324 }
325
326 return -1;
327}
328
Jamie Madille7d84322017-01-10 18:21:59 -0500329GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400330{
331 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500332 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400333
334 // The app is not allowed to specify array indices other than 0 for arrays of basic types
335 if (subscript != 0 && subscript != GL_INVALID_INDEX)
336 {
337 return GL_INVALID_INDEX;
338 }
339
340 for (size_t index = 0; index < mUniforms.size(); index++)
341 {
342 const LinkedUniform &uniform = mUniforms[index];
343 if (uniform.name == baseName)
344 {
345 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
346 {
347 return static_cast<GLuint>(index);
348 }
349 }
350 }
351
352 return GL_INVALID_INDEX;
353}
354
Jamie Madille7d84322017-01-10 18:21:59 -0500355GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
356{
357 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
358 return mUniformLocations[location].index;
359}
360
361Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
362{
363 GLuint index = getUniformIndexFromLocation(location);
364 if (!isSamplerUniformIndex(index))
365 {
366 return Optional<GLuint>::Invalid();
367 }
368
369 return getSamplerIndexFromUniformIndex(index);
370}
371
372bool ProgramState::isSamplerUniformIndex(GLuint index) const
373{
374 return index >= mSamplerUniformRange.start && index < mSamplerUniformRange.end;
375}
376
377GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
378{
379 ASSERT(isSamplerUniformIndex(uniformIndex));
380 return uniformIndex - mSamplerUniformRange.start;
381}
382
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500383Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400384 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400385 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500386 mLinked(false),
387 mDeleteStatus(false),
388 mRefCount(0),
389 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500390 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500391{
392 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000393
394 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500395 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396}
397
398Program::~Program()
399{
400 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000401
Geoff Lang7dd2e102014-11-10 15:19:26 -0500402 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403}
404
Geoff Lang70d0f492015-12-10 17:45:46 -0500405void Program::setLabel(const std::string &label)
406{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400407 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500408}
409
410const std::string &Program::getLabel() const
411{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400412 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500413}
414
Jamie Madillef300b12016-10-07 15:12:09 -0400415void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300417 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300419 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Jamie Madillef300b12016-10-07 15:12:09 -0400421 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300422 mState.mAttachedVertexShader = shader;
423 mState.mAttachedVertexShader->addRef();
424 break;
425 }
426 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427 {
Jamie Madillef300b12016-10-07 15:12:09 -0400428 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300429 mState.mAttachedFragmentShader = shader;
430 mState.mAttachedFragmentShader->addRef();
431 break;
432 }
433 case GL_COMPUTE_SHADER:
434 {
Jamie Madillef300b12016-10-07 15:12:09 -0400435 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300436 mState.mAttachedComputeShader = shader;
437 mState.mAttachedComputeShader->addRef();
438 break;
439 }
440 default:
441 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443}
444
445bool Program::detachShader(Shader *shader)
446{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300447 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300449 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300451 if (mState.mAttachedVertexShader != shader)
452 {
453 return false;
454 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455
Martin Radev4c4c8e72016-08-04 12:25:34 +0300456 shader->release();
457 mState.mAttachedVertexShader = nullptr;
458 break;
459 }
460 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000461 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300462 if (mState.mAttachedFragmentShader != shader)
463 {
464 return false;
465 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466
Martin Radev4c4c8e72016-08-04 12:25:34 +0300467 shader->release();
468 mState.mAttachedFragmentShader = nullptr;
469 break;
470 }
471 case GL_COMPUTE_SHADER:
472 {
473 if (mState.mAttachedComputeShader != shader)
474 {
475 return false;
476 }
477
478 shader->release();
479 mState.mAttachedComputeShader = nullptr;
480 break;
481 }
482 default:
483 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000486 return true;
487}
488
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000489int Program::getAttachedShadersCount() const
490{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300491 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
492 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000493}
494
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495void Program::bindAttributeLocation(GLuint index, const char *name)
496{
Geoff Langd8605522016-04-13 10:19:12 -0400497 mAttributeBindings.bindLocation(index, name);
498}
499
500void Program::bindUniformLocation(GLuint index, const char *name)
501{
502 // Bind the base uniform name only since array indices other than 0 cannot be bound
503 mUniformBindings.bindLocation(index, ParseUniformName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504}
505
Sami Väisänen46eaa942016-06-29 10:26:37 +0300506void Program::bindFragmentInputLocation(GLint index, const char *name)
507{
508 mFragmentInputBindings.bindLocation(index, name);
509}
510
511BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
512{
513 BindingInfo ret;
514 ret.type = GL_NONE;
515 ret.valid = false;
516
517 const Shader *fragmentShader = mState.getAttachedFragmentShader();
518 ASSERT(fragmentShader);
519
520 // Find the actual fragment shader varying we're interested in
521 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
522
523 for (const auto &binding : mFragmentInputBindings)
524 {
525 if (binding.second != static_cast<GLuint>(index))
526 continue;
527
528 ret.valid = true;
529
530 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400531 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300532
533 for (const auto &in : inputs)
534 {
535 if (in.name == originalName)
536 {
537 if (in.isArray())
538 {
539 // The client wants to bind either "name" or "name[0]".
540 // GL ES 3.1 spec refers to active array names with language such as:
541 // "if the string identifies the base name of an active array, where the
542 // string would exactly match the name of the variable if the suffix "[0]"
543 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400544 if (arrayIndex == GL_INVALID_INDEX)
545 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300546
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400547 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300548 }
549 else
550 {
551 ret.name = in.mappedName;
552 }
553 ret.type = in.type;
554 return ret;
555 }
556 }
557 }
558
559 return ret;
560}
561
562void Program::pathFragmentInputGen(GLint index,
563 GLenum genMode,
564 GLint components,
565 const GLfloat *coeffs)
566{
567 // If the location is -1 then the command is silently ignored
568 if (index == -1)
569 return;
570
571 const auto &binding = getFragmentInputBindingInfo(index);
572
573 // If the input doesn't exist then then the command is silently ignored
574 // This could happen through optimization for example, the shader translator
575 // decides that a variable is not actually being used and optimizes it away.
576 if (binding.name.empty())
577 return;
578
579 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
580}
581
Martin Radev4c4c8e72016-08-04 12:25:34 +0300582// The attached shaders are checked for linking errors by matching up their variables.
583// Uniform, input and output variables get collected.
584// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500585Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000586{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500587 const auto &data = context->getContextState();
588
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000589 unlink(false);
590
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000591 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000592 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000593
Martin Radev4c4c8e72016-08-04 12:25:34 +0300594 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500595
Jamie Madill192745a2016-12-22 15:58:21 -0500596 auto vertexShader = mState.mAttachedVertexShader;
597 auto fragmentShader = mState.mAttachedFragmentShader;
598 auto computeShader = mState.mAttachedComputeShader;
599
600 bool isComputeShaderAttached = (computeShader != nullptr);
601 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300602 // Check whether we both have a compute and non-compute shaders attached.
603 // If there are of both types attached, then linking should fail.
604 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
605 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500606 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300607 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
608 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400609 }
610
Jamie Madill192745a2016-12-22 15:58:21 -0500611 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500612 {
Jamie Madill192745a2016-12-22 15:58:21 -0500613 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300614 {
615 mInfoLog << "Attached compute shader is not compiled.";
616 return NoError();
617 }
Jamie Madill192745a2016-12-22 15:58:21 -0500618 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300619
Jamie Madill192745a2016-12-22 15:58:21 -0500620 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300621
622 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
623 // If the work group size is not specified, a link time error should occur.
624 if (!mState.mComputeShaderLocalSize.isDeclared())
625 {
626 mInfoLog << "Work group size is not specified.";
627 return NoError();
628 }
629
630 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
631 {
632 return NoError();
633 }
634
635 if (!linkUniformBlocks(mInfoLog, caps))
636 {
637 return NoError();
638 }
639
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500640 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
641 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), noPacking, mInfoLog),
642 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500643 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300644 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500645 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300646 }
647 }
648 else
649 {
Jamie Madill192745a2016-12-22 15:58:21 -0500650 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300651 {
652 return NoError();
653 }
Jamie Madill192745a2016-12-22 15:58:21 -0500654 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300655
Jamie Madill192745a2016-12-22 15:58:21 -0500656 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300657 {
658 return NoError();
659 }
Jamie Madill192745a2016-12-22 15:58:21 -0500660 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300661
Jamie Madill192745a2016-12-22 15:58:21 -0500662 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300663 {
664 mInfoLog << "Fragment shader version does not match vertex shader version.";
665 return NoError();
666 }
667
Jamie Madilleb979bf2016-11-15 12:28:46 -0500668 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300669 {
670 return NoError();
671 }
672
Jamie Madill192745a2016-12-22 15:58:21 -0500673 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300674 {
675 return NoError();
676 }
677
678 if (!linkUniforms(mInfoLog, caps, mUniformBindings))
679 {
680 return NoError();
681 }
682
683 if (!linkUniformBlocks(mInfoLog, caps))
684 {
685 return NoError();
686 }
687
688 const auto &mergedVaryings = getMergedVaryings();
689
690 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
691 {
692 return NoError();
693 }
694
695 linkOutputVariables();
696
Jamie Madill192745a2016-12-22 15:58:21 -0500697 // Validate we can pack the varyings.
698 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
699
700 // Map the varyings to the register file
701 // In WebGL, we use a slightly different handling for packing variables.
702 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
703 : PackMode::ANGLE_RELAXED;
704 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
705 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
706 mState.getTransformFeedbackVaryingNames()))
707 {
708 return NoError();
709 }
710
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500711 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), varyingPacking, mInfoLog),
712 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500713 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300714 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500715 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300716 }
717
718 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500719 }
720
Jamie Madill4a3c2342015-10-08 12:58:45 -0400721 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400722
Martin Radev4c4c8e72016-08-04 12:25:34 +0300723 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000724}
725
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000726// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727void Program::unlink(bool destroy)
728{
729 if (destroy) // Object being destructed
730 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400731 if (mState.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400733 mState.mAttachedFragmentShader->release();
734 mState.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000735 }
736
Jamie Madill48ef11b2016-04-27 15:21:52 -0400737 if (mState.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738 {
Jamie Madill48ef11b2016-04-27 15:21:52 -0400739 mState.mAttachedVertexShader->release();
740 mState.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300742
743 if (mState.mAttachedComputeShader)
744 {
745 mState.mAttachedComputeShader->release();
746 mState.mAttachedComputeShader = nullptr;
747 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000748 }
749
Jamie Madill48ef11b2016-04-27 15:21:52 -0400750 mState.mAttributes.clear();
751 mState.mActiveAttribLocationsMask.reset();
752 mState.mTransformFeedbackVaryingVars.clear();
753 mState.mUniforms.clear();
754 mState.mUniformLocations.clear();
755 mState.mUniformBlocks.clear();
756 mState.mOutputVariables.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300757 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500758 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500759
Geoff Lang7dd2e102014-11-10 15:19:26 -0500760 mValidated = false;
761
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000762 mLinked = false;
763}
764
Geoff Lange1a27752015-10-05 13:16:04 -0400765bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000766{
767 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768}
769
Jamie Madilla2c74982016-12-12 11:20:42 -0500770Error Program::loadBinary(const Context *context,
771 GLenum binaryFormat,
772 const void *binary,
773 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000774{
775 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000776
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800778 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500779#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400780 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
781 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000782 {
Jamie Madillf6113162015-05-07 11:49:21 -0400783 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800784 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500785 }
786
Geoff Langc46cc2f2015-10-01 17:16:20 -0400787 BinaryInputStream stream(binary, length);
788
Jamie Madilla2c74982016-12-12 11:20:42 -0500789 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
790 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
791 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
792 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500793 {
Jamie Madillf6113162015-05-07 11:49:21 -0400794 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800795 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500796 }
797
Jamie Madilla2c74982016-12-12 11:20:42 -0500798 int majorVersion = stream.readInt<int>();
799 int minorVersion = stream.readInt<int>();
800 if (majorVersion != context->getClientMajorVersion() ||
801 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500802 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500803 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800804 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500805 }
806
Martin Radev4c4c8e72016-08-04 12:25:34 +0300807 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
808 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
809 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
810
Jamie Madill63805b42015-08-25 13:17:39 -0400811 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
812 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400813 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500814
Jamie Madill3da79b72015-04-27 11:09:17 -0400815 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400816 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400817 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
818 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400819 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400820 LoadShaderVar(&stream, &attrib);
821 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400822 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400823 }
824
Jamie Madill62d31cb2015-09-11 13:25:51 -0400825 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400826 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400827 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
828 {
829 LinkedUniform uniform;
830 LoadShaderVar(&stream, &uniform);
831
832 uniform.blockIndex = stream.readInt<int>();
833 uniform.blockInfo.offset = stream.readInt<int>();
834 uniform.blockInfo.arrayStride = stream.readInt<int>();
835 uniform.blockInfo.matrixStride = stream.readInt<int>();
836 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
837
Jamie Madill48ef11b2016-04-27 15:21:52 -0400838 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400839 }
840
841 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400842 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400843 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
844 uniformIndexIndex++)
845 {
846 VariableLocation variable;
847 stream.readString(&variable.name);
848 stream.readInt(&variable.element);
849 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400850 stream.readBool(&variable.used);
851 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400852
Jamie Madill48ef11b2016-04-27 15:21:52 -0400853 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400854 }
855
856 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400857 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400858 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
859 ++uniformBlockIndex)
860 {
861 UniformBlock uniformBlock;
862 stream.readString(&uniformBlock.name);
863 stream.readBool(&uniformBlock.isArray);
864 stream.readInt(&uniformBlock.arrayElement);
865 stream.readInt(&uniformBlock.dataSize);
866 stream.readBool(&uniformBlock.vertexStaticUse);
867 stream.readBool(&uniformBlock.fragmentStaticUse);
868
869 unsigned int numMembers = stream.readInt<unsigned int>();
870 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
871 {
872 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
873 }
874
Jamie Madill48ef11b2016-04-27 15:21:52 -0400875 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400876 }
877
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500878 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
879 ++bindingIndex)
880 {
881 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
882 mState.mActiveUniformBlockBindings.set(bindingIndex,
883 mState.mUniformBlockBindings[bindingIndex] != 0);
884 }
885
Brandon Jones1048ea72015-10-06 15:34:52 -0700886 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400887 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700888 for (unsigned int transformFeedbackVaryingIndex = 0;
889 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
890 ++transformFeedbackVaryingIndex)
891 {
892 sh::Varying varying;
893 stream.readInt(&varying.arraySize);
894 stream.readInt(&varying.type);
895 stream.readString(&varying.name);
896
Jamie Madill48ef11b2016-04-27 15:21:52 -0400897 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700898 }
899
Jamie Madill48ef11b2016-04-27 15:21:52 -0400900 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400901
Jamie Madill80a6fc02015-08-21 16:53:16 -0400902 unsigned int outputVarCount = stream.readInt<unsigned int>();
903 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
904 {
905 int locationIndex = stream.readInt<int>();
906 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400907 stream.readInt(&locationData.element);
908 stream.readInt(&locationData.index);
909 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400910 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400911 }
912
Jamie Madille7d84322017-01-10 18:21:59 -0500913 stream.readInt(&mState.mSamplerUniformRange.start);
914 stream.readInt(&mState.mSamplerUniformRange.end);
915
916 unsigned int samplerCount = stream.readInt<unsigned int>();
917 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
918 {
919 GLenum textureType = stream.readInt<GLenum>();
920 size_t bindingCount = stream.readInt<size_t>();
921 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
922 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400923
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500924 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000925
Jamie Madillb0a838b2016-11-13 20:02:12 -0500926 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500927#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500928}
929
Jamie Madilla2c74982016-12-12 11:20:42 -0500930Error Program::saveBinary(const Context *context,
931 GLenum *binaryFormat,
932 void *binary,
933 GLsizei bufSize,
934 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500935{
936 if (binaryFormat)
937 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400938 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500939 }
940
941 BinaryOutputStream stream;
942
Geoff Lang7dd2e102014-11-10 15:19:26 -0500943 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
944
Jamie Madilla2c74982016-12-12 11:20:42 -0500945 // nullptr context is supported when computing binary length.
946 if (context)
947 {
948 stream.writeInt(context->getClientVersion().major);
949 stream.writeInt(context->getClientVersion().minor);
950 }
951 else
952 {
953 stream.writeInt(2);
954 stream.writeInt(0);
955 }
956
Martin Radev4c4c8e72016-08-04 12:25:34 +0300957 stream.writeInt(mState.mComputeShaderLocalSize[0]);
958 stream.writeInt(mState.mComputeShaderLocalSize[1]);
959 stream.writeInt(mState.mComputeShaderLocalSize[2]);
960
Jamie Madill48ef11b2016-04-27 15:21:52 -0400961 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500962
Jamie Madill48ef11b2016-04-27 15:21:52 -0400963 stream.writeInt(mState.mAttributes.size());
964 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400965 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400966 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400967 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400968 }
969
Jamie Madill48ef11b2016-04-27 15:21:52 -0400970 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500971 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400972 {
973 WriteShaderVar(&stream, uniform);
974
975 // FIXME: referenced
976
977 stream.writeInt(uniform.blockIndex);
978 stream.writeInt(uniform.blockInfo.offset);
979 stream.writeInt(uniform.blockInfo.arrayStride);
980 stream.writeInt(uniform.blockInfo.matrixStride);
981 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
982 }
983
Jamie Madill48ef11b2016-04-27 15:21:52 -0400984 stream.writeInt(mState.mUniformLocations.size());
985 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400986 {
987 stream.writeString(variable.name);
988 stream.writeInt(variable.element);
989 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400990 stream.writeInt(variable.used);
991 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400992 }
993
Jamie Madill48ef11b2016-04-27 15:21:52 -0400994 stream.writeInt(mState.mUniformBlocks.size());
995 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400996 {
997 stream.writeString(uniformBlock.name);
998 stream.writeInt(uniformBlock.isArray);
999 stream.writeInt(uniformBlock.arrayElement);
1000 stream.writeInt(uniformBlock.dataSize);
1001
1002 stream.writeInt(uniformBlock.vertexStaticUse);
1003 stream.writeInt(uniformBlock.fragmentStaticUse);
1004
1005 stream.writeInt(uniformBlock.memberUniformIndexes.size());
1006 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
1007 {
1008 stream.writeInt(memberUniformIndex);
1009 }
Jamie Madill3da79b72015-04-27 11:09:17 -04001010 }
1011
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001012 for (GLuint binding : mState.mUniformBlockBindings)
1013 {
1014 stream.writeInt(binding);
1015 }
1016
Jamie Madill48ef11b2016-04-27 15:21:52 -04001017 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
1018 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -07001019 {
1020 stream.writeInt(varying.arraySize);
1021 stream.writeInt(varying.type);
1022 stream.writeString(varying.name);
1023 }
1024
Jamie Madill48ef11b2016-04-27 15:21:52 -04001025 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001026
Jamie Madill48ef11b2016-04-27 15:21:52 -04001027 stream.writeInt(mState.mOutputVariables.size());
1028 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001029 {
1030 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001031 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001032 stream.writeInt(outputPair.second.index);
1033 stream.writeString(outputPair.second.name);
1034 }
1035
Jamie Madille7d84322017-01-10 18:21:59 -05001036 stream.writeInt(mState.mSamplerUniformRange.start);
1037 stream.writeInt(mState.mSamplerUniformRange.end);
1038
1039 stream.writeInt(mState.mSamplerBindings.size());
1040 for (const auto &samplerBinding : mState.mSamplerBindings)
1041 {
1042 stream.writeInt(samplerBinding.textureType);
1043 stream.writeInt(samplerBinding.boundTextureUnits.size());
1044 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001045
Jamie Madilla2c74982016-12-12 11:20:42 -05001046 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001047
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001048 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001049 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001050
1051 if (streamLength > bufSize)
1052 {
1053 if (length)
1054 {
1055 *length = 0;
1056 }
1057
1058 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1059 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1060 // sizes and then copy it.
1061 return Error(GL_INVALID_OPERATION);
1062 }
1063
1064 if (binary)
1065 {
1066 char *ptr = reinterpret_cast<char*>(binary);
1067
Jamie Madill48ef11b2016-04-27 15:21:52 -04001068 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001069 ptr += streamLength;
1070
1071 ASSERT(ptr - streamLength == binary);
1072 }
1073
1074 if (length)
1075 {
1076 *length = streamLength;
1077 }
1078
He Yunchaoacd18982017-01-04 10:46:42 +08001079 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001080}
1081
1082GLint Program::getBinaryLength() const
1083{
1084 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001085 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001086 if (error.isError())
1087 {
1088 return 0;
1089 }
1090
1091 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001092}
1093
Geoff Langc5629752015-12-07 16:29:04 -05001094void Program::setBinaryRetrievableHint(bool retrievable)
1095{
1096 // TODO(jmadill) : replace with dirty bits
1097 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001098 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001099}
1100
1101bool Program::getBinaryRetrievableHint() const
1102{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001103 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001104}
1105
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001106void Program::release()
1107{
1108 mRefCount--;
1109
1110 if (mRefCount == 0 && mDeleteStatus)
1111 {
1112 mResourceManager->deleteProgram(mHandle);
1113 }
1114}
1115
1116void Program::addRef()
1117{
1118 mRefCount++;
1119}
1120
1121unsigned int Program::getRefCount() const
1122{
1123 return mRefCount;
1124}
1125
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001126int Program::getInfoLogLength() const
1127{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001128 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001129}
1130
Geoff Lange1a27752015-10-05 13:16:04 -04001131void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001132{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001133 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001134}
1135
Geoff Lange1a27752015-10-05 13:16:04 -04001136void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001137{
1138 int total = 0;
1139
Martin Radev4c4c8e72016-08-04 12:25:34 +03001140 if (mState.mAttachedComputeShader)
1141 {
1142 if (total < maxCount)
1143 {
1144 shaders[total] = mState.mAttachedComputeShader->getHandle();
1145 total++;
1146 }
1147 }
1148
Jamie Madill48ef11b2016-04-27 15:21:52 -04001149 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001150 {
1151 if (total < maxCount)
1152 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001153 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001154 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001155 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001156 }
1157
Jamie Madill48ef11b2016-04-27 15:21:52 -04001158 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001159 {
1160 if (total < maxCount)
1161 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001162 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001163 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001164 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001165 }
1166
1167 if (count)
1168 {
1169 *count = total;
1170 }
1171}
1172
Geoff Lange1a27752015-10-05 13:16:04 -04001173GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001174{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001175 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001177 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001178 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001179 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001180 }
1181 }
1182
Austin Kinrossb8af7232015-03-16 22:33:25 -07001183 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001184}
1185
Jamie Madill63805b42015-08-25 13:17:39 -04001186bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001187{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001188 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1189 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001190}
1191
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001192void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1193{
Jamie Madillc349ec02015-08-21 16:53:12 -04001194 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001195 {
1196 if (bufsize > 0)
1197 {
1198 name[0] = '\0';
1199 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001200
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001201 if (length)
1202 {
1203 *length = 0;
1204 }
1205
1206 *type = GL_NONE;
1207 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001208 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001209 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001210
1211 size_t attributeIndex = 0;
1212
Jamie Madill48ef11b2016-04-27 15:21:52 -04001213 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001214 {
1215 // Skip over inactive attributes
1216 if (attribute.staticUse)
1217 {
1218 if (static_cast<size_t>(index) == attributeIndex)
1219 {
1220 break;
1221 }
1222 attributeIndex++;
1223 }
1224 }
1225
Jamie Madill48ef11b2016-04-27 15:21:52 -04001226 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
1227 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -04001228
1229 if (bufsize > 0)
1230 {
1231 const char *string = attrib.name.c_str();
1232
1233 strncpy(name, string, bufsize);
1234 name[bufsize - 1] = '\0';
1235
1236 if (length)
1237 {
1238 *length = static_cast<GLsizei>(strlen(name));
1239 }
1240 }
1241
1242 // Always a single 'type' instance
1243 *size = 1;
1244 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001245}
1246
Geoff Lange1a27752015-10-05 13:16:04 -04001247GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001248{
Jamie Madillc349ec02015-08-21 16:53:12 -04001249 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001250 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001251 return 0;
1252 }
1253
1254 GLint count = 0;
1255
Jamie Madill48ef11b2016-04-27 15:21:52 -04001256 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001257 {
1258 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001259 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001260
1261 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001262}
1263
Geoff Lange1a27752015-10-05 13:16:04 -04001264GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001265{
Jamie Madillc349ec02015-08-21 16:53:12 -04001266 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001267 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001268 return 0;
1269 }
1270
1271 size_t maxLength = 0;
1272
Jamie Madill48ef11b2016-04-27 15:21:52 -04001273 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001274 {
1275 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001276 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001277 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001278 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001279 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001280
Jamie Madillc349ec02015-08-21 16:53:12 -04001281 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001282}
1283
Geoff Lang7dd2e102014-11-10 15:19:26 -05001284GLint Program::getFragDataLocation(const std::string &name) const
1285{
1286 std::string baseName(name);
1287 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001288 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001289 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001290 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001291 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1292 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001293 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001294 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001295 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001296 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001297}
1298
Geoff Lange1a27752015-10-05 13:16:04 -04001299void Program::getActiveUniform(GLuint index,
1300 GLsizei bufsize,
1301 GLsizei *length,
1302 GLint *size,
1303 GLenum *type,
1304 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001305{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001306 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001307 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001308 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001309 ASSERT(index < mState.mUniforms.size());
1310 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001311
1312 if (bufsize > 0)
1313 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001314 std::string string = uniform.name;
1315 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001316 {
1317 string += "[0]";
1318 }
1319
1320 strncpy(name, string.c_str(), bufsize);
1321 name[bufsize - 1] = '\0';
1322
1323 if (length)
1324 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001325 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001326 }
1327 }
1328
Jamie Madill62d31cb2015-09-11 13:25:51 -04001329 *size = uniform.elementCount();
1330 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001331 }
1332 else
1333 {
1334 if (bufsize > 0)
1335 {
1336 name[0] = '\0';
1337 }
1338
1339 if (length)
1340 {
1341 *length = 0;
1342 }
1343
1344 *size = 0;
1345 *type = GL_NONE;
1346 }
1347}
1348
Geoff Lange1a27752015-10-05 13:16:04 -04001349GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001350{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001351 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001352 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001353 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001354 }
1355 else
1356 {
1357 return 0;
1358 }
1359}
1360
Geoff Lange1a27752015-10-05 13:16:04 -04001361GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001362{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001363 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001364
1365 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001366 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001367 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001368 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001369 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001370 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001371 size_t length = uniform.name.length() + 1u;
1372 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373 {
1374 length += 3; // Counting in "[0]".
1375 }
1376 maxLength = std::max(length, maxLength);
1377 }
1378 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001379 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380
Jamie Madill62d31cb2015-09-11 13:25:51 -04001381 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001382}
1383
1384GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1385{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001386 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001387 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001388 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001389 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1391 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1392 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1393 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1394 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1395 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1396 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1397 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1398 default:
1399 UNREACHABLE();
1400 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001401 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001402 return 0;
1403}
1404
1405bool Program::isValidUniformLocation(GLint location) const
1406{
Jamie Madille2e406c2016-06-02 13:04:10 -04001407 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001408 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1409 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001410}
1411
Jamie Madill62d31cb2015-09-11 13:25:51 -04001412const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001413{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001414 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001415 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416}
1417
Jamie Madillac4e9c32017-01-13 14:07:12 -05001418const VariableLocation &Program::getUniformLocation(GLint location) const
1419{
1420 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1421 return mState.mUniformLocations[location];
1422}
1423
1424const std::vector<VariableLocation> &Program::getUniformLocations() const
1425{
1426 return mState.mUniformLocations;
1427}
1428
1429const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1430{
1431 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1432 return mState.mUniforms[index];
1433}
1434
Jamie Madill62d31cb2015-09-11 13:25:51 -04001435GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001436{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001437 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438}
1439
Jamie Madill62d31cb2015-09-11 13:25:51 -04001440GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001441{
Jamie Madille7d84322017-01-10 18:21:59 -05001442 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443}
1444
1445void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1446{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001447 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1448 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001449}
1450
1451void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1452{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001453 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1454 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001455}
1456
1457void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1458{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001459 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1460 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461}
1462
1463void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1464{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001465 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1466 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467}
1468
1469void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1470{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001471 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1472 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473}
1474
1475void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1476{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001477 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1478 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479}
1480
1481void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1482{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001483 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1484 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1488{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001489 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1490 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
1493void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1494{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001495 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1496 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1500{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001501 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1502 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503}
1504
1505void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1506{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001507 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1508 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1512{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001513 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1514 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1518{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001519 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1520 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521}
1522
1523void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1524{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001525 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1526 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
1529void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1530{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001531 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1532 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001533}
1534
1535void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1536{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001537 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1538 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539}
1540
1541void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1542{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001543 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1544 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545}
1546
1547void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1548{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001549 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1550 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001551}
1552
1553void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1554{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001555 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1556 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557}
1558
1559void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1560{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001561 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1562 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001563}
1564
1565void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1566{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001567 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1568 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569}
1570
Geoff Lange1a27752015-10-05 13:16:04 -04001571void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001572{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001573 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001574}
1575
Geoff Lange1a27752015-10-05 13:16:04 -04001576void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001577{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001578 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001579}
1580
Geoff Lange1a27752015-10-05 13:16:04 -04001581void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001582{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001583 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001584}
1585
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001586void Program::flagForDeletion()
1587{
1588 mDeleteStatus = true;
1589}
1590
1591bool Program::isFlaggedForDeletion() const
1592{
1593 return mDeleteStatus;
1594}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001595
Brandon Jones43a53e22014-08-28 16:23:22 -07001596void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001597{
1598 mInfoLog.reset();
1599
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001601 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001602 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001603 }
1604 else
1605 {
Jamie Madillf6113162015-05-07 11:49:21 -04001606 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001607 }
1608}
1609
Geoff Lang7dd2e102014-11-10 15:19:26 -05001610bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1611{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001612 // Skip cache if we're using an infolog, so we get the full error.
1613 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1614 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1615 {
1616 return mCachedValidateSamplersResult.value();
1617 }
1618
1619 if (mTextureUnitTypesCache.empty())
1620 {
1621 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1622 }
1623 else
1624 {
1625 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1626 }
1627
1628 // if any two active samplers in a program are of different types, but refer to the same
1629 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1630 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001631 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001632 {
Jamie Madille7d84322017-01-10 18:21:59 -05001633 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001634
Jamie Madille7d84322017-01-10 18:21:59 -05001635 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001636 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001637 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1638 {
1639 if (infoLog)
1640 {
1641 (*infoLog) << "Sampler uniform (" << textureUnit
1642 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1643 << caps.maxCombinedTextureImageUnits << ")";
1644 }
1645
1646 mCachedValidateSamplersResult = false;
1647 return false;
1648 }
1649
1650 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1651 {
1652 if (textureType != mTextureUnitTypesCache[textureUnit])
1653 {
1654 if (infoLog)
1655 {
1656 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1657 "image unit ("
1658 << textureUnit << ").";
1659 }
1660
1661 mCachedValidateSamplersResult = false;
1662 return false;
1663 }
1664 }
1665 else
1666 {
1667 mTextureUnitTypesCache[textureUnit] = textureType;
1668 }
1669 }
1670 }
1671
1672 mCachedValidateSamplersResult = true;
1673 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674}
1675
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001676bool Program::isValidated() const
1677{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001678 return mValidated;
1679}
1680
Geoff Lange1a27752015-10-05 13:16:04 -04001681GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001682{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001683 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684}
1685
1686void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1687{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001688 ASSERT(
1689 uniformBlockIndex <
1690 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691
Jamie Madill48ef11b2016-04-27 15:21:52 -04001692 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693
1694 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001695 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001696 std::string string = uniformBlock.name;
1697
Jamie Madill62d31cb2015-09-11 13:25:51 -04001698 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001699 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001700 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001701 }
1702
1703 strncpy(uniformBlockName, string.c_str(), bufSize);
1704 uniformBlockName[bufSize - 1] = '\0';
1705
1706 if (length)
1707 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001708 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001709 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001710 }
1711}
1712
Geoff Lange1a27752015-10-05 13:16:04 -04001713GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001714{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715 int maxLength = 0;
1716
1717 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001718 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001719 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001720 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1721 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001722 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001723 if (!uniformBlock.name.empty())
1724 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001725 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001726
1727 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001728 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001729
1730 maxLength = std::max(length + arrayLength, maxLength);
1731 }
1732 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001733 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001734
1735 return maxLength;
1736}
1737
Geoff Lange1a27752015-10-05 13:16:04 -04001738GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001739{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001740 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -05001741 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001742
Jamie Madill48ef11b2016-04-27 15:21:52 -04001743 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001744 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1745 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001746 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001747 if (uniformBlock.name == baseName)
1748 {
1749 const bool arrayElementZero =
1750 (subscript == GL_INVALID_INDEX &&
1751 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1752 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1753 {
1754 return blockIndex;
1755 }
1756 }
1757 }
1758
1759 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001760}
1761
Jamie Madill62d31cb2015-09-11 13:25:51 -04001762const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001763{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001764 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1765 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001766}
1767
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001768void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1769{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001770 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001771 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001772 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001773}
1774
1775GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1776{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001777 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001778}
1779
1780void Program::resetUniformBlockBindings()
1781{
1782 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1783 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001784 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001785 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001787}
1788
Geoff Lang48dcae72014-02-05 16:28:24 -05001789void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1790{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001791 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001792 for (GLsizei i = 0; i < count; i++)
1793 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001794 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001795 }
1796
Jamie Madill48ef11b2016-04-27 15:21:52 -04001797 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001798}
1799
1800void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1801{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001803 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001804 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1805 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001806 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1807 if (length)
1808 {
1809 *length = lastNameIdx;
1810 }
1811 if (size)
1812 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001813 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001814 }
1815 if (type)
1816 {
1817 *type = varying.type;
1818 }
1819 if (name)
1820 {
1821 memcpy(name, varying.name.c_str(), lastNameIdx);
1822 name[lastNameIdx] = '\0';
1823 }
1824 }
1825}
1826
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001827GLsizei Program::getTransformFeedbackVaryingCount() const
1828{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001830 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001831 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001832 }
1833 else
1834 {
1835 return 0;
1836 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001837}
1838
1839GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1840{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001842 {
1843 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001844 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001845 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001846 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1847 }
1848
1849 return maxSize;
1850 }
1851 else
1852 {
1853 return 0;
1854 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001855}
1856
1857GLenum Program::getTransformFeedbackBufferMode() const
1858{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001859 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860}
1861
Jamie Madill192745a2016-12-22 15:58:21 -05001862bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863{
Jamie Madill192745a2016-12-22 15:58:21 -05001864 const Shader *vertexShader = mState.mAttachedVertexShader;
1865 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1866
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001867 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1868
Jamie Madill4cff2472015-08-21 16:53:18 -04001869 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1870 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871
Sami Väisänen46eaa942016-06-29 10:26:37 +03001872 std::map<GLuint, std::string> staticFragmentInputLocations;
1873
Jamie Madill4cff2472015-08-21 16:53:18 -04001874 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001876 bool matched = false;
1877
1878 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001879 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001880 {
1881 continue;
1882 }
1883
Jamie Madill4cff2472015-08-21 16:53:18 -04001884 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001886 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001888 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001889 if (!linkValidateVaryings(infoLog, output.name, input, output,
1890 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001891 {
1892 return false;
1893 }
1894
Geoff Lang7dd2e102014-11-10 15:19:26 -05001895 matched = true;
1896 break;
1897 }
1898 }
1899
1900 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001901 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001902 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001903 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904 return false;
1905 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001906
1907 // Check for aliased path rendering input bindings (if any).
1908 // If more than one binding refer statically to the same
1909 // location the link must fail.
1910
1911 if (!output.staticUse)
1912 continue;
1913
1914 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1915 if (inputBinding == -1)
1916 continue;
1917
1918 const auto it = staticFragmentInputLocations.find(inputBinding);
1919 if (it == std::end(staticFragmentInputLocations))
1920 {
1921 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1922 }
1923 else
1924 {
1925 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1926 << it->second;
1927 return false;
1928 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001929 }
1930
Jamie Madillada9ecc2015-08-17 12:53:37 -04001931 // TODO(jmadill): verify no unmatched vertex varyings?
1932
Geoff Lang7dd2e102014-11-10 15:19:26 -05001933 return true;
1934}
1935
Martin Radev4c4c8e72016-08-04 12:25:34 +03001936bool Program::validateVertexAndFragmentUniforms(InfoLog &infoLog) const
Jamie Madillea918db2015-08-18 14:48:59 -04001937{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001938 // Check that uniforms defined in the vertex and fragment shaders are identical
1939 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001940 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1941 const std::vector<sh::Uniform> &fragmentUniforms =
1942 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001943
Jamie Madillea918db2015-08-18 14:48:59 -04001944 for (const sh::Uniform &vertexUniform : vertexUniforms)
1945 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001946 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001947 }
1948
1949 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1950 {
1951 auto entry = linkedUniforms.find(fragmentUniform.name);
1952 if (entry != linkedUniforms.end())
1953 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001954 LinkedUniform *vertexUniform = &entry->second;
1955 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1956 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001957 {
1958 return false;
1959 }
1960 }
1961 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03001962 return true;
1963}
1964
Jamie Madilla2c74982016-12-12 11:20:42 -05001965bool Program::linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001966{
1967 if (mState.mAttachedVertexShader && mState.mAttachedFragmentShader)
1968 {
1969 ASSERT(mState.mAttachedComputeShader == nullptr);
1970 if (!validateVertexAndFragmentUniforms(infoLog))
1971 {
1972 return false;
1973 }
1974 }
Jamie Madillea918db2015-08-18 14:48:59 -04001975
Jamie Madill62d31cb2015-09-11 13:25:51 -04001976 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1977 // Also check the maximum uniform vector and sampler counts.
1978 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1979 {
1980 return false;
1981 }
1982
Geoff Langd8605522016-04-13 10:19:12 -04001983 if (!indexUniforms(infoLog, caps, uniformBindings))
1984 {
1985 return false;
1986 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001987
Jamie Madillea918db2015-08-18 14:48:59 -04001988 return true;
1989}
1990
Jamie Madilla2c74982016-12-12 11:20:42 -05001991bool Program::indexUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001992{
Geoff Langd8605522016-04-13 10:19:12 -04001993 // Uniforms awaiting a location
1994 std::vector<VariableLocation> unboundUniforms;
1995 std::map<GLuint, VariableLocation> boundUniforms;
1996 int maxUniformLocation = -1;
1997
1998 // Gather bound and unbound uniforms
Jamie Madill48ef11b2016-04-27 15:21:52 -04001999 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002000 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002001 const LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002002
Geoff Langd8605522016-04-13 10:19:12 -04002003 if (uniform.isBuiltIn())
2004 {
2005 continue;
2006 }
2007
2008 int bindingLocation = uniformBindings.getBinding(uniform.name);
2009
2010 // Verify that this location isn't bound twice
2011 if (bindingLocation != -1 && boundUniforms.find(bindingLocation) != boundUniforms.end())
2012 {
2013 infoLog << "Multiple uniforms bound to location " << bindingLocation << ".";
2014 return false;
2015 }
2016
Jamie Madill62d31cb2015-09-11 13:25:51 -04002017 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
2018 {
Geoff Langd8605522016-04-13 10:19:12 -04002019 VariableLocation location(uniform.name, arrayIndex,
2020 static_cast<unsigned int>(uniformIndex));
2021
2022 if (arrayIndex == 0 && bindingLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002023 {
Geoff Langd8605522016-04-13 10:19:12 -04002024 boundUniforms[bindingLocation] = location;
2025 maxUniformLocation = std::max(maxUniformLocation, bindingLocation);
2026 }
2027 else
2028 {
2029 unboundUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002030 }
2031 }
2032 }
Geoff Langd8605522016-04-13 10:19:12 -04002033
2034 // Gather the reserved bindings, ones that are bound but not referenced. Other uniforms should
2035 // not be assigned to those locations.
2036 std::set<GLuint> reservedLocations;
2037 for (const auto &binding : uniformBindings)
2038 {
2039 GLuint location = binding.second;
2040 if (boundUniforms.find(location) == boundUniforms.end())
2041 {
2042 reservedLocations.insert(location);
2043 maxUniformLocation = std::max(maxUniformLocation, static_cast<int>(location));
2044 }
2045 }
2046
2047 // Make enough space for all uniforms, bound and unbound
Jamie Madill48ef11b2016-04-27 15:21:52 -04002048 mState.mUniformLocations.resize(
Geoff Langd8605522016-04-13 10:19:12 -04002049 std::max(unboundUniforms.size() + boundUniforms.size() + reservedLocations.size(),
2050 static_cast<size_t>(maxUniformLocation + 1)));
2051
2052 // Assign bound uniforms
2053 for (const auto &boundUniform : boundUniforms)
2054 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002055 mState.mUniformLocations[boundUniform.first] = boundUniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04002056 }
2057
2058 // Assign reserved uniforms
2059 for (const auto &reservedLocation : reservedLocations)
2060 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002061 mState.mUniformLocations[reservedLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04002062 }
2063
2064 // Assign unbound uniforms
2065 size_t nextUniformLocation = 0;
2066 for (const auto &unboundUniform : unboundUniforms)
2067 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002068 while (mState.mUniformLocations[nextUniformLocation].used ||
2069 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04002070 {
2071 nextUniformLocation++;
2072 }
2073
Jamie Madill48ef11b2016-04-27 15:21:52 -04002074 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
2075 mState.mUniformLocations[nextUniformLocation] = unboundUniform;
Geoff Langd8605522016-04-13 10:19:12 -04002076 nextUniformLocation++;
2077 }
2078
2079 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002080}
2081
Martin Radev4c4c8e72016-08-04 12:25:34 +03002082bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2083 const std::string &uniformName,
2084 const sh::InterfaceBlockField &vertexUniform,
2085 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002086{
Jamie Madillc4c744222015-11-04 09:39:47 -05002087 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
2088 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002089 {
2090 return false;
2091 }
2092
2093 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2094 {
Jamie Madillf6113162015-05-07 11:49:21 -04002095 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002096 return false;
2097 }
2098
2099 return true;
2100}
2101
Jamie Madilleb979bf2016-11-15 12:28:46 -05002102// Assigns locations to all attributes from the bindings and program locations.
2103bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002104{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002105 const auto *vertexShader = mState.getAttachedVertexShader();
2106
Geoff Lang7dd2e102014-11-10 15:19:26 -05002107 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002108 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002109 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002110
2111 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002112 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002113 {
Jamie Madillf6113162015-05-07 11:49:21 -04002114 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002115 return false;
2116 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002117
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002118 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002119
Jamie Madillc349ec02015-08-21 16:53:12 -04002120 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002121 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002122 {
2123 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05002124 ASSERT(attribute.staticUse);
2125
Jamie Madilleb979bf2016-11-15 12:28:46 -05002126 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002127 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002128 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002129 attribute.location = bindingLocation;
2130 }
2131
2132 if (attribute.location != -1)
2133 {
2134 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002135 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002136
Jamie Madill63805b42015-08-25 13:17:39 -04002137 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002138 {
Jamie Madillf6113162015-05-07 11:49:21 -04002139 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002140 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002141
2142 return false;
2143 }
2144
Jamie Madill63805b42015-08-25 13:17:39 -04002145 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 {
Jamie Madill63805b42015-08-25 13:17:39 -04002147 const int regLocation = attribute.location + reg;
2148 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002149
2150 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002151 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002152 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002153 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002154 // TODO(jmadill): fix aliasing on ES2
2155 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002156 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002157 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002158 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159 return false;
2160 }
2161 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002162 else
2163 {
Jamie Madill63805b42015-08-25 13:17:39 -04002164 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002165 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002166
Jamie Madill63805b42015-08-25 13:17:39 -04002167 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002168 }
2169 }
2170 }
2171
2172 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002173 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175 ASSERT(attribute.staticUse);
2176
Jamie Madillc349ec02015-08-21 16:53:12 -04002177 // Not set by glBindAttribLocation or by location layout qualifier
2178 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002179 {
Jamie Madill63805b42015-08-25 13:17:39 -04002180 int regs = VariableRegisterCount(attribute.type);
2181 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002182
Jamie Madill63805b42015-08-25 13:17:39 -04002183 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002184 {
Jamie Madillf6113162015-05-07 11:49:21 -04002185 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002186 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002187 }
2188
Jamie Madillc349ec02015-08-21 16:53:12 -04002189 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002190 }
2191 }
2192
Jamie Madill48ef11b2016-04-27 15:21:52 -04002193 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002194 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002195 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04002196 ASSERT(attribute.location != -1);
2197 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002198
Jamie Madill63805b42015-08-25 13:17:39 -04002199 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002200 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002201 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002202 }
2203 }
2204
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205 return true;
2206}
2207
Martin Radev4c4c8e72016-08-04 12:25:34 +03002208bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2209 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2210 const std::string &errorMessage,
2211 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002212{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002213 GLuint blockCount = 0;
2214 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002215 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002216 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002217 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002218 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002219 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002220 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002221 return false;
2222 }
2223 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002224 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002225 return true;
2226}
Jamie Madille473dee2015-08-18 14:49:01 -04002227
Martin Radev4c4c8e72016-08-04 12:25:34 +03002228bool Program::validateVertexAndFragmentInterfaceBlocks(
2229 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2230 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2231 InfoLog &infoLog) const
2232{
2233 // Check that interface blocks defined in the vertex and fragment shaders are identical
2234 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2235 UniformBlockMap linkedUniformBlocks;
2236
2237 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2238 {
2239 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2240 }
2241
Jamie Madille473dee2015-08-18 14:49:01 -04002242 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002243 {
Jamie Madille473dee2015-08-18 14:49:01 -04002244 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002245 if (entry != linkedUniformBlocks.end())
2246 {
2247 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2248 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2249 {
2250 return false;
2251 }
2252 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002253 }
2254 return true;
2255}
Jamie Madille473dee2015-08-18 14:49:01 -04002256
Martin Radev4c4c8e72016-08-04 12:25:34 +03002257bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2258{
2259 if (mState.mAttachedComputeShader)
2260 {
2261 const Shader &computeShader = *mState.mAttachedComputeShader;
2262 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2263
2264 if (!validateUniformBlocksCount(
2265 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2266 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2267 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002268 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002269 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002270 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002271 return true;
2272 }
2273
2274 const Shader &vertexShader = *mState.mAttachedVertexShader;
2275 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2276
2277 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2278 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2279
2280 if (!validateUniformBlocksCount(
2281 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2282 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2283 {
2284 return false;
2285 }
2286 if (!validateUniformBlocksCount(
2287 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2288 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2289 infoLog))
2290 {
2291
2292 return false;
2293 }
2294 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2295 infoLog))
2296 {
2297 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002298 }
Jamie Madille473dee2015-08-18 14:49:01 -04002299
Geoff Lang7dd2e102014-11-10 15:19:26 -05002300 return true;
2301}
2302
Jamie Madilla2c74982016-12-12 11:20:42 -05002303bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002304 const sh::InterfaceBlock &vertexInterfaceBlock,
2305 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002306{
2307 const char* blockName = vertexInterfaceBlock.name.c_str();
2308 // validate blocks for the same member types
2309 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2310 {
Jamie Madillf6113162015-05-07 11:49:21 -04002311 infoLog << "Types for interface block '" << blockName
2312 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002313 return false;
2314 }
2315 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2316 {
Jamie Madillf6113162015-05-07 11:49:21 -04002317 infoLog << "Array sizes differ for interface block '" << blockName
2318 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002319 return false;
2320 }
2321 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2322 {
Jamie Madillf6113162015-05-07 11:49:21 -04002323 infoLog << "Layout qualifiers differ for interface block '" << blockName
2324 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002325 return false;
2326 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002327 const unsigned int numBlockMembers =
2328 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002329 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2330 {
2331 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2332 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2333 if (vertexMember.name != fragmentMember.name)
2334 {
Jamie Madillf6113162015-05-07 11:49:21 -04002335 infoLog << "Name mismatch for field " << blockMemberIndex
2336 << " of interface block '" << blockName
2337 << "': (in vertex: '" << vertexMember.name
2338 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002339 return false;
2340 }
2341 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2342 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2343 {
2344 return false;
2345 }
2346 }
2347 return true;
2348}
2349
2350bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2351 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2352{
2353 if (vertexVariable.type != fragmentVariable.type)
2354 {
Jamie Madillf6113162015-05-07 11:49:21 -04002355 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002356 return false;
2357 }
2358 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2359 {
Jamie Madillf6113162015-05-07 11:49:21 -04002360 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002361 return false;
2362 }
2363 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2364 {
Jamie Madillf6113162015-05-07 11:49:21 -04002365 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002366 return false;
2367 }
2368
2369 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2370 {
Jamie Madillf6113162015-05-07 11:49:21 -04002371 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002372 return false;
2373 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002374 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002375 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2376 {
2377 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2378 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2379
2380 if (vertexMember.name != fragmentMember.name)
2381 {
Jamie Madillf6113162015-05-07 11:49:21 -04002382 infoLog << "Name mismatch for field '" << memberIndex
2383 << "' of " << variableName
2384 << ": (in vertex: '" << vertexMember.name
2385 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002386 return false;
2387 }
2388
2389 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2390 vertexMember.name + "'";
2391
2392 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2393 {
2394 return false;
2395 }
2396 }
2397
2398 return true;
2399}
2400
2401bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2402{
Cooper Partin1acf4382015-06-12 12:38:57 -07002403#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2404 const bool validatePrecision = true;
2405#else
2406 const bool validatePrecision = false;
2407#endif
2408
2409 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002410 {
2411 return false;
2412 }
2413
2414 return true;
2415}
2416
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002417bool Program::linkValidateVaryings(InfoLog &infoLog,
2418 const std::string &varyingName,
2419 const sh::Varying &vertexVarying,
2420 const sh::Varying &fragmentVarying,
2421 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002422{
2423 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2424 {
2425 return false;
2426 }
2427
Jamie Madille9cc4692015-02-19 16:00:13 -05002428 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002429 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002430 infoLog << "Interpolation types for " << varyingName
2431 << " differ between vertex and fragment shaders.";
2432 return false;
2433 }
2434
2435 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2436 {
2437 infoLog << "Invariance for " << varyingName
2438 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002439 return false;
2440 }
2441
2442 return true;
2443}
2444
Jamie Madillccdf74b2015-08-18 10:46:12 -04002445bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002446 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002447 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002448{
2449 size_t totalComponents = 0;
2450
Jamie Madillccdf74b2015-08-18 10:46:12 -04002451 std::set<std::string> uniqueNames;
2452
Jamie Madill48ef11b2016-04-27 15:21:52 -04002453 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002454 {
2455 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002456 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002457 {
Jamie Madill192745a2016-12-22 15:58:21 -05002458 const sh::Varying *varying = ref.second.get();
2459
Jamie Madillccdf74b2015-08-18 10:46:12 -04002460 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002461 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002462 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002463 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002464 infoLog << "Two transform feedback varyings specify the same output variable ("
2465 << tfVaryingName << ").";
2466 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002467 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002468 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002469
Geoff Lang1a683462015-09-29 15:09:59 -04002470 if (varying->isArray())
2471 {
2472 infoLog << "Capture of arrays is undefined and not supported.";
2473 return false;
2474 }
2475
Jamie Madillccdf74b2015-08-18 10:46:12 -04002476 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002477 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002478 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002479 componentCount > caps.maxTransformFeedbackSeparateComponents)
2480 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002481 infoLog << "Transform feedback varying's " << varying->name << " components ("
2482 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002483 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002484 return false;
2485 }
2486
2487 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002488 found = true;
2489 break;
2490 }
2491 }
2492
Jamie Madill89bb70e2015-08-31 14:18:39 -04002493 if (tfVaryingName.find('[') != std::string::npos)
2494 {
Geoff Lang1a683462015-09-29 15:09:59 -04002495 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002496 return false;
2497 }
2498
Geoff Lang7dd2e102014-11-10 15:19:26 -05002499 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2500 ASSERT(found);
2501 }
2502
Jamie Madill48ef11b2016-04-27 15:21:52 -04002503 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002504 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002505 {
Jamie Madillf6113162015-05-07 11:49:21 -04002506 infoLog << "Transform feedback varying total components (" << totalComponents
2507 << ") exceed the maximum interleaved components ("
2508 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002509 return false;
2510 }
2511
2512 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002513}
2514
Jamie Madill192745a2016-12-22 15:58:21 -05002515void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002516{
2517 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002518 mState.mTransformFeedbackVaryingVars.clear();
2519 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002520 {
Jamie Madill192745a2016-12-22 15:58:21 -05002521 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002522 {
Jamie Madill192745a2016-12-22 15:58:21 -05002523 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002524 if (tfVaryingName == varying->name)
2525 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002526 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002527 break;
2528 }
2529 }
2530 }
2531}
2532
Jamie Madill192745a2016-12-22 15:58:21 -05002533Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002534{
Jamie Madill192745a2016-12-22 15:58:21 -05002535 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002536
Jamie Madill48ef11b2016-04-27 15:21:52 -04002537 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002538 {
Jamie Madill192745a2016-12-22 15:58:21 -05002539 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002540 }
2541
Jamie Madill48ef11b2016-04-27 15:21:52 -04002542 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002543 {
Jamie Madill192745a2016-12-22 15:58:21 -05002544 merged[varying.name].fragment = &varying;
2545 }
2546
2547 return merged;
2548}
2549
2550std::vector<PackedVarying> Program::getPackedVaryings(
2551 const Program::MergedVaryings &mergedVaryings) const
2552{
2553 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2554 std::vector<PackedVarying> packedVaryings;
2555
2556 for (const auto &ref : mergedVaryings)
2557 {
2558 const sh::Varying *input = ref.second.vertex;
2559 const sh::Varying *output = ref.second.fragment;
2560
2561 // Only pack varyings that have a matched input or output, plus special builtins.
2562 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002563 {
Jamie Madill192745a2016-12-22 15:58:21 -05002564 // Will get the vertex shader interpolation by default.
2565 auto interpolation = ref.second.get()->interpolation;
2566
2567 // Interpolation qualifiers must match.
2568 if (output->isStruct())
2569 {
2570 ASSERT(!output->isArray());
2571 for (const auto &field : output->fields)
2572 {
2573 ASSERT(!field.isStruct() && !field.isArray());
2574 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2575 }
2576 }
2577 else
2578 {
2579 packedVaryings.push_back(PackedVarying(*output, interpolation));
2580 }
2581 continue;
2582 }
2583
2584 // Keep Transform FB varyings in the merged list always.
2585 if (!input)
2586 {
2587 continue;
2588 }
2589
2590 for (const std::string &tfVarying : tfVaryings)
2591 {
2592 if (tfVarying == input->name)
2593 {
2594 // Transform feedback for varying structs is underspecified.
2595 // See Khronos bug 9856.
2596 // TODO(jmadill): Figure out how to be spec-compliant here.
2597 if (!input->isStruct())
2598 {
2599 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2600 packedVaryings.back().vertexOnly = true;
2601 }
2602 break;
2603 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002604 }
2605 }
2606
Jamie Madill192745a2016-12-22 15:58:21 -05002607 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2608
2609 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002610}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002611
2612void Program::linkOutputVariables()
2613{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002614 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002615 ASSERT(fragmentShader != nullptr);
2616
2617 // Skip this step for GLES2 shaders.
2618 if (fragmentShader->getShaderVersion() == 100)
2619 return;
2620
Jamie Madilla0a9e122015-09-02 15:54:30 -04002621 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002622
2623 // TODO(jmadill): any caps validation here?
2624
2625 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2626 outputVariableIndex++)
2627 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002628 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002629
2630 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2631 if (outputVariable.isBuiltIn())
2632 continue;
2633
2634 // Since multiple output locations must be specified, use 0 for non-specified locations.
2635 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2636
2637 ASSERT(outputVariable.staticUse);
2638
2639 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2640 elementIndex++)
2641 {
2642 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002643 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002644 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002645 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002646 VariableLocation(outputVariable.name, element, outputVariableIndex);
2647 }
2648 }
2649}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002650
Jamie Madilla2c74982016-12-12 11:20:42 -05002651bool Program::flattenUniformsAndCheckCapsForShader(const Shader &shader,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002652 GLuint maxUniformComponents,
2653 GLuint maxTextureImageUnits,
2654 const std::string &componentsErrorMessage,
2655 const std::string &samplerErrorMessage,
2656 std::vector<LinkedUniform> &samplerUniforms,
2657 InfoLog &infoLog)
2658{
2659 VectorAndSamplerCount vasCount;
2660 for (const sh::Uniform &uniform : shader.getUniforms())
2661 {
2662 if (uniform.staticUse)
2663 {
2664 vasCount += flattenUniform(uniform, uniform.name, &samplerUniforms);
2665 }
2666 }
2667
2668 if (vasCount.vectorCount > maxUniformComponents)
2669 {
2670 infoLog << componentsErrorMessage << maxUniformComponents << ").";
2671 return false;
2672 }
2673
2674 if (vasCount.samplerCount > maxTextureImageUnits)
2675 {
2676 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
2677 return false;
2678 }
2679
2680 return true;
2681}
2682
Jamie Madill62d31cb2015-09-11 13:25:51 -04002683bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2684{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002685 std::vector<LinkedUniform> samplerUniforms;
2686
Martin Radev4c4c8e72016-08-04 12:25:34 +03002687 if (mState.mAttachedComputeShader)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002688 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002689 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002690
2691 // TODO (mradev): check whether we need finer-grained component counting
2692 if (!flattenUniformsAndCheckCapsForShader(
2693 *computeShader, caps.maxComputeUniformComponents / 4,
2694 caps.maxComputeTextureImageUnits,
2695 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
2696 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
2697 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002698 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002699 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002700 }
2701 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002702 else
Jamie Madill62d31cb2015-09-11 13:25:51 -04002703 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002704 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002705
Martin Radev4c4c8e72016-08-04 12:25:34 +03002706 if (!flattenUniformsAndCheckCapsForShader(
2707 *vertexShader, caps.maxVertexUniformVectors, caps.maxVertexTextureImageUnits,
2708 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
2709 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
2710 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002711 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002712 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002713 }
Jamie Madilla2c74982016-12-12 11:20:42 -05002714 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002715
Martin Radev4c4c8e72016-08-04 12:25:34 +03002716 if (!flattenUniformsAndCheckCapsForShader(
2717 *fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
2718 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
2719 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms,
2720 infoLog))
2721 {
2722 return false;
2723 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002724 }
2725
Jamie Madille7d84322017-01-10 18:21:59 -05002726 mState.mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
2727 mState.mSamplerUniformRange.end =
2728 mState.mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002729
Jamie Madill48ef11b2016-04-27 15:21:52 -04002730 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002731
Jamie Madille7d84322017-01-10 18:21:59 -05002732 // If uniform is a sampler type, insert it into the mSamplerBindings array.
2733 for (const auto &samplerUniform : samplerUniforms)
2734 {
2735 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2736 mState.mSamplerBindings.emplace_back(
2737 SamplerBinding(textureType, samplerUniform.elementCount()));
2738 }
2739
Jamie Madill62d31cb2015-09-11 13:25:51 -04002740 return true;
2741}
2742
2743Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002744 const std::string &fullName,
2745 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002746{
2747 VectorAndSamplerCount vectorAndSamplerCount;
2748
2749 if (uniform.isStruct())
2750 {
2751 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2752 {
2753 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2754
2755 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2756 {
2757 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2758 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2759
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002760 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002761 }
2762 }
2763
2764 return vectorAndSamplerCount;
2765 }
2766
2767 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002768 bool isSampler = IsSamplerType(uniform.type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002769 if (!UniformInList(mState.getUniforms(), fullName) &&
2770 !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002771 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002772 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
2773 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002774 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002775
2776 // Store sampler uniforms separately, so we'll append them to the end of the list.
2777 if (isSampler)
2778 {
2779 samplerUniforms->push_back(linkedUniform);
2780 }
2781 else
2782 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002783 mState.mUniforms.push_back(linkedUniform);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002784 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002785 }
2786
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002787 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002788
2789 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2790 // Likewise, don't count "real" uniforms towards sampler count.
2791 vectorAndSamplerCount.vectorCount =
2792 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002793 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002794
2795 return vectorAndSamplerCount;
2796}
2797
2798void Program::gatherInterfaceBlockInfo()
2799{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002800 ASSERT(mState.mUniformBlocks.empty());
2801
2802 if (mState.mAttachedComputeShader)
2803 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002804 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002805
2806 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2807 {
2808
2809 // Only 'packed' blocks are allowed to be considered inactive.
2810 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2811 continue;
2812
Jamie Madilla2c74982016-12-12 11:20:42 -05002813 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002814 {
2815 if (block.name == computeBlock.name)
2816 {
2817 block.computeStaticUse = computeBlock.staticUse;
2818 }
2819 }
2820
2821 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2822 }
2823 return;
2824 }
2825
Jamie Madill62d31cb2015-09-11 13:25:51 -04002826 std::set<std::string> visitedList;
2827
Jamie Madilla2c74982016-12-12 11:20:42 -05002828 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002829
Jamie Madill62d31cb2015-09-11 13:25:51 -04002830 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2831 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002832 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002833 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2834 continue;
2835
2836 if (visitedList.count(vertexBlock.name) > 0)
2837 continue;
2838
2839 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2840 visitedList.insert(vertexBlock.name);
2841 }
2842
Jamie Madilla2c74982016-12-12 11:20:42 -05002843 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002844
2845 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2846 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002847 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002848 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2849 continue;
2850
2851 if (visitedList.count(fragmentBlock.name) > 0)
2852 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002853 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002854 {
2855 if (block.name == fragmentBlock.name)
2856 {
2857 block.fragmentStaticUse = fragmentBlock.staticUse;
2858 }
2859 }
2860
2861 continue;
2862 }
2863
2864 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2865 visitedList.insert(fragmentBlock.name);
2866 }
2867}
2868
Jamie Madill4a3c2342015-10-08 12:58:45 -04002869template <typename VarT>
2870void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2871 const std::string &prefix,
2872 int blockIndex)
2873{
2874 for (const VarT &field : fields)
2875 {
2876 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2877
2878 if (field.isStruct())
2879 {
2880 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2881 {
2882 const std::string uniformElementName =
2883 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2884 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2885 }
2886 }
2887 else
2888 {
2889 // If getBlockMemberInfo returns false, the uniform is optimized out.
2890 sh::BlockMemberInfo memberInfo;
2891 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2892 {
2893 continue;
2894 }
2895
2896 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2897 blockIndex, memberInfo);
2898
2899 // Since block uniforms have no location, we don't need to store them in the uniform
2900 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002901 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002902 }
2903 }
2904}
2905
Jamie Madill62d31cb2015-09-11 13:25:51 -04002906void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2907{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002908 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002909 size_t blockSize = 0;
2910
2911 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002912 std::stringstream blockNameStr;
2913 blockNameStr << interfaceBlock.name;
2914 if (interfaceBlock.arraySize > 0)
2915 {
2916 blockNameStr << "[0]";
2917 }
2918 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002919 {
2920 return;
2921 }
2922
2923 // Track the first and last uniform index to determine the range of active uniforms in the
2924 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002925 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002926 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002927 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002928
2929 std::vector<unsigned int> blockUniformIndexes;
2930 for (size_t blockUniformIndex = firstBlockUniformIndex;
2931 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2932 {
2933 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2934 }
2935
2936 if (interfaceBlock.arraySize > 0)
2937 {
2938 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2939 {
2940 UniformBlock block(interfaceBlock.name, true, arrayElement);
2941 block.memberUniformIndexes = blockUniformIndexes;
2942
Martin Radev4c4c8e72016-08-04 12:25:34 +03002943 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002944 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002945 case GL_VERTEX_SHADER:
2946 {
2947 block.vertexStaticUse = interfaceBlock.staticUse;
2948 break;
2949 }
2950 case GL_FRAGMENT_SHADER:
2951 {
2952 block.fragmentStaticUse = interfaceBlock.staticUse;
2953 break;
2954 }
2955 case GL_COMPUTE_SHADER:
2956 {
2957 block.computeStaticUse = interfaceBlock.staticUse;
2958 break;
2959 }
2960 default:
2961 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002962 }
2963
Qin Jiajia0350a642016-11-01 17:01:51 +08002964 // Since all block elements in an array share the same active uniforms, they will all be
2965 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2966 // here we will add every block element in the array.
2967 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002968 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002969 }
2970 }
2971 else
2972 {
2973 UniformBlock block(interfaceBlock.name, false, 0);
2974 block.memberUniformIndexes = blockUniformIndexes;
2975
Martin Radev4c4c8e72016-08-04 12:25:34 +03002976 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002977 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002978 case GL_VERTEX_SHADER:
2979 {
2980 block.vertexStaticUse = interfaceBlock.staticUse;
2981 break;
2982 }
2983 case GL_FRAGMENT_SHADER:
2984 {
2985 block.fragmentStaticUse = interfaceBlock.staticUse;
2986 break;
2987 }
2988 case GL_COMPUTE_SHADER:
2989 {
2990 block.computeStaticUse = interfaceBlock.staticUse;
2991 break;
2992 }
2993 default:
2994 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002995 }
2996
Jamie Madill4a3c2342015-10-08 12:58:45 -04002997 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002998 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002999 }
3000}
3001
Jamie Madille7d84322017-01-10 18:21:59 -05003002template <>
3003void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3004 const uint8_t *destPointer,
3005 GLsizei clampedCount,
3006 const GLint *v)
3007{
3008 // Invalidate the validation cache only if we modify the sampler data.
3009 if (mState.isSamplerUniformIndex(locationInfo.index) &&
3010 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
3011 {
3012 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3013 std::vector<GLuint> *boundTextureUnits =
3014 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
3015
3016 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
3017 mCachedValidateSamplersResult.reset();
3018 }
3019}
3020
3021template <typename T>
3022void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3023 const uint8_t *destPointer,
3024 GLsizei clampedCount,
3025 const T *v)
3026{
3027}
3028
Jamie Madill62d31cb2015-09-11 13:25:51 -04003029template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003030GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003031{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003032 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3033 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003034 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
3035
Corentin Wallez15ac5342016-11-03 17:06:39 -04003036 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3037 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3038 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003039 GLsizei maxElementCount =
3040 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
3041
3042 GLsizei count = countIn;
3043 GLsizei clampedCount = count * vectorSize;
3044 if (clampedCount > maxElementCount)
3045 {
3046 clampedCount = maxElementCount;
3047 count = maxElementCount / vectorSize;
3048 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04003049
Jamie Madill62d31cb2015-09-11 13:25:51 -04003050 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
3051 {
3052 // Do a cast conversion for boolean types. From the spec:
3053 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
3054 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003055 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003056 {
3057 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
3058 }
3059 }
3060 else
3061 {
Jamie Madille7d84322017-01-10 18:21:59 -05003062 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003063 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003064 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003065
3066 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003067}
3068
3069template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003070GLsizei Program::setMatrixUniformInternal(GLint location,
3071 GLsizei count,
3072 GLboolean transpose,
3073 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003074{
3075 if (!transpose)
3076 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003077 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003078 }
3079
3080 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003081 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3082 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003083 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04003084
3085 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3086 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3087 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
3088 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
3089
3090 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003091 {
3092 size_t elementOffset = element * rows * cols;
3093
3094 for (size_t row = 0; row < rows; ++row)
3095 {
3096 for (size_t col = 0; col < cols; ++col)
3097 {
3098 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
3099 }
3100 }
3101 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003102
3103 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003104}
3105
3106template <typename DestT>
3107void Program::getUniformInternal(GLint location, DestT *dataOut) const
3108{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003109 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3110 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003111
3112 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
3113
3114 GLenum componentType = VariableComponentType(uniform.type);
3115 if (componentType == GLTypeToGLenum<DestT>::value)
3116 {
3117 memcpy(dataOut, srcPointer, uniform.getElementSize());
3118 return;
3119 }
3120
Corentin Wallez6596c462016-03-17 17:26:58 -04003121 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003122
3123 switch (componentType)
3124 {
3125 case GL_INT:
3126 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
3127 break;
3128 case GL_UNSIGNED_INT:
3129 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
3130 break;
3131 case GL_BOOL:
3132 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
3133 break;
3134 case GL_FLOAT:
3135 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
3136 break;
3137 default:
3138 UNREACHABLE();
3139 }
3140}
Jamie Madilla4595b82017-01-11 17:36:34 -05003141
3142bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3143{
3144 // Must be called after samplers are validated.
3145 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3146
3147 for (const auto &binding : mState.mSamplerBindings)
3148 {
3149 GLenum textureType = binding.textureType;
3150 for (const auto &unit : binding.boundTextureUnits)
3151 {
3152 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3153 if (programTextureID == textureID)
3154 {
3155 // TODO(jmadill): Check for appropriate overlap.
3156 return true;
3157 }
3158 }
3159 }
3160
3161 return false;
3162}
3163
Jamie Madilla2c74982016-12-12 11:20:42 -05003164} // namespace gl