blob: e7aa9dd5ebaa60e9d33648d12e42496d9d6d69b9 [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
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000128LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400129{
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000130 for (LinkedUniform &uniform : list)
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400131 {
132 if (uniform.name == name)
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000133 return &uniform;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400134 }
135
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000136 return nullptr;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400137}
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{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500257 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400258}
259
Jamie Madill48ef11b2016-04-27 15:21:52 -0400260const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500261{
262 return mLabel;
263}
264
Jamie Madill48ef11b2016-04-27 15:21:52 -0400265GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400266{
267 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500268 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400269
270 for (size_t location = 0; location < mUniformLocations.size(); ++location)
271 {
272 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400273 if (!uniformLocation.used)
274 {
275 continue;
276 }
277
278 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400279
280 if (uniform.name == baseName)
281 {
Geoff Langd8605522016-04-13 10:19:12 -0400282 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400283 {
Geoff Langd8605522016-04-13 10:19:12 -0400284 if (uniformLocation.element == subscript ||
285 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
286 {
287 return static_cast<GLint>(location);
288 }
289 }
290 else
291 {
292 if (subscript == GL_INVALID_INDEX)
293 {
294 return static_cast<GLint>(location);
295 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400296 }
297 }
298 }
299
300 return -1;
301}
302
Jamie Madille7d84322017-01-10 18:21:59 -0500303GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400304{
305 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -0500306 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400307
308 // The app is not allowed to specify array indices other than 0 for arrays of basic types
309 if (subscript != 0 && subscript != GL_INVALID_INDEX)
310 {
311 return GL_INVALID_INDEX;
312 }
313
314 for (size_t index = 0; index < mUniforms.size(); index++)
315 {
316 const LinkedUniform &uniform = mUniforms[index];
317 if (uniform.name == baseName)
318 {
319 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
320 {
321 return static_cast<GLuint>(index);
322 }
323 }
324 }
325
326 return GL_INVALID_INDEX;
327}
328
Jamie Madille7d84322017-01-10 18:21:59 -0500329GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
330{
331 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
332 return mUniformLocations[location].index;
333}
334
335Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
336{
337 GLuint index = getUniformIndexFromLocation(location);
338 if (!isSamplerUniformIndex(index))
339 {
340 return Optional<GLuint>::Invalid();
341 }
342
343 return getSamplerIndexFromUniformIndex(index);
344}
345
346bool ProgramState::isSamplerUniformIndex(GLuint index) const
347{
348 return index >= mSamplerUniformRange.start && index < mSamplerUniformRange.end;
349}
350
351GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
352{
353 ASSERT(isSamplerUniformIndex(uniformIndex));
354 return uniformIndex - mSamplerUniformRange.start;
355}
356
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500357Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400358 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400359 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500360 mLinked(false),
361 mDeleteStatus(false),
362 mRefCount(0),
363 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500364 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500365{
366 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000367
368 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500369 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370}
371
372Program::~Program()
373{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500374 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
375 !mState.mAttachedComputeShader);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500376 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377}
378
Jamie Madill6c1f6712017-02-14 19:08:04 -0500379void Program::destroy(const Context *context)
380{
381 if (mState.mAttachedVertexShader != nullptr)
382 {
383 mState.mAttachedVertexShader->release(context);
384 mState.mAttachedVertexShader = nullptr;
385 }
386
387 if (mState.mAttachedFragmentShader != nullptr)
388 {
389 mState.mAttachedFragmentShader->release(context);
390 mState.mAttachedFragmentShader = nullptr;
391 }
392
393 if (mState.mAttachedComputeShader != nullptr)
394 {
395 mState.mAttachedComputeShader->release(context);
396 mState.mAttachedComputeShader = nullptr;
397 }
398
399 mProgram->destroy(rx::SafeGetImpl(context));
400}
401
Geoff Lang70d0f492015-12-10 17:45:46 -0500402void Program::setLabel(const std::string &label)
403{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400404 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500405}
406
407const std::string &Program::getLabel() const
408{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400409 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500410}
411
Jamie Madillef300b12016-10-07 15:12:09 -0400412void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300414 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300416 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000417 {
Jamie Madillef300b12016-10-07 15:12:09 -0400418 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300419 mState.mAttachedVertexShader = shader;
420 mState.mAttachedVertexShader->addRef();
421 break;
422 }
423 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424 {
Jamie Madillef300b12016-10-07 15:12:09 -0400425 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300426 mState.mAttachedFragmentShader = shader;
427 mState.mAttachedFragmentShader->addRef();
428 break;
429 }
430 case GL_COMPUTE_SHADER:
431 {
Jamie Madillef300b12016-10-07 15:12:09 -0400432 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300433 mState.mAttachedComputeShader = shader;
434 mState.mAttachedComputeShader->addRef();
435 break;
436 }
437 default:
438 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440}
441
Jamie Madill6c1f6712017-02-14 19:08:04 -0500442bool Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300444 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300446 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300448 if (mState.mAttachedVertexShader != shader)
449 {
450 return false;
451 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452
Jamie Madill6c1f6712017-02-14 19:08:04 -0500453 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300454 mState.mAttachedVertexShader = nullptr;
455 break;
456 }
457 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300459 if (mState.mAttachedFragmentShader != shader)
460 {
461 return false;
462 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463
Jamie Madill6c1f6712017-02-14 19:08:04 -0500464 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300465 mState.mAttachedFragmentShader = nullptr;
466 break;
467 }
468 case GL_COMPUTE_SHADER:
469 {
470 if (mState.mAttachedComputeShader != shader)
471 {
472 return false;
473 }
474
Jamie Madill6c1f6712017-02-14 19:08:04 -0500475 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300476 mState.mAttachedComputeShader = nullptr;
477 break;
478 }
479 default:
480 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483 return true;
484}
485
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000486int Program::getAttachedShadersCount() const
487{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300488 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
489 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000490}
491
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000492void Program::bindAttributeLocation(GLuint index, const char *name)
493{
Geoff Langd8605522016-04-13 10:19:12 -0400494 mAttributeBindings.bindLocation(index, name);
495}
496
497void Program::bindUniformLocation(GLuint index, const char *name)
498{
499 // Bind the base uniform name only since array indices other than 0 cannot be bound
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000500 mUniformLocationBindings.bindLocation(index, ParseUniformName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501}
502
Sami Väisänen46eaa942016-06-29 10:26:37 +0300503void Program::bindFragmentInputLocation(GLint index, const char *name)
504{
505 mFragmentInputBindings.bindLocation(index, name);
506}
507
508BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
509{
510 BindingInfo ret;
511 ret.type = GL_NONE;
512 ret.valid = false;
513
514 const Shader *fragmentShader = mState.getAttachedFragmentShader();
515 ASSERT(fragmentShader);
516
517 // Find the actual fragment shader varying we're interested in
518 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
519
520 for (const auto &binding : mFragmentInputBindings)
521 {
522 if (binding.second != static_cast<GLuint>(index))
523 continue;
524
525 ret.valid = true;
526
527 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400528 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300529
530 for (const auto &in : inputs)
531 {
532 if (in.name == originalName)
533 {
534 if (in.isArray())
535 {
536 // The client wants to bind either "name" or "name[0]".
537 // GL ES 3.1 spec refers to active array names with language such as:
538 // "if the string identifies the base name of an active array, where the
539 // string would exactly match the name of the variable if the suffix "[0]"
540 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400541 if (arrayIndex == GL_INVALID_INDEX)
542 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300543
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400544 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300545 }
546 else
547 {
548 ret.name = in.mappedName;
549 }
550 ret.type = in.type;
551 return ret;
552 }
553 }
554 }
555
556 return ret;
557}
558
559void Program::pathFragmentInputGen(GLint index,
560 GLenum genMode,
561 GLint components,
562 const GLfloat *coeffs)
563{
564 // If the location is -1 then the command is silently ignored
565 if (index == -1)
566 return;
567
568 const auto &binding = getFragmentInputBindingInfo(index);
569
570 // If the input doesn't exist then then the command is silently ignored
571 // This could happen through optimization for example, the shader translator
572 // decides that a variable is not actually being used and optimizes it away.
573 if (binding.name.empty())
574 return;
575
576 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
577}
578
Martin Radev4c4c8e72016-08-04 12:25:34 +0300579// The attached shaders are checked for linking errors by matching up their variables.
580// Uniform, input and output variables get collected.
581// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500582Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000583{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500584 const auto &data = context->getContextState();
585
Jamie Madill6c1f6712017-02-14 19:08:04 -0500586 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000587
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000588 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000589 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000590
Martin Radev4c4c8e72016-08-04 12:25:34 +0300591 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500592
Jamie Madill192745a2016-12-22 15:58:21 -0500593 auto vertexShader = mState.mAttachedVertexShader;
594 auto fragmentShader = mState.mAttachedFragmentShader;
595 auto computeShader = mState.mAttachedComputeShader;
596
597 bool isComputeShaderAttached = (computeShader != nullptr);
598 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300599 // Check whether we both have a compute and non-compute shaders attached.
600 // If there are of both types attached, then linking should fail.
601 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
602 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500603 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300604 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
605 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400606 }
607
Jamie Madill192745a2016-12-22 15:58:21 -0500608 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500609 {
Jamie Madill192745a2016-12-22 15:58:21 -0500610 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300611 {
612 mInfoLog << "Attached compute shader is not compiled.";
613 return NoError();
614 }
Jamie Madill192745a2016-12-22 15:58:21 -0500615 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300616
Jamie Madill192745a2016-12-22 15:58:21 -0500617 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300618
619 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
620 // If the work group size is not specified, a link time error should occur.
621 if (!mState.mComputeShaderLocalSize.isDeclared())
622 {
623 mInfoLog << "Work group size is not specified.";
624 return NoError();
625 }
626
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000627 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300628 {
629 return NoError();
630 }
631
632 if (!linkUniformBlocks(mInfoLog, caps))
633 {
634 return NoError();
635 }
636
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500637 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
638 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), noPacking, mInfoLog),
639 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500640 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300641 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500642 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300643 }
644 }
645 else
646 {
Jamie Madill192745a2016-12-22 15:58:21 -0500647 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300648 {
649 return NoError();
650 }
Jamie Madill192745a2016-12-22 15:58:21 -0500651 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300652
Jamie Madill192745a2016-12-22 15:58:21 -0500653 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300654 {
655 return NoError();
656 }
Jamie Madill192745a2016-12-22 15:58:21 -0500657 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300658
Jamie Madill192745a2016-12-22 15:58:21 -0500659 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300660 {
661 mInfoLog << "Fragment shader version does not match vertex shader version.";
662 return NoError();
663 }
664
Jamie Madilleb979bf2016-11-15 12:28:46 -0500665 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300666 {
667 return NoError();
668 }
669
Jamie Madill192745a2016-12-22 15:58:21 -0500670 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300671 {
672 return NoError();
673 }
674
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000675 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300676 {
677 return NoError();
678 }
679
680 if (!linkUniformBlocks(mInfoLog, caps))
681 {
682 return NoError();
683 }
684
685 const auto &mergedVaryings = getMergedVaryings();
686
687 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
688 {
689 return NoError();
690 }
691
692 linkOutputVariables();
693
Jamie Madill192745a2016-12-22 15:58:21 -0500694 // Validate we can pack the varyings.
695 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
696
697 // Map the varyings to the register file
698 // In WebGL, we use a slightly different handling for packing variables.
699 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
700 : PackMode::ANGLE_RELAXED;
701 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
702 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
703 mState.getTransformFeedbackVaryingNames()))
704 {
705 return NoError();
706 }
707
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500708 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), varyingPacking, mInfoLog),
709 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500710 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300711 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500712 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300713 }
714
715 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500716 }
717
Jamie Madill4a3c2342015-10-08 12:58:45 -0400718 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400719
Martin Radev4c4c8e72016-08-04 12:25:34 +0300720 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000721}
722
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000723// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500724void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000725{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400726 mState.mAttributes.clear();
727 mState.mActiveAttribLocationsMask.reset();
728 mState.mTransformFeedbackVaryingVars.clear();
729 mState.mUniforms.clear();
730 mState.mUniformLocations.clear();
731 mState.mUniformBlocks.clear();
732 mState.mOutputVariables.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300733 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500734 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500735
Geoff Lang7dd2e102014-11-10 15:19:26 -0500736 mValidated = false;
737
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000738 mLinked = false;
739}
740
Geoff Lange1a27752015-10-05 13:16:04 -0400741bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000742{
743 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000744}
745
Jamie Madilla2c74982016-12-12 11:20:42 -0500746Error Program::loadBinary(const Context *context,
747 GLenum binaryFormat,
748 const void *binary,
749 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000750{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500751 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000752
Geoff Lang7dd2e102014-11-10 15:19:26 -0500753#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800754 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500755#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400756 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
757 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000758 {
Jamie Madillf6113162015-05-07 11:49:21 -0400759 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800760 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500761 }
762
Geoff Langc46cc2f2015-10-01 17:16:20 -0400763 BinaryInputStream stream(binary, length);
764
Jamie Madilla2c74982016-12-12 11:20:42 -0500765 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
766 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
767 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
768 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500769 {
Jamie Madillf6113162015-05-07 11:49:21 -0400770 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800771 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500772 }
773
Jamie Madilla2c74982016-12-12 11:20:42 -0500774 int majorVersion = stream.readInt<int>();
775 int minorVersion = stream.readInt<int>();
776 if (majorVersion != context->getClientMajorVersion() ||
777 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500778 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500779 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800780 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500781 }
782
Martin Radev4c4c8e72016-08-04 12:25:34 +0300783 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
784 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
785 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
786
Jamie Madill63805b42015-08-25 13:17:39 -0400787 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
788 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400789 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500790
Jamie Madill3da79b72015-04-27 11:09:17 -0400791 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400792 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400793 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
794 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400795 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400796 LoadShaderVar(&stream, &attrib);
797 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400798 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400799 }
800
Jamie Madill62d31cb2015-09-11 13:25:51 -0400801 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400802 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400803 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
804 {
805 LinkedUniform uniform;
806 LoadShaderVar(&stream, &uniform);
807
808 uniform.blockIndex = stream.readInt<int>();
809 uniform.blockInfo.offset = stream.readInt<int>();
810 uniform.blockInfo.arrayStride = stream.readInt<int>();
811 uniform.blockInfo.matrixStride = stream.readInt<int>();
812 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
813
Jamie Madill48ef11b2016-04-27 15:21:52 -0400814 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400815 }
816
817 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400818 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400819 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
820 uniformIndexIndex++)
821 {
822 VariableLocation variable;
823 stream.readString(&variable.name);
824 stream.readInt(&variable.element);
825 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400826 stream.readBool(&variable.used);
827 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400828
Jamie Madill48ef11b2016-04-27 15:21:52 -0400829 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400830 }
831
832 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400833 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400834 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
835 ++uniformBlockIndex)
836 {
837 UniformBlock uniformBlock;
838 stream.readString(&uniformBlock.name);
839 stream.readBool(&uniformBlock.isArray);
840 stream.readInt(&uniformBlock.arrayElement);
841 stream.readInt(&uniformBlock.dataSize);
842 stream.readBool(&uniformBlock.vertexStaticUse);
843 stream.readBool(&uniformBlock.fragmentStaticUse);
844
845 unsigned int numMembers = stream.readInt<unsigned int>();
846 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
847 {
848 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
849 }
850
Jamie Madill48ef11b2016-04-27 15:21:52 -0400851 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400852 }
853
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500854 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
855 ++bindingIndex)
856 {
857 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
858 mState.mActiveUniformBlockBindings.set(bindingIndex,
859 mState.mUniformBlockBindings[bindingIndex] != 0);
860 }
861
Brandon Jones1048ea72015-10-06 15:34:52 -0700862 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400863 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700864 for (unsigned int transformFeedbackVaryingIndex = 0;
865 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
866 ++transformFeedbackVaryingIndex)
867 {
868 sh::Varying varying;
869 stream.readInt(&varying.arraySize);
870 stream.readInt(&varying.type);
871 stream.readString(&varying.name);
872
Jamie Madill48ef11b2016-04-27 15:21:52 -0400873 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700874 }
875
Jamie Madill48ef11b2016-04-27 15:21:52 -0400876 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400877
Jamie Madill80a6fc02015-08-21 16:53:16 -0400878 unsigned int outputVarCount = stream.readInt<unsigned int>();
879 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
880 {
881 int locationIndex = stream.readInt<int>();
882 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400883 stream.readInt(&locationData.element);
884 stream.readInt(&locationData.index);
885 stream.readString(&locationData.name);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400886 mState.mOutputVariables[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400887 }
888
Jamie Madille7d84322017-01-10 18:21:59 -0500889 stream.readInt(&mState.mSamplerUniformRange.start);
890 stream.readInt(&mState.mSamplerUniformRange.end);
891
892 unsigned int samplerCount = stream.readInt<unsigned int>();
893 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
894 {
895 GLenum textureType = stream.readInt<GLenum>();
896 size_t bindingCount = stream.readInt<size_t>();
897 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
898 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400899
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500900 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000901
Jamie Madillb0a838b2016-11-13 20:02:12 -0500902 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500903#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500904}
905
Jamie Madilla2c74982016-12-12 11:20:42 -0500906Error Program::saveBinary(const Context *context,
907 GLenum *binaryFormat,
908 void *binary,
909 GLsizei bufSize,
910 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500911{
912 if (binaryFormat)
913 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400914 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500915 }
916
917 BinaryOutputStream stream;
918
Geoff Lang7dd2e102014-11-10 15:19:26 -0500919 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
920
Jamie Madilla2c74982016-12-12 11:20:42 -0500921 // nullptr context is supported when computing binary length.
922 if (context)
923 {
924 stream.writeInt(context->getClientVersion().major);
925 stream.writeInt(context->getClientVersion().minor);
926 }
927 else
928 {
929 stream.writeInt(2);
930 stream.writeInt(0);
931 }
932
Martin Radev4c4c8e72016-08-04 12:25:34 +0300933 stream.writeInt(mState.mComputeShaderLocalSize[0]);
934 stream.writeInt(mState.mComputeShaderLocalSize[1]);
935 stream.writeInt(mState.mComputeShaderLocalSize[2]);
936
Jamie Madill48ef11b2016-04-27 15:21:52 -0400937 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500938
Jamie Madill48ef11b2016-04-27 15:21:52 -0400939 stream.writeInt(mState.mAttributes.size());
940 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400941 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400942 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400943 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400944 }
945
Jamie Madill48ef11b2016-04-27 15:21:52 -0400946 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500947 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400948 {
949 WriteShaderVar(&stream, uniform);
950
951 // FIXME: referenced
952
953 stream.writeInt(uniform.blockIndex);
954 stream.writeInt(uniform.blockInfo.offset);
955 stream.writeInt(uniform.blockInfo.arrayStride);
956 stream.writeInt(uniform.blockInfo.matrixStride);
957 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
958 }
959
Jamie Madill48ef11b2016-04-27 15:21:52 -0400960 stream.writeInt(mState.mUniformLocations.size());
961 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400962 {
963 stream.writeString(variable.name);
964 stream.writeInt(variable.element);
965 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400966 stream.writeInt(variable.used);
967 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400968 }
969
Jamie Madill48ef11b2016-04-27 15:21:52 -0400970 stream.writeInt(mState.mUniformBlocks.size());
971 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400972 {
973 stream.writeString(uniformBlock.name);
974 stream.writeInt(uniformBlock.isArray);
975 stream.writeInt(uniformBlock.arrayElement);
976 stream.writeInt(uniformBlock.dataSize);
977
978 stream.writeInt(uniformBlock.vertexStaticUse);
979 stream.writeInt(uniformBlock.fragmentStaticUse);
980
981 stream.writeInt(uniformBlock.memberUniformIndexes.size());
982 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
983 {
984 stream.writeInt(memberUniformIndex);
985 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400986 }
987
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500988 for (GLuint binding : mState.mUniformBlockBindings)
989 {
990 stream.writeInt(binding);
991 }
992
Jamie Madill48ef11b2016-04-27 15:21:52 -0400993 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
994 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -0700995 {
996 stream.writeInt(varying.arraySize);
997 stream.writeInt(varying.type);
998 stream.writeString(varying.name);
999 }
1000
Jamie Madill48ef11b2016-04-27 15:21:52 -04001001 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001002
Jamie Madill48ef11b2016-04-27 15:21:52 -04001003 stream.writeInt(mState.mOutputVariables.size());
1004 for (const auto &outputPair : mState.mOutputVariables)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001005 {
1006 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001007 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001008 stream.writeInt(outputPair.second.index);
1009 stream.writeString(outputPair.second.name);
1010 }
1011
Jamie Madille7d84322017-01-10 18:21:59 -05001012 stream.writeInt(mState.mSamplerUniformRange.start);
1013 stream.writeInt(mState.mSamplerUniformRange.end);
1014
1015 stream.writeInt(mState.mSamplerBindings.size());
1016 for (const auto &samplerBinding : mState.mSamplerBindings)
1017 {
1018 stream.writeInt(samplerBinding.textureType);
1019 stream.writeInt(samplerBinding.boundTextureUnits.size());
1020 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001021
Jamie Madilla2c74982016-12-12 11:20:42 -05001022 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001023
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001024 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001025 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001026
1027 if (streamLength > bufSize)
1028 {
1029 if (length)
1030 {
1031 *length = 0;
1032 }
1033
1034 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1035 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1036 // sizes and then copy it.
1037 return Error(GL_INVALID_OPERATION);
1038 }
1039
1040 if (binary)
1041 {
1042 char *ptr = reinterpret_cast<char*>(binary);
1043
Jamie Madill48ef11b2016-04-27 15:21:52 -04001044 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001045 ptr += streamLength;
1046
1047 ASSERT(ptr - streamLength == binary);
1048 }
1049
1050 if (length)
1051 {
1052 *length = streamLength;
1053 }
1054
He Yunchaoacd18982017-01-04 10:46:42 +08001055 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001056}
1057
1058GLint Program::getBinaryLength() const
1059{
1060 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001061 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001062 if (error.isError())
1063 {
1064 return 0;
1065 }
1066
1067 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001068}
1069
Geoff Langc5629752015-12-07 16:29:04 -05001070void Program::setBinaryRetrievableHint(bool retrievable)
1071{
1072 // TODO(jmadill) : replace with dirty bits
1073 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001074 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001075}
1076
1077bool Program::getBinaryRetrievableHint() const
1078{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001079 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001080}
1081
Jamie Madill6c1f6712017-02-14 19:08:04 -05001082void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001083{
1084 mRefCount--;
1085
1086 if (mRefCount == 0 && mDeleteStatus)
1087 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001088 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001089 }
1090}
1091
1092void Program::addRef()
1093{
1094 mRefCount++;
1095}
1096
1097unsigned int Program::getRefCount() const
1098{
1099 return mRefCount;
1100}
1101
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001102int Program::getInfoLogLength() const
1103{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001104 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001105}
1106
Geoff Lange1a27752015-10-05 13:16:04 -04001107void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001108{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001109 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001110}
1111
Geoff Lange1a27752015-10-05 13:16:04 -04001112void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001113{
1114 int total = 0;
1115
Martin Radev4c4c8e72016-08-04 12:25:34 +03001116 if (mState.mAttachedComputeShader)
1117 {
1118 if (total < maxCount)
1119 {
1120 shaders[total] = mState.mAttachedComputeShader->getHandle();
1121 total++;
1122 }
1123 }
1124
Jamie Madill48ef11b2016-04-27 15:21:52 -04001125 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001126 {
1127 if (total < maxCount)
1128 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001129 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001130 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001131 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001132 }
1133
Jamie Madill48ef11b2016-04-27 15:21:52 -04001134 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001135 {
1136 if (total < maxCount)
1137 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001138 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001139 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001140 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001141 }
1142
1143 if (count)
1144 {
1145 *count = total;
1146 }
1147}
1148
Geoff Lange1a27752015-10-05 13:16:04 -04001149GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001150{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001151 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001152 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001153 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001154 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001155 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001156 }
1157 }
1158
Austin Kinrossb8af7232015-03-16 22:33:25 -07001159 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160}
1161
Jamie Madill63805b42015-08-25 13:17:39 -04001162bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001163{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001164 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1165 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001166}
1167
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001168void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1169{
Jamie Madillc349ec02015-08-21 16:53:12 -04001170 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001171 {
1172 if (bufsize > 0)
1173 {
1174 name[0] = '\0';
1175 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001177 if (length)
1178 {
1179 *length = 0;
1180 }
1181
1182 *type = GL_NONE;
1183 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001184 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001185 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001186
1187 size_t attributeIndex = 0;
1188
Jamie Madill48ef11b2016-04-27 15:21:52 -04001189 for (const sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001190 {
1191 // Skip over inactive attributes
1192 if (attribute.staticUse)
1193 {
1194 if (static_cast<size_t>(index) == attributeIndex)
1195 {
1196 break;
1197 }
1198 attributeIndex++;
1199 }
1200 }
1201
Jamie Madill48ef11b2016-04-27 15:21:52 -04001202 ASSERT(index == attributeIndex && attributeIndex < mState.mAttributes.size());
1203 const sh::Attribute &attrib = mState.mAttributes[attributeIndex];
Jamie Madillc349ec02015-08-21 16:53:12 -04001204
1205 if (bufsize > 0)
1206 {
1207 const char *string = attrib.name.c_str();
1208
1209 strncpy(name, string, bufsize);
1210 name[bufsize - 1] = '\0';
1211
1212 if (length)
1213 {
1214 *length = static_cast<GLsizei>(strlen(name));
1215 }
1216 }
1217
1218 // Always a single 'type' instance
1219 *size = 1;
1220 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001221}
1222
Geoff Lange1a27752015-10-05 13:16:04 -04001223GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001224{
Jamie Madillc349ec02015-08-21 16:53:12 -04001225 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001226 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001227 return 0;
1228 }
1229
1230 GLint count = 0;
1231
Jamie Madill48ef11b2016-04-27 15:21:52 -04001232 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001233 {
1234 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001235 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236
1237 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001238}
1239
Geoff Lange1a27752015-10-05 13:16:04 -04001240GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001241{
Jamie Madillc349ec02015-08-21 16:53:12 -04001242 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001243 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001244 return 0;
1245 }
1246
1247 size_t maxLength = 0;
1248
Jamie Madill48ef11b2016-04-27 15:21:52 -04001249 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001250 {
1251 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001252 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001253 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001254 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001255 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001256
Jamie Madillc349ec02015-08-21 16:53:12 -04001257 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001258}
1259
Geoff Lang7dd2e102014-11-10 15:19:26 -05001260GLint Program::getFragDataLocation(const std::string &name) const
1261{
1262 std::string baseName(name);
1263 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001264 for (auto outputPair : mState.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001265 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001266 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001267 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1268 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001269 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001270 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001271 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001272 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001273}
1274
Geoff Lange1a27752015-10-05 13:16:04 -04001275void Program::getActiveUniform(GLuint index,
1276 GLsizei bufsize,
1277 GLsizei *length,
1278 GLint *size,
1279 GLenum *type,
1280 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001281{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001282 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001283 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001284 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001285 ASSERT(index < mState.mUniforms.size());
1286 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001287
1288 if (bufsize > 0)
1289 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001290 std::string string = uniform.name;
1291 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001292 {
1293 string += "[0]";
1294 }
1295
1296 strncpy(name, string.c_str(), bufsize);
1297 name[bufsize - 1] = '\0';
1298
1299 if (length)
1300 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001301 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001302 }
1303 }
1304
Jamie Madill62d31cb2015-09-11 13:25:51 -04001305 *size = uniform.elementCount();
1306 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001307 }
1308 else
1309 {
1310 if (bufsize > 0)
1311 {
1312 name[0] = '\0';
1313 }
1314
1315 if (length)
1316 {
1317 *length = 0;
1318 }
1319
1320 *size = 0;
1321 *type = GL_NONE;
1322 }
1323}
1324
Geoff Lange1a27752015-10-05 13:16:04 -04001325GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001326{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001327 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001328 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001329 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001330 }
1331 else
1332 {
1333 return 0;
1334 }
1335}
1336
Geoff Lange1a27752015-10-05 13:16:04 -04001337GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001338{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001339 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001340
1341 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001342 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001343 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001344 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001345 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001346 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001347 size_t length = uniform.name.length() + 1u;
1348 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001349 {
1350 length += 3; // Counting in "[0]".
1351 }
1352 maxLength = std::max(length, maxLength);
1353 }
1354 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001355 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001356
Jamie Madill62d31cb2015-09-11 13:25:51 -04001357 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001358}
1359
1360GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1361{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001362 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001363 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001364 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001365 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001366 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1367 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1368 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1369 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1370 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1371 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1372 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1373 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1374 default:
1375 UNREACHABLE();
1376 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001377 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001378 return 0;
1379}
1380
1381bool Program::isValidUniformLocation(GLint location) const
1382{
Jamie Madille2e406c2016-06-02 13:04:10 -04001383 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001384 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1385 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001386}
1387
Jamie Madill62d31cb2015-09-11 13:25:51 -04001388const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001389{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001390 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001391 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392}
1393
Jamie Madillac4e9c32017-01-13 14:07:12 -05001394const VariableLocation &Program::getUniformLocation(GLint location) const
1395{
1396 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1397 return mState.mUniformLocations[location];
1398}
1399
1400const std::vector<VariableLocation> &Program::getUniformLocations() const
1401{
1402 return mState.mUniformLocations;
1403}
1404
1405const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1406{
1407 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1408 return mState.mUniforms[index];
1409}
1410
Jamie Madill62d31cb2015-09-11 13:25:51 -04001411GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001412{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001413 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001414}
1415
Jamie Madill62d31cb2015-09-11 13:25:51 -04001416GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001417{
Jamie Madille7d84322017-01-10 18:21:59 -05001418 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001419}
1420
1421void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1422{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001423 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1424 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001425}
1426
1427void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1428{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001429 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1430 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001431}
1432
1433void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1434{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001435 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1436 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001437}
1438
1439void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1440{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001441 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1442 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443}
1444
1445void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1446{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001447 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1448 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001449}
1450
1451void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1452{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001453 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1454 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001455}
1456
1457void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1458{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001459 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1460 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461}
1462
1463void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1464{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001465 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1466 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467}
1468
1469void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1470{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001471 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1472 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473}
1474
1475void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1476{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001477 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1478 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479}
1480
1481void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1482{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001483 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1484 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1488{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001489 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1490 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
1493void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1494{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001495 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1496 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1500{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001501 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1502 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503}
1504
1505void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1506{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001507 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1508 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1512{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001513 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1514 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1518{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001519 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1520 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521}
1522
1523void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1524{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001525 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1526 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
1529void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1530{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001531 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1532 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001533}
1534
1535void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1536{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001537 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1538 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539}
1540
1541void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1542{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001543 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1544 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545}
1546
Geoff Lange1a27752015-10-05 13:16:04 -04001547void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001548{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001549 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001550}
1551
Geoff Lange1a27752015-10-05 13:16:04 -04001552void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001553{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001554 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001555}
1556
Geoff Lange1a27752015-10-05 13:16:04 -04001557void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001559 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001560}
1561
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562void Program::flagForDeletion()
1563{
1564 mDeleteStatus = true;
1565}
1566
1567bool Program::isFlaggedForDeletion() const
1568{
1569 return mDeleteStatus;
1570}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001571
Brandon Jones43a53e22014-08-28 16:23:22 -07001572void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001573{
1574 mInfoLog.reset();
1575
Geoff Lang7dd2e102014-11-10 15:19:26 -05001576 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001577 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001578 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001579 }
1580 else
1581 {
Jamie Madillf6113162015-05-07 11:49:21 -04001582 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001583 }
1584}
1585
Geoff Lang7dd2e102014-11-10 15:19:26 -05001586bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1587{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001588 // Skip cache if we're using an infolog, so we get the full error.
1589 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1590 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1591 {
1592 return mCachedValidateSamplersResult.value();
1593 }
1594
1595 if (mTextureUnitTypesCache.empty())
1596 {
1597 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1598 }
1599 else
1600 {
1601 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1602 }
1603
1604 // if any two active samplers in a program are of different types, but refer to the same
1605 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1606 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001607 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001608 {
Jamie Madille7d84322017-01-10 18:21:59 -05001609 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001610
Jamie Madille7d84322017-01-10 18:21:59 -05001611 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001612 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001613 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1614 {
1615 if (infoLog)
1616 {
1617 (*infoLog) << "Sampler uniform (" << textureUnit
1618 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1619 << caps.maxCombinedTextureImageUnits << ")";
1620 }
1621
1622 mCachedValidateSamplersResult = false;
1623 return false;
1624 }
1625
1626 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1627 {
1628 if (textureType != mTextureUnitTypesCache[textureUnit])
1629 {
1630 if (infoLog)
1631 {
1632 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1633 "image unit ("
1634 << textureUnit << ").";
1635 }
1636
1637 mCachedValidateSamplersResult = false;
1638 return false;
1639 }
1640 }
1641 else
1642 {
1643 mTextureUnitTypesCache[textureUnit] = textureType;
1644 }
1645 }
1646 }
1647
1648 mCachedValidateSamplersResult = true;
1649 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650}
1651
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001652bool Program::isValidated() const
1653{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001654 return mValidated;
1655}
1656
Geoff Lange1a27752015-10-05 13:16:04 -04001657GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001658{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001659 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001660}
1661
1662void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1663{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001664 ASSERT(
1665 uniformBlockIndex <
1666 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001667
Jamie Madill48ef11b2016-04-27 15:21:52 -04001668 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001669
1670 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001671 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001672 std::string string = uniformBlock.name;
1673
Jamie Madill62d31cb2015-09-11 13:25:51 -04001674 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001675 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001676 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677 }
1678
1679 strncpy(uniformBlockName, string.c_str(), bufSize);
1680 uniformBlockName[bufSize - 1] = '\0';
1681
1682 if (length)
1683 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001684 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001685 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001686 }
1687}
1688
Geoff Lange1a27752015-10-05 13:16:04 -04001689GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001690{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691 int maxLength = 0;
1692
1693 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001694 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001695 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001696 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1697 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001698 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001699 if (!uniformBlock.name.empty())
1700 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001701 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001702
1703 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001704 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001705
1706 maxLength = std::max(length + arrayLength, maxLength);
1707 }
1708 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001709 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001710
1711 return maxLength;
1712}
1713
Geoff Lange1a27752015-10-05 13:16:04 -04001714GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001716 size_t subscript = GL_INVALID_INDEX;
Jamie Madilla2c74982016-12-12 11:20:42 -05001717 std::string baseName = ParseUniformName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001718
Jamie Madill48ef11b2016-04-27 15:21:52 -04001719 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001720 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1721 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001722 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001723 if (uniformBlock.name == baseName)
1724 {
1725 const bool arrayElementZero =
1726 (subscript == GL_INVALID_INDEX &&
1727 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1728 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1729 {
1730 return blockIndex;
1731 }
1732 }
1733 }
1734
1735 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001736}
1737
Jamie Madill62d31cb2015-09-11 13:25:51 -04001738const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001739{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001740 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1741 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001742}
1743
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001744void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1745{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001746 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001747 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001748 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001749}
1750
1751GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1752{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001753 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001754}
1755
1756void Program::resetUniformBlockBindings()
1757{
1758 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1759 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001760 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001761 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001762 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001763}
1764
Geoff Lang48dcae72014-02-05 16:28:24 -05001765void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1766{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001767 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001768 for (GLsizei i = 0; i < count; i++)
1769 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001770 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001771 }
1772
Jamie Madill48ef11b2016-04-27 15:21:52 -04001773 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001774}
1775
1776void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1777{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001778 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001779 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001780 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1781 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001782 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1783 if (length)
1784 {
1785 *length = lastNameIdx;
1786 }
1787 if (size)
1788 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001789 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001790 }
1791 if (type)
1792 {
1793 *type = varying.type;
1794 }
1795 if (name)
1796 {
1797 memcpy(name, varying.name.c_str(), lastNameIdx);
1798 name[lastNameIdx] = '\0';
1799 }
1800 }
1801}
1802
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001803GLsizei Program::getTransformFeedbackVaryingCount() const
1804{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001805 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001806 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001807 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001808 }
1809 else
1810 {
1811 return 0;
1812 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001813}
1814
1815GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1816{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001817 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001818 {
1819 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001820 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001821 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001822 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1823 }
1824
1825 return maxSize;
1826 }
1827 else
1828 {
1829 return 0;
1830 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001831}
1832
1833GLenum Program::getTransformFeedbackBufferMode() const
1834{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001835 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836}
1837
Jamie Madill192745a2016-12-22 15:58:21 -05001838bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001839{
Jamie Madill192745a2016-12-22 15:58:21 -05001840 const Shader *vertexShader = mState.mAttachedVertexShader;
1841 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1842
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001843 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1844
Jamie Madill4cff2472015-08-21 16:53:18 -04001845 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1846 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001847
Sami Väisänen46eaa942016-06-29 10:26:37 +03001848 std::map<GLuint, std::string> staticFragmentInputLocations;
1849
Jamie Madill4cff2472015-08-21 16:53:18 -04001850 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001851 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001852 bool matched = false;
1853
1854 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001855 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856 {
1857 continue;
1858 }
1859
Jamie Madill4cff2472015-08-21 16:53:18 -04001860 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001862 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001864 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001865 if (!linkValidateVaryings(infoLog, output.name, input, output,
1866 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001867 {
1868 return false;
1869 }
1870
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871 matched = true;
1872 break;
1873 }
1874 }
1875
1876 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001877 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001879 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001880 return false;
1881 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001882
1883 // Check for aliased path rendering input bindings (if any).
1884 // If more than one binding refer statically to the same
1885 // location the link must fail.
1886
1887 if (!output.staticUse)
1888 continue;
1889
1890 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1891 if (inputBinding == -1)
1892 continue;
1893
1894 const auto it = staticFragmentInputLocations.find(inputBinding);
1895 if (it == std::end(staticFragmentInputLocations))
1896 {
1897 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1898 }
1899 else
1900 {
1901 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1902 << it->second;
1903 return false;
1904 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001905 }
1906
Yuly Novikov817232e2017-02-22 18:36:10 -05001907 if (!linkValidateBuiltInVaryings(infoLog))
1908 {
1909 return false;
1910 }
1911
Jamie Madillada9ecc2015-08-17 12:53:37 -04001912 // TODO(jmadill): verify no unmatched vertex varyings?
1913
Geoff Lang7dd2e102014-11-10 15:19:26 -05001914 return true;
1915}
1916
Martin Radev4c4c8e72016-08-04 12:25:34 +03001917bool Program::validateVertexAndFragmentUniforms(InfoLog &infoLog) const
Jamie Madillea918db2015-08-18 14:48:59 -04001918{
Martin Radev4c4c8e72016-08-04 12:25:34 +03001919 // Check that uniforms defined in the vertex and fragment shaders are identical
1920 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001921 const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
1922 const std::vector<sh::Uniform> &fragmentUniforms =
1923 mState.mAttachedFragmentShader->getUniforms();
Jamie Madillea918db2015-08-18 14:48:59 -04001924
Jamie Madillea918db2015-08-18 14:48:59 -04001925 for (const sh::Uniform &vertexUniform : vertexUniforms)
1926 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001927 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001928 }
1929
1930 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1931 {
1932 auto entry = linkedUniforms.find(fragmentUniform.name);
1933 if (entry != linkedUniforms.end())
1934 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001935 LinkedUniform *linkedUniform = &entry->second;
1936 const std::string &uniformName = "uniform '" + linkedUniform->name + "'";
1937 if (!linkValidateUniforms(infoLog, uniformName, *linkedUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001938 {
1939 return false;
1940 }
1941 }
1942 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03001943 return true;
1944}
1945
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001946bool Program::linkUniforms(InfoLog &infoLog,
1947 const Caps &caps,
1948 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001949{
1950 if (mState.mAttachedVertexShader && mState.mAttachedFragmentShader)
1951 {
1952 ASSERT(mState.mAttachedComputeShader == nullptr);
1953 if (!validateVertexAndFragmentUniforms(infoLog))
1954 {
1955 return false;
1956 }
1957 }
Jamie Madillea918db2015-08-18 14:48:59 -04001958
Jamie Madill62d31cb2015-09-11 13:25:51 -04001959 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1960 // Also check the maximum uniform vector and sampler counts.
1961 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1962 {
1963 return false;
1964 }
1965
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001966 if (!indexUniforms(infoLog, uniformLocationBindings))
Geoff Langd8605522016-04-13 10:19:12 -04001967 {
1968 return false;
1969 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04001970
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001971 updateSamplerBindings();
1972
1973 return true;
1974}
1975
1976bool Program::gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog,
1977 const Bindings &uniformLocationBindings,
1978 std::set<GLuint> *reservedLocations,
1979 std::set<GLuint> *ignoredLocations,
1980 int *maxUniformLocation)
1981{
1982 for (const LinkedUniform &uniform : mState.mUniforms)
1983 {
1984 if (uniform.isBuiltIn())
1985 {
1986 continue;
1987 }
1988
1989 int apiBoundLocation = uniformLocationBindings.getBinding(uniform.name);
1990 int shaderLocation = uniform.location;
1991
1992 if (shaderLocation != -1)
1993 {
1994 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1995 {
1996 // GLSL ES 3.10 section 4.4.3
1997 int elementLocation = shaderLocation + arrayIndex;
1998 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
1999 if (reservedLocations->find(elementLocation) != reservedLocations->end())
2000 {
2001 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
2002 return false;
2003 }
2004 reservedLocations->insert(elementLocation);
2005 if (!uniform.staticUse)
2006 {
2007 ignoredLocations->insert(elementLocation);
2008 }
2009 }
2010 }
2011 else if (apiBoundLocation != -1 && uniform.staticUse)
2012 {
2013 // Only the first location is reserved even if the uniform is an array.
2014 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
2015 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
2016 {
2017 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
2018 return false;
2019 }
2020 reservedLocations->insert(apiBoundLocation);
2021 }
2022 }
2023
2024 // Record the uniform locations that were bound using the API for uniforms that were not found
2025 // from the shader. Other uniforms should not be assigned to those locations.
2026 for (const auto &locationBinding : uniformLocationBindings)
2027 {
2028 GLuint location = locationBinding.second;
2029 if (reservedLocations->find(location) == reservedLocations->end())
2030 {
2031 ignoredLocations->insert(location);
2032 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
2033 }
2034 }
2035
Jamie Madillea918db2015-08-18 14:48:59 -04002036 return true;
2037}
2038
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002039void Program::pruneUnusedUniforms()
2040{
2041 auto uniformIter = mState.mUniforms.begin();
2042 while (uniformIter != mState.mUniforms.end())
2043 {
2044 if (uniformIter->staticUse)
2045 {
2046 ++uniformIter;
2047 }
2048 else
2049 {
2050 uniformIter = mState.mUniforms.erase(uniformIter);
2051 }
2052 }
2053}
2054
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002055bool Program::indexUniforms(InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002056 const Bindings &uniformLocationBindings)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002057{
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002058 // All the locations where another uniform can't be located.
2059 std::set<GLuint> reservedLocations;
2060 // Locations which have been allocated for an unused uniform.
2061 std::set<GLuint> ignoredLocations;
2062
Geoff Langd8605522016-04-13 10:19:12 -04002063 int maxUniformLocation = -1;
2064
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002065 // Gather uniform locations that have been set either using the bindUniformLocation API or by
2066 // using a location layout qualifier and check conflicts between them.
2067 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
2068 &reservedLocations, &ignoredLocations,
2069 &maxUniformLocation))
2070 {
2071 return false;
2072 }
2073
2074 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
2075 // the line relies on only having statically used uniforms in mState.mUniforms.
2076 pruneUnusedUniforms();
2077
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002078 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002079 std::vector<VariableLocation> unlocatedUniforms;
2080 std::map<GLuint, VariableLocation> preLocatedUniforms;
2081
Jamie Madill48ef11b2016-04-27 15:21:52 -04002082 for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002083 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002084 const LinkedUniform &uniform = mState.mUniforms[uniformIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002085
Geoff Langd8605522016-04-13 10:19:12 -04002086 if (uniform.isBuiltIn())
2087 {
2088 continue;
2089 }
2090
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002091 int preSetLocation = uniformLocationBindings.getBinding(uniform.name);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002092 int shaderLocation = uniform.location;
Geoff Langd8605522016-04-13 10:19:12 -04002093
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002094 if (shaderLocation != -1)
Geoff Langd8605522016-04-13 10:19:12 -04002095 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002096 preSetLocation = shaderLocation;
Geoff Langd8605522016-04-13 10:19:12 -04002097 }
2098
Jamie Madill62d31cb2015-09-11 13:25:51 -04002099 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
2100 {
Geoff Langd8605522016-04-13 10:19:12 -04002101 VariableLocation location(uniform.name, arrayIndex,
2102 static_cast<unsigned int>(uniformIndex));
2103
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002104 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002105 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002106 int elementLocation = preSetLocation + arrayIndex;
2107 preLocatedUniforms[elementLocation] = location;
Geoff Langd8605522016-04-13 10:19:12 -04002108 }
2109 else
2110 {
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002111 unlocatedUniforms.push_back(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002112 }
2113 }
2114 }
Geoff Langd8605522016-04-13 10:19:12 -04002115
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002116 // Make enough space for all uniforms, with pre-set locations or not.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002117 mState.mUniformLocations.resize(
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002118 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
Geoff Langd8605522016-04-13 10:19:12 -04002119 static_cast<size_t>(maxUniformLocation + 1)));
2120
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002121 // Assign uniforms with pre-set locations
2122 for (const auto &uniform : preLocatedUniforms)
Geoff Langd8605522016-04-13 10:19:12 -04002123 {
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002124 mState.mUniformLocations[uniform.first] = uniform.second;
Geoff Langd8605522016-04-13 10:19:12 -04002125 }
2126
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002127 // Assign ignored uniforms
2128 for (const auto &ignoredLocation : ignoredLocations)
Geoff Langd8605522016-04-13 10:19:12 -04002129 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002130 mState.mUniformLocations[ignoredLocation].ignored = true;
Geoff Langd8605522016-04-13 10:19:12 -04002131 }
2132
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002133 // Automatically assign locations for the rest of the uniforms
Geoff Langd8605522016-04-13 10:19:12 -04002134 size_t nextUniformLocation = 0;
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002135 for (const auto &unlocatedUniform : unlocatedUniforms)
Geoff Langd8605522016-04-13 10:19:12 -04002136 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002137 while (mState.mUniformLocations[nextUniformLocation].used ||
2138 mState.mUniformLocations[nextUniformLocation].ignored)
Geoff Langd8605522016-04-13 10:19:12 -04002139 {
2140 nextUniformLocation++;
2141 }
2142
Jamie Madill48ef11b2016-04-27 15:21:52 -04002143 ASSERT(nextUniformLocation < mState.mUniformLocations.size());
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002144 mState.mUniformLocations[nextUniformLocation] = unlocatedUniform;
Geoff Langd8605522016-04-13 10:19:12 -04002145 nextUniformLocation++;
2146 }
2147
2148 return true;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002149}
2150
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002151void Program::updateSamplerBindings()
2152{
2153 mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
2154 mState.mSamplerUniformRange.start = mState.mSamplerUniformRange.end;
2155 auto samplerIter = mState.mUniforms.rbegin();
2156 while (samplerIter != mState.mUniforms.rend() && samplerIter->isSampler())
2157 {
2158 --mState.mSamplerUniformRange.start;
2159 ++samplerIter;
2160 }
2161 // If uniform is a sampler type, insert it into the mSamplerBindings array.
2162 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
2163 samplerIndex < mState.mUniforms.size(); ++samplerIndex)
2164 {
2165 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2166 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2167 mState.mSamplerBindings.emplace_back(
2168 SamplerBinding(textureType, samplerUniform.elementCount()));
2169 }
2170}
2171
Martin Radev4c4c8e72016-08-04 12:25:34 +03002172bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2173 const std::string &uniformName,
2174 const sh::InterfaceBlockField &vertexUniform,
2175 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002176{
Jamie Madillc4c744222015-11-04 09:39:47 -05002177 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
2178 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002179 {
2180 return false;
2181 }
2182
2183 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2184 {
Jamie Madillf6113162015-05-07 11:49:21 -04002185 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002186 return false;
2187 }
2188
2189 return true;
2190}
2191
Jamie Madilleb979bf2016-11-15 12:28:46 -05002192// Assigns locations to all attributes from the bindings and program locations.
2193bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002194{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002195 const auto *vertexShader = mState.getAttachedVertexShader();
2196
Geoff Lang7dd2e102014-11-10 15:19:26 -05002197 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002198 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002199 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002200
2201 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002202 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002203 {
Jamie Madillf6113162015-05-07 11:49:21 -04002204 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002205 return false;
2206 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002207
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002208 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002209
Jamie Madillc349ec02015-08-21 16:53:12 -04002210 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002211 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002212 {
2213 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05002214 ASSERT(attribute.staticUse);
2215
Jamie Madilleb979bf2016-11-15 12:28:46 -05002216 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002217 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002218 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002219 attribute.location = bindingLocation;
2220 }
2221
2222 if (attribute.location != -1)
2223 {
2224 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002225 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002226
Jamie Madill63805b42015-08-25 13:17:39 -04002227 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002228 {
Jamie Madillf6113162015-05-07 11:49:21 -04002229 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002230 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002231
2232 return false;
2233 }
2234
Jamie Madill63805b42015-08-25 13:17:39 -04002235 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002236 {
Jamie Madill63805b42015-08-25 13:17:39 -04002237 const int regLocation = attribute.location + reg;
2238 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002239
2240 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002241 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002242 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002243 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002244 // TODO(jmadill): fix aliasing on ES2
2245 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002246 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002247 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002248 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002249 return false;
2250 }
2251 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002252 else
2253 {
Jamie Madill63805b42015-08-25 13:17:39 -04002254 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002255 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002256
Jamie Madill63805b42015-08-25 13:17:39 -04002257 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002258 }
2259 }
2260 }
2261
2262 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002263 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002264 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002265 ASSERT(attribute.staticUse);
2266
Jamie Madillc349ec02015-08-21 16:53:12 -04002267 // Not set by glBindAttribLocation or by location layout qualifier
2268 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002269 {
Jamie Madill63805b42015-08-25 13:17:39 -04002270 int regs = VariableRegisterCount(attribute.type);
2271 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002272
Jamie Madill63805b42015-08-25 13:17:39 -04002273 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002274 {
Jamie Madillf6113162015-05-07 11:49:21 -04002275 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002276 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002277 }
2278
Jamie Madillc349ec02015-08-21 16:53:12 -04002279 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002280 }
2281 }
2282
Jamie Madill48ef11b2016-04-27 15:21:52 -04002283 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002284 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002285 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04002286 ASSERT(attribute.location != -1);
2287 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002288
Jamie Madill63805b42015-08-25 13:17:39 -04002289 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002290 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002291 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002292 }
2293 }
2294
Geoff Lang7dd2e102014-11-10 15:19:26 -05002295 return true;
2296}
2297
Martin Radev4c4c8e72016-08-04 12:25:34 +03002298bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2299 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2300 const std::string &errorMessage,
2301 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002302{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002303 GLuint blockCount = 0;
2304 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002305 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002306 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002307 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002308 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002309 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002310 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002311 return false;
2312 }
2313 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002314 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002315 return true;
2316}
Jamie Madille473dee2015-08-18 14:49:01 -04002317
Martin Radev4c4c8e72016-08-04 12:25:34 +03002318bool Program::validateVertexAndFragmentInterfaceBlocks(
2319 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2320 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2321 InfoLog &infoLog) const
2322{
2323 // Check that interface blocks defined in the vertex and fragment shaders are identical
2324 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2325 UniformBlockMap linkedUniformBlocks;
2326
2327 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2328 {
2329 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2330 }
2331
Jamie Madille473dee2015-08-18 14:49:01 -04002332 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002333 {
Jamie Madille473dee2015-08-18 14:49:01 -04002334 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002335 if (entry != linkedUniformBlocks.end())
2336 {
2337 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2338 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2339 {
2340 return false;
2341 }
2342 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002343 }
2344 return true;
2345}
Jamie Madille473dee2015-08-18 14:49:01 -04002346
Martin Radev4c4c8e72016-08-04 12:25:34 +03002347bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2348{
2349 if (mState.mAttachedComputeShader)
2350 {
2351 const Shader &computeShader = *mState.mAttachedComputeShader;
2352 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2353
2354 if (!validateUniformBlocksCount(
2355 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2356 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2357 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002358 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002359 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002360 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002361 return true;
2362 }
2363
2364 const Shader &vertexShader = *mState.mAttachedVertexShader;
2365 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2366
2367 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2368 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2369
2370 if (!validateUniformBlocksCount(
2371 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2372 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2373 {
2374 return false;
2375 }
2376 if (!validateUniformBlocksCount(
2377 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2378 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2379 infoLog))
2380 {
2381
2382 return false;
2383 }
2384 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2385 infoLog))
2386 {
2387 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002388 }
Jamie Madille473dee2015-08-18 14:49:01 -04002389
Geoff Lang7dd2e102014-11-10 15:19:26 -05002390 return true;
2391}
2392
Jamie Madilla2c74982016-12-12 11:20:42 -05002393bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002394 const sh::InterfaceBlock &vertexInterfaceBlock,
2395 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002396{
2397 const char* blockName = vertexInterfaceBlock.name.c_str();
2398 // validate blocks for the same member types
2399 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2400 {
Jamie Madillf6113162015-05-07 11:49:21 -04002401 infoLog << "Types for interface block '" << blockName
2402 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002403 return false;
2404 }
2405 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2406 {
Jamie Madillf6113162015-05-07 11:49:21 -04002407 infoLog << "Array sizes differ for interface block '" << blockName
2408 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002409 return false;
2410 }
2411 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2412 {
Jamie Madillf6113162015-05-07 11:49:21 -04002413 infoLog << "Layout qualifiers differ for interface block '" << blockName
2414 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002415 return false;
2416 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002417 const unsigned int numBlockMembers =
2418 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002419 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2420 {
2421 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2422 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2423 if (vertexMember.name != fragmentMember.name)
2424 {
Jamie Madillf6113162015-05-07 11:49:21 -04002425 infoLog << "Name mismatch for field " << blockMemberIndex
2426 << " of interface block '" << blockName
2427 << "': (in vertex: '" << vertexMember.name
2428 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002429 return false;
2430 }
2431 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2432 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2433 {
2434 return false;
2435 }
2436 }
2437 return true;
2438}
2439
2440bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2441 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2442{
2443 if (vertexVariable.type != fragmentVariable.type)
2444 {
Jamie Madillf6113162015-05-07 11:49:21 -04002445 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002446 return false;
2447 }
2448 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2449 {
Jamie Madillf6113162015-05-07 11:49:21 -04002450 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002451 return false;
2452 }
2453 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2454 {
Jamie Madillf6113162015-05-07 11:49:21 -04002455 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002456 return false;
2457 }
2458
2459 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2460 {
Jamie Madillf6113162015-05-07 11:49:21 -04002461 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002462 return false;
2463 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002464 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002465 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2466 {
2467 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2468 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2469
2470 if (vertexMember.name != fragmentMember.name)
2471 {
Jamie Madillf6113162015-05-07 11:49:21 -04002472 infoLog << "Name mismatch for field '" << memberIndex
2473 << "' of " << variableName
2474 << ": (in vertex: '" << vertexMember.name
2475 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002476 return false;
2477 }
2478
2479 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2480 vertexMember.name + "'";
2481
2482 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2483 {
2484 return false;
2485 }
2486 }
2487
2488 return true;
2489}
2490
Olli Etuaho547cbd42017-02-27 11:54:00 +02002491// GLSL ES Spec 3.00.3, section 4.3.5.
Geoff Lang7dd2e102014-11-10 15:19:26 -05002492bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2493{
Cooper Partin1acf4382015-06-12 12:38:57 -07002494#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
2495 const bool validatePrecision = true;
2496#else
2497 const bool validatePrecision = false;
2498#endif
2499
2500 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002501 {
2502 return false;
2503 }
2504
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002505 // GLSL ES Spec 3.10.4, section 4.4.5.
Olli Etuaho547cbd42017-02-27 11:54:00 +02002506 if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
2507 vertexUniform.binding != fragmentUniform.binding)
2508 {
2509 infoLog << "Binding layout qualifiers for " << uniformName
2510 << " differ between vertex and fragment shaders.";
2511 return false;
2512 }
2513
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002514 // GLSL ES Spec 3.10.4, section 9.2.1.
2515 if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
2516 vertexUniform.location != fragmentUniform.location)
2517 {
2518 infoLog << "Location layout qualifiers for " << uniformName
2519 << " differ between vertex and fragment shaders.";
2520 return false;
2521 }
2522
Geoff Lang7dd2e102014-11-10 15:19:26 -05002523 return true;
2524}
2525
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002526bool Program::linkValidateVaryings(InfoLog &infoLog,
2527 const std::string &varyingName,
2528 const sh::Varying &vertexVarying,
2529 const sh::Varying &fragmentVarying,
2530 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002531{
2532 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2533 {
2534 return false;
2535 }
2536
Jamie Madille9cc4692015-02-19 16:00:13 -05002537 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002538 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002539 infoLog << "Interpolation types for " << varyingName
2540 << " differ between vertex and fragment shaders.";
2541 return false;
2542 }
2543
2544 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2545 {
2546 infoLog << "Invariance for " << varyingName
2547 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002548 return false;
2549 }
2550
2551 return true;
2552}
2553
Yuly Novikov817232e2017-02-22 18:36:10 -05002554bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
2555{
2556 const Shader *vertexShader = mState.mAttachedVertexShader;
2557 const Shader *fragmentShader = mState.mAttachedFragmentShader;
2558 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
2559 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
2560 int shaderVersion = vertexShader->getShaderVersion();
2561
2562 if (shaderVersion != 100)
2563 {
2564 // Only ESSL 1.0 has restrictions on matching input and output invariance
2565 return true;
2566 }
2567
2568 bool glPositionIsInvariant = false;
2569 bool glPointSizeIsInvariant = false;
2570 bool glFragCoordIsInvariant = false;
2571 bool glPointCoordIsInvariant = false;
2572
2573 for (const sh::Varying &varying : vertexVaryings)
2574 {
2575 if (!varying.isBuiltIn())
2576 {
2577 continue;
2578 }
2579 if (varying.name.compare("gl_Position") == 0)
2580 {
2581 glPositionIsInvariant = varying.isInvariant;
2582 }
2583 else if (varying.name.compare("gl_PointSize") == 0)
2584 {
2585 glPointSizeIsInvariant = varying.isInvariant;
2586 }
2587 }
2588
2589 for (const sh::Varying &varying : fragmentVaryings)
2590 {
2591 if (!varying.isBuiltIn())
2592 {
2593 continue;
2594 }
2595 if (varying.name.compare("gl_FragCoord") == 0)
2596 {
2597 glFragCoordIsInvariant = varying.isInvariant;
2598 }
2599 else if (varying.name.compare("gl_PointCoord") == 0)
2600 {
2601 glPointCoordIsInvariant = varying.isInvariant;
2602 }
2603 }
2604
2605 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2606 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2607 // Not requiring invariance to match is supported by:
2608 // dEQP, WebGL CTS, Nexus 5X GLES
2609 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2610 {
2611 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2612 "declared invariant.";
2613 return false;
2614 }
2615 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2616 {
2617 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2618 "declared invariant.";
2619 return false;
2620 }
2621
2622 return true;
2623}
2624
Jamie Madillccdf74b2015-08-18 10:46:12 -04002625bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002626 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002627 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002628{
2629 size_t totalComponents = 0;
2630
Jamie Madillccdf74b2015-08-18 10:46:12 -04002631 std::set<std::string> uniqueNames;
2632
Jamie Madill48ef11b2016-04-27 15:21:52 -04002633 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002634 {
2635 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002636 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002637 {
Jamie Madill192745a2016-12-22 15:58:21 -05002638 const sh::Varying *varying = ref.second.get();
2639
Jamie Madillccdf74b2015-08-18 10:46:12 -04002640 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002641 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002642 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002643 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002644 infoLog << "Two transform feedback varyings specify the same output variable ("
2645 << tfVaryingName << ").";
2646 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002647 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002648 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002649
Geoff Lang1a683462015-09-29 15:09:59 -04002650 if (varying->isArray())
2651 {
2652 infoLog << "Capture of arrays is undefined and not supported.";
2653 return false;
2654 }
2655
Jamie Madillccdf74b2015-08-18 10:46:12 -04002656 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002657 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002658 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002659 componentCount > caps.maxTransformFeedbackSeparateComponents)
2660 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002661 infoLog << "Transform feedback varying's " << varying->name << " components ("
2662 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002663 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002664 return false;
2665 }
2666
2667 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002668 found = true;
2669 break;
2670 }
2671 }
2672
Jamie Madill89bb70e2015-08-31 14:18:39 -04002673 if (tfVaryingName.find('[') != std::string::npos)
2674 {
Geoff Lang1a683462015-09-29 15:09:59 -04002675 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002676 return false;
2677 }
2678
Geoff Lang7dd2e102014-11-10 15:19:26 -05002679 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2680 ASSERT(found);
2681 }
2682
Jamie Madill48ef11b2016-04-27 15:21:52 -04002683 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002684 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002685 {
Jamie Madillf6113162015-05-07 11:49:21 -04002686 infoLog << "Transform feedback varying total components (" << totalComponents
2687 << ") exceed the maximum interleaved components ("
2688 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002689 return false;
2690 }
2691
2692 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002693}
2694
Jamie Madill192745a2016-12-22 15:58:21 -05002695void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002696{
2697 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002698 mState.mTransformFeedbackVaryingVars.clear();
2699 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002700 {
Jamie Madill192745a2016-12-22 15:58:21 -05002701 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002702 {
Jamie Madill192745a2016-12-22 15:58:21 -05002703 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002704 if (tfVaryingName == varying->name)
2705 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002706 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002707 break;
2708 }
2709 }
2710 }
2711}
2712
Jamie Madill192745a2016-12-22 15:58:21 -05002713Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002714{
Jamie Madill192745a2016-12-22 15:58:21 -05002715 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002716
Jamie Madill48ef11b2016-04-27 15:21:52 -04002717 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002718 {
Jamie Madill192745a2016-12-22 15:58:21 -05002719 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002720 }
2721
Jamie Madill48ef11b2016-04-27 15:21:52 -04002722 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002723 {
Jamie Madill192745a2016-12-22 15:58:21 -05002724 merged[varying.name].fragment = &varying;
2725 }
2726
2727 return merged;
2728}
2729
2730std::vector<PackedVarying> Program::getPackedVaryings(
2731 const Program::MergedVaryings &mergedVaryings) const
2732{
2733 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2734 std::vector<PackedVarying> packedVaryings;
2735
2736 for (const auto &ref : mergedVaryings)
2737 {
2738 const sh::Varying *input = ref.second.vertex;
2739 const sh::Varying *output = ref.second.fragment;
2740
2741 // Only pack varyings that have a matched input or output, plus special builtins.
2742 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002743 {
Jamie Madill192745a2016-12-22 15:58:21 -05002744 // Will get the vertex shader interpolation by default.
2745 auto interpolation = ref.second.get()->interpolation;
2746
2747 // Interpolation qualifiers must match.
2748 if (output->isStruct())
2749 {
2750 ASSERT(!output->isArray());
2751 for (const auto &field : output->fields)
2752 {
2753 ASSERT(!field.isStruct() && !field.isArray());
2754 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2755 }
2756 }
2757 else
2758 {
2759 packedVaryings.push_back(PackedVarying(*output, interpolation));
2760 }
2761 continue;
2762 }
2763
2764 // Keep Transform FB varyings in the merged list always.
2765 if (!input)
2766 {
2767 continue;
2768 }
2769
2770 for (const std::string &tfVarying : tfVaryings)
2771 {
2772 if (tfVarying == input->name)
2773 {
2774 // Transform feedback for varying structs is underspecified.
2775 // See Khronos bug 9856.
2776 // TODO(jmadill): Figure out how to be spec-compliant here.
2777 if (!input->isStruct())
2778 {
2779 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2780 packedVaryings.back().vertexOnly = true;
2781 }
2782 break;
2783 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002784 }
2785 }
2786
Jamie Madill192745a2016-12-22 15:58:21 -05002787 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2788
2789 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002790}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002791
2792void Program::linkOutputVariables()
2793{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002794 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002795 ASSERT(fragmentShader != nullptr);
2796
2797 // Skip this step for GLES2 shaders.
2798 if (fragmentShader->getShaderVersion() == 100)
2799 return;
2800
Jamie Madilla0a9e122015-09-02 15:54:30 -04002801 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002802
2803 // TODO(jmadill): any caps validation here?
2804
2805 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2806 outputVariableIndex++)
2807 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002808 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002809
2810 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2811 if (outputVariable.isBuiltIn())
2812 continue;
2813
2814 // Since multiple output locations must be specified, use 0 for non-specified locations.
2815 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2816
2817 ASSERT(outputVariable.staticUse);
2818
2819 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2820 elementIndex++)
2821 {
2822 const int location = baseLocation + elementIndex;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002823 ASSERT(mState.mOutputVariables.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002824 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002825 mState.mOutputVariables[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002826 VariableLocation(outputVariable.name, element, outputVariableIndex);
2827 }
2828 }
2829}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002830
Jamie Madilla2c74982016-12-12 11:20:42 -05002831bool Program::flattenUniformsAndCheckCapsForShader(const Shader &shader,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002832 GLuint maxUniformComponents,
2833 GLuint maxTextureImageUnits,
2834 const std::string &componentsErrorMessage,
2835 const std::string &samplerErrorMessage,
2836 std::vector<LinkedUniform> &samplerUniforms,
2837 InfoLog &infoLog)
2838{
2839 VectorAndSamplerCount vasCount;
2840 for (const sh::Uniform &uniform : shader.getUniforms())
2841 {
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002842 vasCount += flattenUniform(uniform, &samplerUniforms);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002843 }
2844
2845 if (vasCount.vectorCount > maxUniformComponents)
2846 {
2847 infoLog << componentsErrorMessage << maxUniformComponents << ").";
2848 return false;
2849 }
2850
2851 if (vasCount.samplerCount > maxTextureImageUnits)
2852 {
2853 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
2854 return false;
2855 }
2856
2857 return true;
2858}
2859
Jamie Madill62d31cb2015-09-11 13:25:51 -04002860bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2861{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002862 std::vector<LinkedUniform> samplerUniforms;
2863
Martin Radev4c4c8e72016-08-04 12:25:34 +03002864 if (mState.mAttachedComputeShader)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002865 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002866 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002867
2868 // TODO (mradev): check whether we need finer-grained component counting
2869 if (!flattenUniformsAndCheckCapsForShader(
2870 *computeShader, caps.maxComputeUniformComponents / 4,
2871 caps.maxComputeTextureImageUnits,
2872 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
2873 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
2874 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002875 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002876 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002877 }
2878 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002879 else
Jamie Madill62d31cb2015-09-11 13:25:51 -04002880 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002881 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002882
Martin Radev4c4c8e72016-08-04 12:25:34 +03002883 if (!flattenUniformsAndCheckCapsForShader(
2884 *vertexShader, caps.maxVertexUniformVectors, caps.maxVertexTextureImageUnits,
2885 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
2886 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
2887 samplerUniforms, infoLog))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002888 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002889 return false;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002890 }
Jamie Madilla2c74982016-12-12 11:20:42 -05002891 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002892
Martin Radev4c4c8e72016-08-04 12:25:34 +03002893 if (!flattenUniformsAndCheckCapsForShader(
2894 *fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
2895 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
2896 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms,
2897 infoLog))
2898 {
2899 return false;
2900 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002901 }
2902
Jamie Madill48ef11b2016-04-27 15:21:52 -04002903 mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Jamie Madill62d31cb2015-09-11 13:25:51 -04002904 return true;
2905}
2906
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002907Program::VectorAndSamplerCount Program::flattenUniform(const sh::Uniform &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002908 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002909{
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002910 int location = uniform.location;
2911 VectorAndSamplerCount uniformVasCount = flattenUniformImpl(
2912 uniform, uniform.name, samplerUniforms, uniform.staticUse, uniform.binding, &location);
2913 if (uniform.staticUse)
2914 {
2915 return uniformVasCount;
2916 }
2917 return VectorAndSamplerCount();
2918}
2919
2920Program::VectorAndSamplerCount Program::flattenUniformImpl(
2921 const sh::ShaderVariable &uniform,
2922 const std::string &fullName,
2923 std::vector<LinkedUniform> *samplerUniforms,
2924 bool markStaticUse,
2925 int binding,
2926 int *location)
2927{
2928 ASSERT(location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002929 VectorAndSamplerCount vectorAndSamplerCount;
2930
2931 if (uniform.isStruct())
2932 {
2933 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2934 {
2935 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2936
2937 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2938 {
2939 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2940 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2941
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002942 vectorAndSamplerCount += flattenUniformImpl(field, fieldFullName, samplerUniforms,
2943 markStaticUse, -1, location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002944 }
2945 }
2946
2947 return vectorAndSamplerCount;
2948 }
2949
2950 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002951 bool isSampler = IsSamplerType(uniform.type);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002952 std::vector<gl::LinkedUniform> *uniformList = &mState.mUniforms;
2953 if (isSampler)
2954 {
2955 // Store sampler uniforms separately, so we'll append them to the end of the list.
2956 uniformList = samplerUniforms;
2957 }
2958 LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
2959 if (existingUniform)
2960 {
2961 if (binding != -1)
2962 {
2963 existingUniform->binding = binding;
2964 }
2965 if (*location != -1)
2966 {
2967 existingUniform->location = *location;
2968 }
2969 if (markStaticUse)
2970 {
2971 existingUniform->staticUse = true;
2972 }
2973 }
2974 else
Jamie Madill62d31cb2015-09-11 13:25:51 -04002975 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002976 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002977 binding, *location, -1,
2978 sh::BlockMemberInfo::getDefaultBlockInfo());
2979 linkedUniform.staticUse = markStaticUse;
2980 uniformList->push_back(linkedUniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002981 }
2982
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002983 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002984
2985 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2986 // Likewise, don't count "real" uniforms towards sampler count.
2987 vectorAndSamplerCount.vectorCount =
2988 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002989 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002990
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002991 if (*location != -1)
2992 {
2993 *location += elementCount;
2994 }
2995
Jamie Madill62d31cb2015-09-11 13:25:51 -04002996 return vectorAndSamplerCount;
2997}
2998
2999void Program::gatherInterfaceBlockInfo()
3000{
Martin Radev4c4c8e72016-08-04 12:25:34 +03003001 ASSERT(mState.mUniformBlocks.empty());
3002
3003 if (mState.mAttachedComputeShader)
3004 {
Jamie Madilla2c74982016-12-12 11:20:42 -05003005 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03003006
3007 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
3008 {
3009
3010 // Only 'packed' blocks are allowed to be considered inactive.
3011 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
3012 continue;
3013
Jamie Madilla2c74982016-12-12 11:20:42 -05003014 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03003015 {
3016 if (block.name == computeBlock.name)
3017 {
3018 block.computeStaticUse = computeBlock.staticUse;
3019 }
3020 }
3021
3022 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
3023 }
3024 return;
3025 }
3026
Jamie Madill62d31cb2015-09-11 13:25:51 -04003027 std::set<std::string> visitedList;
3028
Jamie Madilla2c74982016-12-12 11:20:42 -05003029 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04003030
Jamie Madill62d31cb2015-09-11 13:25:51 -04003031 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
3032 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03003033 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003034 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
3035 continue;
3036
3037 if (visitedList.count(vertexBlock.name) > 0)
3038 continue;
3039
3040 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
3041 visitedList.insert(vertexBlock.name);
3042 }
3043
Jamie Madilla2c74982016-12-12 11:20:42 -05003044 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04003045
3046 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
3047 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03003048 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003049 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
3050 continue;
3051
3052 if (visitedList.count(fragmentBlock.name) > 0)
3053 {
Jamie Madilla2c74982016-12-12 11:20:42 -05003054 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003055 {
3056 if (block.name == fragmentBlock.name)
3057 {
3058 block.fragmentStaticUse = fragmentBlock.staticUse;
3059 }
3060 }
3061
3062 continue;
3063 }
3064
3065 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
3066 visitedList.insert(fragmentBlock.name);
3067 }
3068}
3069
Jamie Madill4a3c2342015-10-08 12:58:45 -04003070template <typename VarT>
3071void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
3072 const std::string &prefix,
3073 int blockIndex)
3074{
3075 for (const VarT &field : fields)
3076 {
3077 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
3078
3079 if (field.isStruct())
3080 {
3081 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
3082 {
3083 const std::string uniformElementName =
3084 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
3085 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
3086 }
3087 }
3088 else
3089 {
3090 // If getBlockMemberInfo returns false, the uniform is optimized out.
3091 sh::BlockMemberInfo memberInfo;
3092 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
3093 {
3094 continue;
3095 }
3096
Olli Etuaho6ca2b652017-02-19 18:05:10 +00003097 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04003098 blockIndex, memberInfo);
3099
3100 // Since block uniforms have no location, we don't need to store them in the uniform
3101 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003102 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04003103 }
3104 }
3105}
3106
Jamie Madill62d31cb2015-09-11 13:25:51 -04003107void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
3108{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003109 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04003110 size_t blockSize = 0;
3111
3112 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08003113 std::stringstream blockNameStr;
3114 blockNameStr << interfaceBlock.name;
3115 if (interfaceBlock.arraySize > 0)
3116 {
3117 blockNameStr << "[0]";
3118 }
3119 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04003120 {
3121 return;
3122 }
3123
3124 // Track the first and last uniform index to determine the range of active uniforms in the
3125 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003126 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05003127 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04003128 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04003129
3130 std::vector<unsigned int> blockUniformIndexes;
3131 for (size_t blockUniformIndex = firstBlockUniformIndex;
3132 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
3133 {
3134 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
3135 }
3136
3137 if (interfaceBlock.arraySize > 0)
3138 {
3139 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
3140 {
3141 UniformBlock block(interfaceBlock.name, true, arrayElement);
3142 block.memberUniformIndexes = blockUniformIndexes;
3143
Martin Radev4c4c8e72016-08-04 12:25:34 +03003144 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003145 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03003146 case GL_VERTEX_SHADER:
3147 {
3148 block.vertexStaticUse = interfaceBlock.staticUse;
3149 break;
3150 }
3151 case GL_FRAGMENT_SHADER:
3152 {
3153 block.fragmentStaticUse = interfaceBlock.staticUse;
3154 break;
3155 }
3156 case GL_COMPUTE_SHADER:
3157 {
3158 block.computeStaticUse = interfaceBlock.staticUse;
3159 break;
3160 }
3161 default:
3162 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04003163 }
3164
Qin Jiajia0350a642016-11-01 17:01:51 +08003165 // Since all block elements in an array share the same active uniforms, they will all be
3166 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
3167 // here we will add every block element in the array.
3168 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04003169 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003170 }
3171 }
3172 else
3173 {
3174 UniformBlock block(interfaceBlock.name, false, 0);
3175 block.memberUniformIndexes = blockUniformIndexes;
3176
Martin Radev4c4c8e72016-08-04 12:25:34 +03003177 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003178 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03003179 case GL_VERTEX_SHADER:
3180 {
3181 block.vertexStaticUse = interfaceBlock.staticUse;
3182 break;
3183 }
3184 case GL_FRAGMENT_SHADER:
3185 {
3186 block.fragmentStaticUse = interfaceBlock.staticUse;
3187 break;
3188 }
3189 case GL_COMPUTE_SHADER:
3190 {
3191 block.computeStaticUse = interfaceBlock.staticUse;
3192 break;
3193 }
3194 default:
3195 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04003196 }
3197
Jamie Madill4a3c2342015-10-08 12:58:45 -04003198 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04003199 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003200 }
3201}
3202
Jamie Madille7d84322017-01-10 18:21:59 -05003203template <>
3204void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3205 const uint8_t *destPointer,
3206 GLsizei clampedCount,
3207 const GLint *v)
3208{
3209 // Invalidate the validation cache only if we modify the sampler data.
3210 if (mState.isSamplerUniformIndex(locationInfo.index) &&
3211 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
3212 {
3213 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3214 std::vector<GLuint> *boundTextureUnits =
3215 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
3216
3217 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
3218 mCachedValidateSamplersResult.reset();
3219 }
3220}
3221
3222template <typename T>
3223void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3224 const uint8_t *destPointer,
3225 GLsizei clampedCount,
3226 const T *v)
3227{
3228}
3229
Jamie Madill62d31cb2015-09-11 13:25:51 -04003230template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003231GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003232{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003233 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3234 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003235 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
3236
Corentin Wallez15ac5342016-11-03 17:06:39 -04003237 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3238 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3239 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003240 GLsizei maxElementCount =
3241 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
3242
3243 GLsizei count = countIn;
3244 GLsizei clampedCount = count * vectorSize;
3245 if (clampedCount > maxElementCount)
3246 {
3247 clampedCount = maxElementCount;
3248 count = maxElementCount / vectorSize;
3249 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04003250
Jamie Madill62d31cb2015-09-11 13:25:51 -04003251 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
3252 {
3253 // Do a cast conversion for boolean types. From the spec:
3254 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
3255 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003256 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003257 {
3258 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
3259 }
3260 }
3261 else
3262 {
Jamie Madille7d84322017-01-10 18:21:59 -05003263 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003264 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003265 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003266
3267 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003268}
3269
3270template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003271GLsizei Program::setMatrixUniformInternal(GLint location,
3272 GLsizei count,
3273 GLboolean transpose,
3274 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003275{
3276 if (!transpose)
3277 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003278 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003279 }
3280
3281 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003282 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3283 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003284 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04003285
3286 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3287 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3288 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
3289 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
3290
3291 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003292 {
3293 size_t elementOffset = element * rows * cols;
3294
3295 for (size_t row = 0; row < rows; ++row)
3296 {
3297 for (size_t col = 0; col < cols; ++col)
3298 {
3299 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
3300 }
3301 }
3302 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003303
3304 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003305}
3306
3307template <typename DestT>
3308void Program::getUniformInternal(GLint location, DestT *dataOut) const
3309{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003310 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3311 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003312
3313 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
3314
3315 GLenum componentType = VariableComponentType(uniform.type);
3316 if (componentType == GLTypeToGLenum<DestT>::value)
3317 {
3318 memcpy(dataOut, srcPointer, uniform.getElementSize());
3319 return;
3320 }
3321
Corentin Wallez6596c462016-03-17 17:26:58 -04003322 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003323
3324 switch (componentType)
3325 {
3326 case GL_INT:
3327 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
3328 break;
3329 case GL_UNSIGNED_INT:
3330 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
3331 break;
3332 case GL_BOOL:
3333 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
3334 break;
3335 case GL_FLOAT:
3336 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
3337 break;
3338 default:
3339 UNREACHABLE();
3340 }
3341}
Jamie Madilla4595b82017-01-11 17:36:34 -05003342
3343bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3344{
3345 // Must be called after samplers are validated.
3346 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3347
3348 for (const auto &binding : mState.mSamplerBindings)
3349 {
3350 GLenum textureType = binding.textureType;
3351 for (const auto &unit : binding.boundTextureUnits)
3352 {
3353 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3354 if (programTextureID == textureID)
3355 {
3356 // TODO(jmadill): Check for appropriate overlap.
3357 return true;
3358 }
3359 }
3360 }
3361
3362 return false;
3363}
3364
Jamie Madilla2c74982016-12-12 11:20:42 -05003365} // namespace gl