blob: 6d18f2a31c37aa533663b5d4070ee1ae251938b3 [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 Madill20e005b2017-04-07 14:19:22 -040014#include "common/bitset_utils.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"
Olli Etuahob78707c2017-03-09 15:03:11 +000028#include "libANGLE/UniformLinker.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050029
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030namespace gl
31{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000032
Geoff Lang7dd2e102014-11-10 15:19:26 -050033namespace
34{
35
Jamie Madill62d31cb2015-09-11 13:25:51 -040036void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
37{
38 stream->writeInt(var.type);
39 stream->writeInt(var.precision);
40 stream->writeString(var.name);
41 stream->writeString(var.mappedName);
42 stream->writeInt(var.arraySize);
43 stream->writeInt(var.staticUse);
44 stream->writeString(var.structName);
45 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050046}
47
Jamie Madill62d31cb2015-09-11 13:25:51 -040048void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
49{
50 var->type = stream->readInt<GLenum>();
51 var->precision = stream->readInt<GLenum>();
52 var->name = stream->readString();
53 var->mappedName = stream->readString();
54 var->arraySize = stream->readInt<unsigned int>();
55 var->staticUse = stream->readBool();
56 var->structName = stream->readString();
57}
58
Jamie Madill62d31cb2015-09-11 13:25:51 -040059// This simplified cast function doesn't need to worry about advanced concepts like
60// depth range values, or casting to bool.
61template <typename DestT, typename SrcT>
62DestT UniformStateQueryCast(SrcT value);
63
64// From-Float-To-Integer Casts
65template <>
66GLint UniformStateQueryCast(GLfloat value)
67{
68 return clampCast<GLint>(roundf(value));
69}
70
71template <>
72GLuint UniformStateQueryCast(GLfloat value)
73{
74 return clampCast<GLuint>(roundf(value));
75}
76
77// From-Integer-to-Integer Casts
78template <>
79GLint UniformStateQueryCast(GLuint value)
80{
81 return clampCast<GLint>(value);
82}
83
84template <>
85GLuint UniformStateQueryCast(GLint value)
86{
87 return clampCast<GLuint>(value);
88}
89
90// From-Boolean-to-Anything Casts
91template <>
92GLfloat UniformStateQueryCast(GLboolean value)
93{
94 return (value == GL_TRUE ? 1.0f : 0.0f);
95}
96
97template <>
98GLint UniformStateQueryCast(GLboolean value)
99{
100 return (value == GL_TRUE ? 1 : 0);
101}
102
103template <>
104GLuint UniformStateQueryCast(GLboolean value)
105{
106 return (value == GL_TRUE ? 1u : 0u);
107}
108
109// Default to static_cast
110template <typename DestT, typename SrcT>
111DestT UniformStateQueryCast(SrcT value)
112{
113 return static_cast<DestT>(value);
114}
115
116template <typename SrcT, typename DestT>
117void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
118{
119 for (int comp = 0; comp < components; ++comp)
120 {
121 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
122 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
123 size_t offset = comp * 4;
124 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
125 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
126 }
127}
128
Jamie Madill192745a2016-12-22 15:58:21 -0500129// true if varying x has a higher priority in packing than y
130bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
131{
jchen10a9042d32017-03-17 08:50:45 +0800132 // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent
133 // non-array shader variable 'vx' or 'vy' for actual comparison instead.
134 sh::ShaderVariable vx, vy;
135 const sh::ShaderVariable *px, *py;
136 if (x.isArrayElement())
137 {
138 vx = *x.varying;
139 vx.arraySize = 0;
140 px = &vx;
141 }
142 else
143 {
144 px = x.varying;
145 }
146
147 if (y.isArrayElement())
148 {
149 vy = *y.varying;
150 vy.arraySize = 0;
151 py = &vy;
152 }
153 else
154 {
155 py = y.varying;
156 }
157
158 return gl::CompareShaderVar(*px, *py);
Jamie Madill192745a2016-12-22 15:58:21 -0500159}
160
jchen1015015f72017-03-16 13:54:21 +0800161template <typename VarT>
162GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
163{
164 size_t subscript = GL_INVALID_INDEX;
165 std::string baseName = ParseResourceName(name, &subscript);
166
167 // The app is not allowed to specify array indices other than 0 for arrays of basic types
168 if (subscript != 0 && subscript != GL_INVALID_INDEX)
169 {
170 return GL_INVALID_INDEX;
171 }
172
173 for (size_t index = 0; index < list.size(); index++)
174 {
175 const VarT &resource = list[index];
176 if (resource.name == baseName)
177 {
178 if (resource.isArray() || subscript == GL_INVALID_INDEX)
179 {
180 return static_cast<GLuint>(index);
181 }
182 }
183 }
184
185 return GL_INVALID_INDEX;
186}
187
jchen10fd7c3b52017-03-21 15:36:03 +0800188void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
189{
190 ASSERT(bufSize > 0);
191 strncpy(buffer, string.c_str(), bufSize);
192 buffer[bufSize - 1] = '\0';
193
194 if (length)
195 {
196 *length = static_cast<GLsizei>(strlen(buffer));
197 }
198}
199
jchen10a9042d32017-03-17 08:50:45 +0800200bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
201{
202 size_t subscript = GL_INVALID_INDEX;
203 std::string baseName = ParseResourceName(name, &subscript);
204 for (auto it = nameSet.begin(); it != nameSet.end(); ++it)
205 {
206 size_t arrayIndex = GL_INVALID_INDEX;
207 std::string arrayName = ParseResourceName(*it, &arrayIndex);
208 if (baseName == arrayName && (subscript == GL_INVALID_INDEX ||
209 arrayIndex == GL_INVALID_INDEX || subscript == arrayIndex))
210 {
211 return true;
212 }
213 }
214 return false;
215}
216
Jamie Madill62d31cb2015-09-11 13:25:51 -0400217} // anonymous namespace
218
Jamie Madill4a3c2342015-10-08 12:58:45 -0400219const char *const g_fakepath = "C:\\fakepath";
220
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400221InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000222{
223}
224
225InfoLog::~InfoLog()
226{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000227}
228
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400229size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000230{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400231 const std::string &logString = mStream.str();
232 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000233}
234
Geoff Lange1a27752015-10-05 13:16:04 -0400235void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000236{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400237 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000238
239 if (bufSize > 0)
240 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400241 const std::string str(mStream.str());
242
243 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000244 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400245 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
246 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000247 }
248
249 infoLog[index] = '\0';
250 }
251
252 if (length)
253 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400254 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000255 }
256}
257
258// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300259// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000260// messages, so lets remove all occurrences of this fake file path from the log.
261void InfoLog::appendSanitized(const char *message)
262{
263 std::string msg(message);
264
265 size_t found;
266 do
267 {
268 found = msg.find(g_fakepath);
269 if (found != std::string::npos)
270 {
271 msg.erase(found, strlen(g_fakepath));
272 }
273 }
274 while (found != std::string::npos);
275
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400276 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000277}
278
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000279void InfoLog::reset()
280{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000281}
282
Geoff Langd8605522016-04-13 10:19:12 -0400283VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000284{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500285}
286
Geoff Langd8605522016-04-13 10:19:12 -0400287VariableLocation::VariableLocation(const std::string &name,
288 unsigned int element,
289 unsigned int index)
290 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500291{
292}
293
Geoff Langd8605522016-04-13 10:19:12 -0400294void Program::Bindings::bindLocation(GLuint index, const std::string &name)
295{
296 mBindings[name] = index;
297}
298
299int Program::Bindings::getBinding(const std::string &name) const
300{
301 auto iter = mBindings.find(name);
302 return (iter != mBindings.end()) ? iter->second : -1;
303}
304
305Program::Bindings::const_iterator Program::Bindings::begin() const
306{
307 return mBindings.begin();
308}
309
310Program::Bindings::const_iterator Program::Bindings::end() const
311{
312 return mBindings.end();
313}
314
Jamie Madill48ef11b2016-04-27 15:21:52 -0400315ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500316 : mLabel(),
317 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400318 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300319 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500320 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madille7d84322017-01-10 18:21:59 -0500321 mSamplerUniformRange(0, 0),
Geoff Langc5629752015-12-07 16:29:04 -0500322 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400323{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300324 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400325}
326
Jamie Madill48ef11b2016-04-27 15:21:52 -0400327ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400328{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500329 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400330}
331
Jamie Madill48ef11b2016-04-27 15:21:52 -0400332const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500333{
334 return mLabel;
335}
336
Jamie Madill48ef11b2016-04-27 15:21:52 -0400337GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400338{
339 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +0800340 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400341
342 for (size_t location = 0; location < mUniformLocations.size(); ++location)
343 {
344 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400345 if (!uniformLocation.used)
346 {
347 continue;
348 }
349
350 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400351
352 if (uniform.name == baseName)
353 {
Geoff Langd8605522016-04-13 10:19:12 -0400354 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400355 {
Geoff Langd8605522016-04-13 10:19:12 -0400356 if (uniformLocation.element == subscript ||
357 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
358 {
359 return static_cast<GLint>(location);
360 }
361 }
362 else
363 {
364 if (subscript == GL_INVALID_INDEX)
365 {
366 return static_cast<GLint>(location);
367 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400368 }
369 }
370 }
371
372 return -1;
373}
374
Jamie Madille7d84322017-01-10 18:21:59 -0500375GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400376{
jchen1015015f72017-03-16 13:54:21 +0800377 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400378}
379
Jamie Madille7d84322017-01-10 18:21:59 -0500380GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
381{
382 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
383 return mUniformLocations[location].index;
384}
385
386Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
387{
388 GLuint index = getUniformIndexFromLocation(location);
389 if (!isSamplerUniformIndex(index))
390 {
391 return Optional<GLuint>::Invalid();
392 }
393
394 return getSamplerIndexFromUniformIndex(index);
395}
396
397bool ProgramState::isSamplerUniformIndex(GLuint index) const
398{
Jamie Madill982f6e02017-06-07 14:33:04 -0400399 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500400}
401
402GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
403{
404 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400405 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500406}
407
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500408Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400409 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400410 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500411 mLinked(false),
412 mDeleteStatus(false),
413 mRefCount(0),
414 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500415 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500416{
417 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000418
419 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500420 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421}
422
423Program::~Program()
424{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500425 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
426 !mState.mAttachedComputeShader);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500427 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428}
429
Jamie Madill6c1f6712017-02-14 19:08:04 -0500430void Program::destroy(const Context *context)
431{
432 if (mState.mAttachedVertexShader != nullptr)
433 {
434 mState.mAttachedVertexShader->release(context);
435 mState.mAttachedVertexShader = nullptr;
436 }
437
438 if (mState.mAttachedFragmentShader != nullptr)
439 {
440 mState.mAttachedFragmentShader->release(context);
441 mState.mAttachedFragmentShader = nullptr;
442 }
443
444 if (mState.mAttachedComputeShader != nullptr)
445 {
446 mState.mAttachedComputeShader->release(context);
447 mState.mAttachedComputeShader = nullptr;
448 }
449
Jamie Madillc564c072017-06-01 12:45:42 -0400450 mProgram->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500451}
452
Geoff Lang70d0f492015-12-10 17:45:46 -0500453void Program::setLabel(const std::string &label)
454{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400455 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500456}
457
458const std::string &Program::getLabel() const
459{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400460 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500461}
462
Jamie Madillef300b12016-10-07 15:12:09 -0400463void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300465 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300467 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468 {
Jamie Madillef300b12016-10-07 15:12:09 -0400469 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300470 mState.mAttachedVertexShader = shader;
471 mState.mAttachedVertexShader->addRef();
472 break;
473 }
474 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 {
Jamie Madillef300b12016-10-07 15:12:09 -0400476 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300477 mState.mAttachedFragmentShader = shader;
478 mState.mAttachedFragmentShader->addRef();
479 break;
480 }
481 case GL_COMPUTE_SHADER:
482 {
Jamie Madillef300b12016-10-07 15:12:09 -0400483 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300484 mState.mAttachedComputeShader = shader;
485 mState.mAttachedComputeShader->addRef();
486 break;
487 }
488 default:
489 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491}
492
Jamie Madillc1d770e2017-04-13 17:31:24 -0400493void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300495 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300497 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000498 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400499 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500500 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300501 mState.mAttachedVertexShader = nullptr;
502 break;
503 }
504 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400506 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500507 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300508 mState.mAttachedFragmentShader = nullptr;
509 break;
510 }
511 case GL_COMPUTE_SHADER:
512 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400513 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500514 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300515 mState.mAttachedComputeShader = nullptr;
516 break;
517 }
518 default:
519 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521}
522
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000523int Program::getAttachedShadersCount() const
524{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300525 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
526 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000527}
528
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529void Program::bindAttributeLocation(GLuint index, const char *name)
530{
Geoff Langd8605522016-04-13 10:19:12 -0400531 mAttributeBindings.bindLocation(index, name);
532}
533
534void Program::bindUniformLocation(GLuint index, const char *name)
535{
536 // Bind the base uniform name only since array indices other than 0 cannot be bound
jchen1015015f72017-03-16 13:54:21 +0800537 mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538}
539
Sami Väisänen46eaa942016-06-29 10:26:37 +0300540void Program::bindFragmentInputLocation(GLint index, const char *name)
541{
542 mFragmentInputBindings.bindLocation(index, name);
543}
544
Jamie Madillbd044ed2017-06-05 12:59:21 -0400545BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300546{
547 BindingInfo ret;
548 ret.type = GL_NONE;
549 ret.valid = false;
550
Jamie Madillbd044ed2017-06-05 12:59:21 -0400551 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300552 ASSERT(fragmentShader);
553
554 // Find the actual fragment shader varying we're interested in
Jamie Madillbd044ed2017-06-05 12:59:21 -0400555 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300556
557 for (const auto &binding : mFragmentInputBindings)
558 {
559 if (binding.second != static_cast<GLuint>(index))
560 continue;
561
562 ret.valid = true;
563
564 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400565 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300566
567 for (const auto &in : inputs)
568 {
569 if (in.name == originalName)
570 {
571 if (in.isArray())
572 {
573 // The client wants to bind either "name" or "name[0]".
574 // GL ES 3.1 spec refers to active array names with language such as:
575 // "if the string identifies the base name of an active array, where the
576 // string would exactly match the name of the variable if the suffix "[0]"
577 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400578 if (arrayIndex == GL_INVALID_INDEX)
579 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300580
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400581 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300582 }
583 else
584 {
585 ret.name = in.mappedName;
586 }
587 ret.type = in.type;
588 return ret;
589 }
590 }
591 }
592
593 return ret;
594}
595
Jamie Madillbd044ed2017-06-05 12:59:21 -0400596void Program::pathFragmentInputGen(const Context *context,
597 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300598 GLenum genMode,
599 GLint components,
600 const GLfloat *coeffs)
601{
602 // If the location is -1 then the command is silently ignored
603 if (index == -1)
604 return;
605
Jamie Madillbd044ed2017-06-05 12:59:21 -0400606 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300607
608 // If the input doesn't exist then then the command is silently ignored
609 // This could happen through optimization for example, the shader translator
610 // decides that a variable is not actually being used and optimizes it away.
611 if (binding.name.empty())
612 return;
613
614 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
615}
616
Martin Radev4c4c8e72016-08-04 12:25:34 +0300617// The attached shaders are checked for linking errors by matching up their variables.
618// Uniform, input and output variables get collected.
619// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500620Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000621{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500622 const auto &data = context->getContextState();
623
Jamie Madill6c1f6712017-02-14 19:08:04 -0500624 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000625
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000626 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000627 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000628
Martin Radev4c4c8e72016-08-04 12:25:34 +0300629 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500630
Jamie Madill192745a2016-12-22 15:58:21 -0500631 auto vertexShader = mState.mAttachedVertexShader;
632 auto fragmentShader = mState.mAttachedFragmentShader;
633 auto computeShader = mState.mAttachedComputeShader;
634
635 bool isComputeShaderAttached = (computeShader != nullptr);
636 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300637 // Check whether we both have a compute and non-compute shaders attached.
638 // If there are of both types attached, then linking should fail.
639 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
640 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500641 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300642 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
643 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400644 }
645
Jamie Madill192745a2016-12-22 15:58:21 -0500646 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500647 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400648 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300649 {
650 mInfoLog << "Attached compute shader is not compiled.";
651 return NoError();
652 }
Jamie Madill192745a2016-12-22 15:58:21 -0500653 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300654
Jamie Madillbd044ed2017-06-05 12:59:21 -0400655 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300656
657 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
658 // If the work group size is not specified, a link time error should occur.
659 if (!mState.mComputeShaderLocalSize.isDeclared())
660 {
661 mInfoLog << "Work group size is not specified.";
662 return NoError();
663 }
664
Jamie Madillbd044ed2017-06-05 12:59:21 -0400665 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300666 {
667 return NoError();
668 }
669
Jamie Madillbd044ed2017-06-05 12:59:21 -0400670 if (!linkUniformBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300671 {
672 return NoError();
673 }
674
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500675 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
Jamie Madillc564c072017-06-01 12:45:42 -0400676 ANGLE_TRY_RESULT(mProgram->link(context, noPacking, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500677 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300678 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500679 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300680 }
681 }
682 else
683 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400684 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300685 {
686 return NoError();
687 }
Jamie Madill192745a2016-12-22 15:58:21 -0500688 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300689
Jamie Madillbd044ed2017-06-05 12:59:21 -0400690 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300691 {
692 return NoError();
693 }
Jamie Madill192745a2016-12-22 15:58:21 -0500694 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300695
Jamie Madillbd044ed2017-06-05 12:59:21 -0400696 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300697 {
698 mInfoLog << "Fragment shader version does not match vertex shader version.";
699 return NoError();
700 }
701
Jamie Madillbd044ed2017-06-05 12:59:21 -0400702 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300703 {
704 return NoError();
705 }
706
Jamie Madillbd044ed2017-06-05 12:59:21 -0400707 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300708 {
709 return NoError();
710 }
711
Jamie Madillbd044ed2017-06-05 12:59:21 -0400712 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300713 {
714 return NoError();
715 }
716
Jamie Madillbd044ed2017-06-05 12:59:21 -0400717 if (!linkUniformBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300718 {
719 return NoError();
720 }
721
Jamie Madillbd044ed2017-06-05 12:59:21 -0400722 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300723
jchen10a9042d32017-03-17 08:50:45 +0800724 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300725 {
726 return NoError();
727 }
728
Jamie Madillbd044ed2017-06-05 12:59:21 -0400729 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300730
Jamie Madill192745a2016-12-22 15:58:21 -0500731 // Validate we can pack the varyings.
732 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
733
734 // Map the varyings to the register file
735 // In WebGL, we use a slightly different handling for packing variables.
736 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
737 : PackMode::ANGLE_RELAXED;
738 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
739 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
740 mState.getTransformFeedbackVaryingNames()))
741 {
742 return NoError();
743 }
744
Jamie Madillc564c072017-06-01 12:45:42 -0400745 ANGLE_TRY_RESULT(mProgram->link(context, varyingPacking, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500746 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300747 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500748 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300749 }
750
751 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500752 }
753
Olli Etuaho48fed632017-03-16 12:05:30 +0000754 setUniformValuesFromBindingQualifiers();
755
Jamie Madillbd044ed2017-06-05 12:59:21 -0400756 gatherInterfaceBlockInfo(context);
Jamie Madillccdf74b2015-08-18 10:46:12 -0400757
Martin Radev4c4c8e72016-08-04 12:25:34 +0300758 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000759}
760
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000761// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500762void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000763{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400764 mState.mAttributes.clear();
765 mState.mActiveAttribLocationsMask.reset();
jchen10a9042d32017-03-17 08:50:45 +0800766 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400767 mState.mUniforms.clear();
768 mState.mUniformLocations.clear();
769 mState.mUniformBlocks.clear();
770 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800771 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -0400772 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -0400773 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300774 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500775 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500776
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777 mValidated = false;
778
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000779 mLinked = false;
780}
781
Geoff Lange1a27752015-10-05 13:16:04 -0400782bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000783{
784 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785}
786
Jamie Madilla2c74982016-12-12 11:20:42 -0500787Error Program::loadBinary(const Context *context,
788 GLenum binaryFormat,
789 const void *binary,
790 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000791{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500792 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000793
Geoff Lang7dd2e102014-11-10 15:19:26 -0500794#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800795 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500796#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400797 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
798 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000799 {
Jamie Madillf6113162015-05-07 11:49:21 -0400800 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800801 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500802 }
803
Geoff Langc46cc2f2015-10-01 17:16:20 -0400804 BinaryInputStream stream(binary, length);
805
Jamie Madilla2c74982016-12-12 11:20:42 -0500806 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
807 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
808 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
809 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500810 {
Jamie Madillf6113162015-05-07 11:49:21 -0400811 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800812 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500813 }
814
Jamie Madilla2c74982016-12-12 11:20:42 -0500815 int majorVersion = stream.readInt<int>();
816 int minorVersion = stream.readInt<int>();
817 if (majorVersion != context->getClientMajorVersion() ||
818 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500819 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500820 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800821 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500822 }
823
Martin Radev4c4c8e72016-08-04 12:25:34 +0300824 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
825 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
826 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
827
Jamie Madill63805b42015-08-25 13:17:39 -0400828 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
829 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400830 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500831
Jamie Madill3da79b72015-04-27 11:09:17 -0400832 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400833 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400834 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
835 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400836 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400837 LoadShaderVar(&stream, &attrib);
838 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400839 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400840 }
841
Jamie Madill62d31cb2015-09-11 13:25:51 -0400842 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400843 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400844 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
845 {
846 LinkedUniform uniform;
847 LoadShaderVar(&stream, &uniform);
848
849 uniform.blockIndex = stream.readInt<int>();
850 uniform.blockInfo.offset = stream.readInt<int>();
851 uniform.blockInfo.arrayStride = stream.readInt<int>();
852 uniform.blockInfo.matrixStride = stream.readInt<int>();
853 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
854
Jamie Madill48ef11b2016-04-27 15:21:52 -0400855 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400856 }
857
858 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400859 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400860 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
861 uniformIndexIndex++)
862 {
863 VariableLocation variable;
864 stream.readString(&variable.name);
865 stream.readInt(&variable.element);
866 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400867 stream.readBool(&variable.used);
868 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400869
Jamie Madill48ef11b2016-04-27 15:21:52 -0400870 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400871 }
872
873 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400874 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400875 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
876 ++uniformBlockIndex)
877 {
878 UniformBlock uniformBlock;
879 stream.readString(&uniformBlock.name);
880 stream.readBool(&uniformBlock.isArray);
881 stream.readInt(&uniformBlock.arrayElement);
jchen10af713a22017-04-19 09:10:56 +0800882 stream.readInt(&uniformBlock.binding);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400883 stream.readInt(&uniformBlock.dataSize);
884 stream.readBool(&uniformBlock.vertexStaticUse);
885 stream.readBool(&uniformBlock.fragmentStaticUse);
886
887 unsigned int numMembers = stream.readInt<unsigned int>();
888 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
889 {
890 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
891 }
892
Jamie Madill48ef11b2016-04-27 15:21:52 -0400893 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400894 }
895
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500896 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
897 ++bindingIndex)
898 {
899 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
900 mState.mActiveUniformBlockBindings.set(bindingIndex,
901 mState.mUniformBlockBindings[bindingIndex] != 0);
902 }
903
Brandon Jones1048ea72015-10-06 15:34:52 -0700904 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
jchen10a9042d32017-03-17 08:50:45 +0800905 ASSERT(mState.mLinkedTransformFeedbackVaryings.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700906 for (unsigned int transformFeedbackVaryingIndex = 0;
907 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
908 ++transformFeedbackVaryingIndex)
909 {
910 sh::Varying varying;
911 stream.readInt(&varying.arraySize);
912 stream.readInt(&varying.type);
913 stream.readString(&varying.name);
914
jchen10a9042d32017-03-17 08:50:45 +0800915 GLuint arrayIndex = stream.readInt<GLuint>();
916
917 mState.mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
Brandon Jones1048ea72015-10-06 15:34:52 -0700918 }
919
Jamie Madill48ef11b2016-04-27 15:21:52 -0400920 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400921
jchen1015015f72017-03-16 13:54:21 +0800922 unsigned int outputCount = stream.readInt<unsigned int>();
923 ASSERT(mState.mOutputVariables.empty());
924 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
925 {
926 sh::OutputVariable output;
927 LoadShaderVar(&stream, &output);
928 output.location = stream.readInt<int>();
929 mState.mOutputVariables.push_back(output);
930 }
931
Jamie Madill80a6fc02015-08-21 16:53:16 -0400932 unsigned int outputVarCount = stream.readInt<unsigned int>();
933 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
934 {
935 int locationIndex = stream.readInt<int>();
936 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400937 stream.readInt(&locationData.element);
938 stream.readInt(&locationData.index);
939 stream.readString(&locationData.name);
jchen1015015f72017-03-16 13:54:21 +0800940 mState.mOutputLocations[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400941 }
942
Geoff Lange0cff192017-05-30 13:04:56 -0400943 unsigned int outputTypeCount = stream.readInt<unsigned int>();
944 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
945 {
946 mState.mOutputVariableTypes.push_back(stream.readInt<GLenum>());
947 }
Corentin Walleze7557742017-06-01 13:09:57 -0400948 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
949 "All bits of DrawBufferMask can be contained in an uint32_t");
950 mState.mActiveOutputVariables = stream.readInt<uint32_t>();
Geoff Lange0cff192017-05-30 13:04:56 -0400951
Jamie Madill982f6e02017-06-07 14:33:04 -0400952 unsigned int start = 0;
953 unsigned int end = 0;
954 stream.readInt(&start);
955 stream.readInt(&end);
956 mState.mSamplerUniformRange = RangeUI(start, end);
Jamie Madille7d84322017-01-10 18:21:59 -0500957
958 unsigned int samplerCount = stream.readInt<unsigned int>();
959 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
960 {
961 GLenum textureType = stream.readInt<GLenum>();
962 size_t bindingCount = stream.readInt<size_t>();
963 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
964 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400965
Jamie Madillc564c072017-06-01 12:45:42 -0400966 ANGLE_TRY_RESULT(mProgram->load(context, mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000967
Jamie Madillb0a838b2016-11-13 20:02:12 -0500968 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500969#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500970}
971
Jamie Madilla2c74982016-12-12 11:20:42 -0500972Error Program::saveBinary(const Context *context,
973 GLenum *binaryFormat,
974 void *binary,
975 GLsizei bufSize,
976 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500977{
978 if (binaryFormat)
979 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400980 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500981 }
982
983 BinaryOutputStream stream;
984
Geoff Lang7dd2e102014-11-10 15:19:26 -0500985 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
986
Jamie Madilla2c74982016-12-12 11:20:42 -0500987 // nullptr context is supported when computing binary length.
988 if (context)
989 {
990 stream.writeInt(context->getClientVersion().major);
991 stream.writeInt(context->getClientVersion().minor);
992 }
993 else
994 {
995 stream.writeInt(2);
996 stream.writeInt(0);
997 }
998
Martin Radev4c4c8e72016-08-04 12:25:34 +0300999 stream.writeInt(mState.mComputeShaderLocalSize[0]);
1000 stream.writeInt(mState.mComputeShaderLocalSize[1]);
1001 stream.writeInt(mState.mComputeShaderLocalSize[2]);
1002
Jamie Madill48ef11b2016-04-27 15:21:52 -04001003 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001004
Jamie Madill48ef11b2016-04-27 15:21:52 -04001005 stream.writeInt(mState.mAttributes.size());
1006 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -04001007 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001008 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -04001009 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001010 }
1011
Jamie Madill48ef11b2016-04-27 15:21:52 -04001012 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001013 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001014 {
1015 WriteShaderVar(&stream, uniform);
1016
1017 // FIXME: referenced
1018
1019 stream.writeInt(uniform.blockIndex);
1020 stream.writeInt(uniform.blockInfo.offset);
1021 stream.writeInt(uniform.blockInfo.arrayStride);
1022 stream.writeInt(uniform.blockInfo.matrixStride);
1023 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
1024 }
1025
Jamie Madill48ef11b2016-04-27 15:21:52 -04001026 stream.writeInt(mState.mUniformLocations.size());
1027 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001028 {
1029 stream.writeString(variable.name);
1030 stream.writeInt(variable.element);
1031 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -04001032 stream.writeInt(variable.used);
1033 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001034 }
1035
Jamie Madill48ef11b2016-04-27 15:21:52 -04001036 stream.writeInt(mState.mUniformBlocks.size());
1037 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001038 {
1039 stream.writeString(uniformBlock.name);
1040 stream.writeInt(uniformBlock.isArray);
1041 stream.writeInt(uniformBlock.arrayElement);
jchen10af713a22017-04-19 09:10:56 +08001042 stream.writeInt(uniformBlock.binding);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001043 stream.writeInt(uniformBlock.dataSize);
1044
1045 stream.writeInt(uniformBlock.vertexStaticUse);
1046 stream.writeInt(uniformBlock.fragmentStaticUse);
1047
1048 stream.writeInt(uniformBlock.memberUniformIndexes.size());
1049 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
1050 {
1051 stream.writeInt(memberUniformIndex);
1052 }
Jamie Madill3da79b72015-04-27 11:09:17 -04001053 }
1054
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001055 for (GLuint binding : mState.mUniformBlockBindings)
1056 {
1057 stream.writeInt(binding);
1058 }
1059
jchen10a9042d32017-03-17 08:50:45 +08001060 stream.writeInt(mState.mLinkedTransformFeedbackVaryings.size());
1061 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Brandon Jones1048ea72015-10-06 15:34:52 -07001062 {
jchen10a9042d32017-03-17 08:50:45 +08001063 stream.writeInt(var.arraySize);
1064 stream.writeInt(var.type);
1065 stream.writeString(var.name);
1066
1067 stream.writeIntOrNegOne(var.arrayIndex);
Brandon Jones1048ea72015-10-06 15:34:52 -07001068 }
1069
Jamie Madill48ef11b2016-04-27 15:21:52 -04001070 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001071
Jamie Madill48ef11b2016-04-27 15:21:52 -04001072 stream.writeInt(mState.mOutputVariables.size());
jchen1015015f72017-03-16 13:54:21 +08001073 for (const sh::OutputVariable &output : mState.mOutputVariables)
1074 {
1075 WriteShaderVar(&stream, output);
1076 stream.writeInt(output.location);
1077 }
1078
1079 stream.writeInt(mState.mOutputLocations.size());
1080 for (const auto &outputPair : mState.mOutputLocations)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001081 {
1082 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001083 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001084 stream.writeInt(outputPair.second.index);
1085 stream.writeString(outputPair.second.name);
1086 }
1087
Geoff Lange0cff192017-05-30 13:04:56 -04001088 stream.writeInt(mState.mOutputVariableTypes.size());
1089 for (const auto &outputVariableType : mState.mOutputVariableTypes)
1090 {
1091 stream.writeInt(outputVariableType);
1092 }
Corentin Walleze7557742017-06-01 13:09:57 -04001093 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
1094 "All bits of DrawBufferMask can be contained in an uint32_t");
1095 stream.writeInt(static_cast<uint32_t>(mState.mActiveOutputVariables.to_ulong()));
Geoff Lange0cff192017-05-30 13:04:56 -04001096
Jamie Madill982f6e02017-06-07 14:33:04 -04001097 stream.writeInt(mState.mSamplerUniformRange.low());
1098 stream.writeInt(mState.mSamplerUniformRange.high());
Jamie Madille7d84322017-01-10 18:21:59 -05001099
1100 stream.writeInt(mState.mSamplerBindings.size());
1101 for (const auto &samplerBinding : mState.mSamplerBindings)
1102 {
1103 stream.writeInt(samplerBinding.textureType);
1104 stream.writeInt(samplerBinding.boundTextureUnits.size());
1105 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001106
Jamie Madilla2c74982016-12-12 11:20:42 -05001107 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001108
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001109 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001110 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001111
1112 if (streamLength > bufSize)
1113 {
1114 if (length)
1115 {
1116 *length = 0;
1117 }
1118
1119 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1120 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1121 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001122 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001123 }
1124
1125 if (binary)
1126 {
1127 char *ptr = reinterpret_cast<char*>(binary);
1128
Jamie Madill48ef11b2016-04-27 15:21:52 -04001129 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130 ptr += streamLength;
1131
1132 ASSERT(ptr - streamLength == binary);
1133 }
1134
1135 if (length)
1136 {
1137 *length = streamLength;
1138 }
1139
He Yunchaoacd18982017-01-04 10:46:42 +08001140 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001141}
1142
1143GLint Program::getBinaryLength() const
1144{
1145 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001146 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001147 if (error.isError())
1148 {
1149 return 0;
1150 }
1151
1152 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001153}
1154
Geoff Langc5629752015-12-07 16:29:04 -05001155void Program::setBinaryRetrievableHint(bool retrievable)
1156{
1157 // TODO(jmadill) : replace with dirty bits
1158 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001159 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001160}
1161
1162bool Program::getBinaryRetrievableHint() const
1163{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001164 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001165}
1166
Yunchao He61afff12017-03-14 15:34:03 +08001167void Program::setSeparable(bool separable)
1168{
1169 // TODO(yunchao) : replace with dirty bits
1170 if (mState.mSeparable != separable)
1171 {
1172 mProgram->setSeparable(separable);
1173 mState.mSeparable = separable;
1174 }
1175}
1176
1177bool Program::isSeparable() const
1178{
1179 return mState.mSeparable;
1180}
1181
Jamie Madill6c1f6712017-02-14 19:08:04 -05001182void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001183{
1184 mRefCount--;
1185
1186 if (mRefCount == 0 && mDeleteStatus)
1187 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001188 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001189 }
1190}
1191
1192void Program::addRef()
1193{
1194 mRefCount++;
1195}
1196
1197unsigned int Program::getRefCount() const
1198{
1199 return mRefCount;
1200}
1201
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001202int Program::getInfoLogLength() const
1203{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001204 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001205}
1206
Geoff Lange1a27752015-10-05 13:16:04 -04001207void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001208{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001209 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001210}
1211
Geoff Lange1a27752015-10-05 13:16:04 -04001212void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001213{
1214 int total = 0;
1215
Martin Radev4c4c8e72016-08-04 12:25:34 +03001216 if (mState.mAttachedComputeShader)
1217 {
1218 if (total < maxCount)
1219 {
1220 shaders[total] = mState.mAttachedComputeShader->getHandle();
1221 total++;
1222 }
1223 }
1224
Jamie Madill48ef11b2016-04-27 15:21:52 -04001225 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001226 {
1227 if (total < maxCount)
1228 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001229 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001230 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001231 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001232 }
1233
Jamie Madill48ef11b2016-04-27 15:21:52 -04001234 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001235 {
1236 if (total < maxCount)
1237 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001238 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001239 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001240 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001241 }
1242
1243 if (count)
1244 {
1245 *count = total;
1246 }
1247}
1248
Geoff Lange1a27752015-10-05 13:16:04 -04001249GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001250{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001251 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001252 {
jchen1036e120e2017-03-14 14:53:58 +08001253 if (attribute.name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001254 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001255 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001256 }
1257 }
1258
Austin Kinrossb8af7232015-03-16 22:33:25 -07001259 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001260}
1261
Jamie Madill63805b42015-08-25 13:17:39 -04001262bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001263{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001264 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1265 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001266}
1267
jchen10fd7c3b52017-03-21 15:36:03 +08001268void Program::getActiveAttribute(GLuint index,
1269 GLsizei bufsize,
1270 GLsizei *length,
1271 GLint *size,
1272 GLenum *type,
1273 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001274{
Jamie Madillc349ec02015-08-21 16:53:12 -04001275 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001276 {
1277 if (bufsize > 0)
1278 {
1279 name[0] = '\0';
1280 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001281
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001282 if (length)
1283 {
1284 *length = 0;
1285 }
1286
1287 *type = GL_NONE;
1288 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001289 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001290 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001291
jchen1036e120e2017-03-14 14:53:58 +08001292 ASSERT(index < mState.mAttributes.size());
1293 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001294
1295 if (bufsize > 0)
1296 {
jchen10fd7c3b52017-03-21 15:36:03 +08001297 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001298 }
1299
1300 // Always a single 'type' instance
1301 *size = 1;
1302 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001303}
1304
Geoff Lange1a27752015-10-05 13:16:04 -04001305GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001306{
Jamie Madillc349ec02015-08-21 16:53:12 -04001307 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001308 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001309 return 0;
1310 }
1311
jchen1036e120e2017-03-14 14:53:58 +08001312 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001313}
1314
Geoff Lange1a27752015-10-05 13:16:04 -04001315GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001316{
Jamie Madillc349ec02015-08-21 16:53:12 -04001317 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001318 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001319 return 0;
1320 }
1321
1322 size_t maxLength = 0;
1323
Jamie Madill48ef11b2016-04-27 15:21:52 -04001324 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001325 {
jchen1036e120e2017-03-14 14:53:58 +08001326 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001327 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001328
Jamie Madillc349ec02015-08-21 16:53:12 -04001329 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001330}
1331
jchen1015015f72017-03-16 13:54:21 +08001332GLuint Program::getInputResourceIndex(const GLchar *name) const
1333{
1334 for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
1335 {
1336 const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
1337 if (attribute.name == name)
1338 {
1339 return attributeIndex;
1340 }
1341 }
1342 return GL_INVALID_INDEX;
1343}
1344
1345GLuint Program::getOutputResourceIndex(const GLchar *name) const
1346{
1347 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1348}
1349
jchen10fd7c3b52017-03-21 15:36:03 +08001350size_t Program::getOutputResourceCount() const
1351{
1352 return (mLinked ? mState.mOutputVariables.size() : 0);
1353}
1354
1355void Program::getInputResourceName(GLuint index,
1356 GLsizei bufSize,
1357 GLsizei *length,
1358 GLchar *name) const
1359{
1360 GLint size;
1361 GLenum type;
1362 getActiveAttribute(index, bufSize, length, &size, &type, name);
1363}
1364
1365void Program::getOutputResourceName(GLuint index,
1366 GLsizei bufSize,
1367 GLsizei *length,
1368 GLchar *name) const
1369{
1370 if (length)
1371 {
1372 *length = 0;
1373 }
1374
1375 if (!mLinked)
1376 {
1377 if (bufSize > 0)
1378 {
1379 name[0] = '\0';
1380 }
1381 return;
1382 }
1383 ASSERT(index < mState.mOutputVariables.size());
1384 const auto &output = mState.mOutputVariables[index];
1385
1386 if (bufSize > 0)
1387 {
1388 std::string nameWithArray = (output.isArray() ? output.name + "[0]" : output.name);
1389
1390 CopyStringToBuffer(name, nameWithArray, bufSize, length);
1391 }
1392}
1393
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394GLint Program::getFragDataLocation(const std::string &name) const
1395{
1396 std::string baseName(name);
1397 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
jchen1015015f72017-03-16 13:54:21 +08001398 for (auto outputPair : mState.mOutputLocations)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001399 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001400 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001401 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1402 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001403 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001404 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001405 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001406 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001407}
1408
Geoff Lange1a27752015-10-05 13:16:04 -04001409void Program::getActiveUniform(GLuint index,
1410 GLsizei bufsize,
1411 GLsizei *length,
1412 GLint *size,
1413 GLenum *type,
1414 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001415{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001417 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001418 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001419 ASSERT(index < mState.mUniforms.size());
1420 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001421
1422 if (bufsize > 0)
1423 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001424 std::string string = uniform.name;
1425 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001426 {
1427 string += "[0]";
1428 }
jchen10fd7c3b52017-03-21 15:36:03 +08001429 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001430 }
1431
Jamie Madill62d31cb2015-09-11 13:25:51 -04001432 *size = uniform.elementCount();
1433 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001434 }
1435 else
1436 {
1437 if (bufsize > 0)
1438 {
1439 name[0] = '\0';
1440 }
1441
1442 if (length)
1443 {
1444 *length = 0;
1445 }
1446
1447 *size = 0;
1448 *type = GL_NONE;
1449 }
1450}
1451
Geoff Lange1a27752015-10-05 13:16:04 -04001452GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001453{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001454 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001455 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001456 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001457 }
1458 else
1459 {
1460 return 0;
1461 }
1462}
1463
Geoff Lange1a27752015-10-05 13:16:04 -04001464GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001465{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001466 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467
1468 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001469 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001470 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001472 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001474 size_t length = uniform.name.length() + 1u;
1475 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001476 {
1477 length += 3; // Counting in "[0]".
1478 }
1479 maxLength = std::max(length, maxLength);
1480 }
1481 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001482 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001483
Jamie Madill62d31cb2015-09-11 13:25:51 -04001484 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1488{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001489 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001490 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001492 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001493 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1494 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1495 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1496 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1497 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1498 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1499 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1500 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1501 default:
1502 UNREACHABLE();
1503 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001504 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001505 return 0;
1506}
1507
1508bool Program::isValidUniformLocation(GLint location) const
1509{
Jamie Madille2e406c2016-06-02 13:04:10 -04001510 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001511 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1512 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001513}
1514
Jamie Madill62d31cb2015-09-11 13:25:51 -04001515const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001516{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001517 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001518 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001519}
1520
Jamie Madillac4e9c32017-01-13 14:07:12 -05001521const VariableLocation &Program::getUniformLocation(GLint location) const
1522{
1523 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1524 return mState.mUniformLocations[location];
1525}
1526
1527const std::vector<VariableLocation> &Program::getUniformLocations() const
1528{
1529 return mState.mUniformLocations;
1530}
1531
1532const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1533{
1534 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1535 return mState.mUniforms[index];
1536}
1537
Jamie Madill62d31cb2015-09-11 13:25:51 -04001538GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001540 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001541}
1542
Jamie Madill62d31cb2015-09-11 13:25:51 -04001543GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001544{
Jamie Madille7d84322017-01-10 18:21:59 -05001545 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001546}
1547
1548void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1549{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001550 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1551 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001552}
1553
1554void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1555{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001556 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1557 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558}
1559
1560void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1561{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001562 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1563 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564}
1565
1566void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1567{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001568 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1569 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570}
1571
1572void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1573{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001574 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1575 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001576}
1577
1578void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1579{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001580 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1581 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001582}
1583
1584void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1585{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001586 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1587 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001588}
1589
1590void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1591{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001592 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1593 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001594}
1595
1596void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1597{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001598 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1599 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600}
1601
1602void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1603{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001604 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1605 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001606}
1607
1608void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1609{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001610 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1611 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001612}
1613
1614void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1615{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001616 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1617 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001618}
1619
1620void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1621{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001622 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1623 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001624}
1625
1626void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1627{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001628 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1629 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001630}
1631
1632void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1633{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001634 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1635 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636}
1637
1638void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1639{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001640 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1641 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001642}
1643
1644void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1645{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001646 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1647 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001648}
1649
1650void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1651{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001652 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1653 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001654}
1655
1656void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1657{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001658 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1659 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001660}
1661
1662void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1663{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001664 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1665 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001666}
1667
1668void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1669{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001670 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1671 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001672}
1673
Geoff Lange1a27752015-10-05 13:16:04 -04001674void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001675{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001676 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677}
1678
Geoff Lange1a27752015-10-05 13:16:04 -04001679void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001680{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001681 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001682}
1683
Geoff Lange1a27752015-10-05 13:16:04 -04001684void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001685{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001686 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001687}
1688
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001689void Program::flagForDeletion()
1690{
1691 mDeleteStatus = true;
1692}
1693
1694bool Program::isFlaggedForDeletion() const
1695{
1696 return mDeleteStatus;
1697}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001698
Brandon Jones43a53e22014-08-28 16:23:22 -07001699void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001700{
1701 mInfoLog.reset();
1702
Geoff Lang7dd2e102014-11-10 15:19:26 -05001703 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001704 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001705 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001706 }
1707 else
1708 {
Jamie Madillf6113162015-05-07 11:49:21 -04001709 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001710 }
1711}
1712
Geoff Lang7dd2e102014-11-10 15:19:26 -05001713bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1714{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001715 // Skip cache if we're using an infolog, so we get the full error.
1716 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1717 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1718 {
1719 return mCachedValidateSamplersResult.value();
1720 }
1721
1722 if (mTextureUnitTypesCache.empty())
1723 {
1724 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1725 }
1726 else
1727 {
1728 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1729 }
1730
1731 // if any two active samplers in a program are of different types, but refer to the same
1732 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1733 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001734 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001735 {
Jamie Madille7d84322017-01-10 18:21:59 -05001736 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001737
Jamie Madille7d84322017-01-10 18:21:59 -05001738 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001739 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001740 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1741 {
1742 if (infoLog)
1743 {
1744 (*infoLog) << "Sampler uniform (" << textureUnit
1745 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1746 << caps.maxCombinedTextureImageUnits << ")";
1747 }
1748
1749 mCachedValidateSamplersResult = false;
1750 return false;
1751 }
1752
1753 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1754 {
1755 if (textureType != mTextureUnitTypesCache[textureUnit])
1756 {
1757 if (infoLog)
1758 {
1759 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1760 "image unit ("
1761 << textureUnit << ").";
1762 }
1763
1764 mCachedValidateSamplersResult = false;
1765 return false;
1766 }
1767 }
1768 else
1769 {
1770 mTextureUnitTypesCache[textureUnit] = textureType;
1771 }
1772 }
1773 }
1774
1775 mCachedValidateSamplersResult = true;
1776 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001777}
1778
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001779bool Program::isValidated() const
1780{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001781 return mValidated;
1782}
1783
Geoff Lange1a27752015-10-05 13:16:04 -04001784GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001785{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001787}
1788
1789void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1790{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001791 ASSERT(
1792 uniformBlockIndex <
1793 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001794
Jamie Madill48ef11b2016-04-27 15:21:52 -04001795 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001796
1797 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001798 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001799 std::string string = uniformBlock.name;
1800
Jamie Madill62d31cb2015-09-11 13:25:51 -04001801 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001803 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001804 }
jchen10fd7c3b52017-03-21 15:36:03 +08001805 CopyStringToBuffer(uniformBlockName, string, bufSize, length);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001806 }
1807}
1808
Geoff Lange1a27752015-10-05 13:16:04 -04001809GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001810{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001811 int maxLength = 0;
1812
1813 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001814 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001815 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001816 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1817 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001818 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001819 if (!uniformBlock.name.empty())
1820 {
jchen10af713a22017-04-19 09:10:56 +08001821 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1822 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001823 }
1824 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001825 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001826
1827 return maxLength;
1828}
1829
Geoff Lange1a27752015-10-05 13:16:04 -04001830GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001831{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001832 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08001833 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001834
Jamie Madill48ef11b2016-04-27 15:21:52 -04001835 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001836 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1837 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001838 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001839 if (uniformBlock.name == baseName)
1840 {
1841 const bool arrayElementZero =
1842 (subscript == GL_INVALID_INDEX &&
1843 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1844 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1845 {
1846 return blockIndex;
1847 }
1848 }
1849 }
1850
1851 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001852}
1853
Jamie Madill62d31cb2015-09-11 13:25:51 -04001854const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001855{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001856 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1857 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001858}
1859
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001860void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1861{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001862 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001863 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001864 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001865}
1866
1867GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1868{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001869 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001870}
1871
1872void Program::resetUniformBlockBindings()
1873{
1874 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1875 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001876 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001877 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001878 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001879}
1880
Geoff Lang48dcae72014-02-05 16:28:24 -05001881void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1882{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001883 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001884 for (GLsizei i = 0; i < count; i++)
1885 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001886 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001887 }
1888
Jamie Madill48ef11b2016-04-27 15:21:52 -04001889 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001890}
1891
1892void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1893{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001895 {
jchen10a9042d32017-03-17 08:50:45 +08001896 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1897 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1898 std::string varName = var.nameWithArrayIndex();
1899 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001900 if (length)
1901 {
1902 *length = lastNameIdx;
1903 }
1904 if (size)
1905 {
jchen10a9042d32017-03-17 08:50:45 +08001906 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001907 }
1908 if (type)
1909 {
jchen10a9042d32017-03-17 08:50:45 +08001910 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001911 }
1912 if (name)
1913 {
jchen10a9042d32017-03-17 08:50:45 +08001914 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001915 name[lastNameIdx] = '\0';
1916 }
1917 }
1918}
1919
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001920GLsizei Program::getTransformFeedbackVaryingCount() const
1921{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001922 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001923 {
jchen10a9042d32017-03-17 08:50:45 +08001924 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001925 }
1926 else
1927 {
1928 return 0;
1929 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001930}
1931
1932GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1933{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001934 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001935 {
1936 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001937 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001938 {
jchen10a9042d32017-03-17 08:50:45 +08001939 maxSize =
1940 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001941 }
1942
1943 return maxSize;
1944 }
1945 else
1946 {
1947 return 0;
1948 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001949}
1950
1951GLenum Program::getTransformFeedbackBufferMode() const
1952{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001953 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001954}
1955
Jamie Madillbd044ed2017-06-05 12:59:21 -04001956bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001957{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001958 Shader *vertexShader = mState.mAttachedVertexShader;
1959 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001960
Jamie Madillbd044ed2017-06-05 12:59:21 -04001961 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001962
Jamie Madillbd044ed2017-06-05 12:59:21 -04001963 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings(context);
1964 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001965
Sami Väisänen46eaa942016-06-29 10:26:37 +03001966 std::map<GLuint, std::string> staticFragmentInputLocations;
1967
Jamie Madill4cff2472015-08-21 16:53:18 -04001968 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001969 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001970 bool matched = false;
1971
1972 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001973 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001974 {
1975 continue;
1976 }
1977
Jamie Madill4cff2472015-08-21 16:53:18 -04001978 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001979 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001980 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001981 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001982 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001983 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04001984 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001985 {
1986 return false;
1987 }
1988
Geoff Lang7dd2e102014-11-10 15:19:26 -05001989 matched = true;
1990 break;
1991 }
1992 }
1993
1994 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001995 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001996 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001997 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001998 return false;
1999 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002000
2001 // Check for aliased path rendering input bindings (if any).
2002 // If more than one binding refer statically to the same
2003 // location the link must fail.
2004
2005 if (!output.staticUse)
2006 continue;
2007
2008 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
2009 if (inputBinding == -1)
2010 continue;
2011
2012 const auto it = staticFragmentInputLocations.find(inputBinding);
2013 if (it == std::end(staticFragmentInputLocations))
2014 {
2015 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
2016 }
2017 else
2018 {
2019 infoLog << "Binding for fragment input " << output.name << " conflicts with "
2020 << it->second;
2021 return false;
2022 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002023 }
2024
Jamie Madillbd044ed2017-06-05 12:59:21 -04002025 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05002026 {
2027 return false;
2028 }
2029
Jamie Madillada9ecc2015-08-17 12:53:37 -04002030 // TODO(jmadill): verify no unmatched vertex varyings?
2031
Geoff Lang7dd2e102014-11-10 15:19:26 -05002032 return true;
2033}
2034
Jamie Madillbd044ed2017-06-05 12:59:21 -04002035bool Program::linkUniforms(const Context *context,
2036 InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002037 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002038{
Olli Etuahob78707c2017-03-09 15:03:11 +00002039 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002040 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002041 {
2042 return false;
2043 }
2044
Olli Etuahob78707c2017-03-09 15:03:11 +00002045 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002046
Olli Etuaho48fed632017-03-16 12:05:30 +00002047 linkSamplerBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002048
2049 return true;
2050}
2051
Olli Etuaho48fed632017-03-16 12:05:30 +00002052void Program::linkSamplerBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002053{
Jamie Madill982f6e02017-06-07 14:33:04 -04002054 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2055 unsigned int low = high;
2056
2057 for (auto samplerIter = mState.mUniforms.rbegin();
2058 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002059 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002060 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002061 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002062
2063 mState.mSamplerUniformRange = RangeUI(low, high);
2064
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002065 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002066 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002067 {
2068 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2069 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2070 mState.mSamplerBindings.emplace_back(
2071 SamplerBinding(textureType, samplerUniform.elementCount()));
2072 }
2073}
2074
Martin Radev4c4c8e72016-08-04 12:25:34 +03002075bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2076 const std::string &uniformName,
2077 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002078 const sh::InterfaceBlockField &fragmentUniform,
2079 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002080{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002081 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2082 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2083 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002084 {
2085 return false;
2086 }
2087
2088 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2089 {
Jamie Madillf6113162015-05-07 11:49:21 -04002090 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002091 return false;
2092 }
2093
2094 return true;
2095}
2096
Jamie Madilleb979bf2016-11-15 12:28:46 -05002097// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002098bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002099{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002100 const ContextState &data = context->getContextState();
2101 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002102
Geoff Lang7dd2e102014-11-10 15:19:26 -05002103 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002104 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002105 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002106
2107 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002108 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002109 {
Jamie Madillf6113162015-05-07 11:49:21 -04002110 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002111 return false;
2112 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002113
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002114 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002115
Jamie Madillc349ec02015-08-21 16:53:12 -04002116 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002117 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002118 {
Jamie Madilleb979bf2016-11-15 12:28:46 -05002119 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002120 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002121 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002122 attribute.location = bindingLocation;
2123 }
2124
2125 if (attribute.location != -1)
2126 {
2127 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002128 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002129
Jamie Madill63805b42015-08-25 13:17:39 -04002130 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 {
Jamie Madillf6113162015-05-07 11:49:21 -04002132 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002133 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002134
2135 return false;
2136 }
2137
Jamie Madill63805b42015-08-25 13:17:39 -04002138 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002139 {
Jamie Madill63805b42015-08-25 13:17:39 -04002140 const int regLocation = attribute.location + reg;
2141 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002142
2143 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002144 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002145 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002147 // TODO(jmadill): fix aliasing on ES2
2148 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002149 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002150 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002151 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002152 return false;
2153 }
2154 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002155 else
2156 {
Jamie Madill63805b42015-08-25 13:17:39 -04002157 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002158 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159
Jamie Madill63805b42015-08-25 13:17:39 -04002160 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002161 }
2162 }
2163 }
2164
2165 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002166 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002167 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002168 // Not set by glBindAttribLocation or by location layout qualifier
2169 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002170 {
Jamie Madill63805b42015-08-25 13:17:39 -04002171 int regs = VariableRegisterCount(attribute.type);
2172 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002173
Jamie Madill63805b42015-08-25 13:17:39 -04002174 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175 {
Jamie Madillf6113162015-05-07 11:49:21 -04002176 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002177 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 }
2179
Jamie Madillc349ec02015-08-21 16:53:12 -04002180 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002181 }
2182 }
2183
Jamie Madill48ef11b2016-04-27 15:21:52 -04002184 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185 {
Jamie Madill63805b42015-08-25 13:17:39 -04002186 ASSERT(attribute.location != -1);
2187 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002188
Jamie Madill63805b42015-08-25 13:17:39 -04002189 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002190 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002191 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002192 }
2193 }
2194
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195 return true;
2196}
2197
Martin Radev4c4c8e72016-08-04 12:25:34 +03002198bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2199 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2200 const std::string &errorMessage,
2201 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002202{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002203 GLuint blockCount = 0;
2204 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002206 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002207 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002208 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002209 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002210 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002211 return false;
2212 }
2213 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002214 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002215 return true;
2216}
Jamie Madille473dee2015-08-18 14:49:01 -04002217
Martin Radev4c4c8e72016-08-04 12:25:34 +03002218bool Program::validateVertexAndFragmentInterfaceBlocks(
2219 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2220 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002221 InfoLog &infoLog,
2222 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002223{
2224 // Check that interface blocks defined in the vertex and fragment shaders are identical
2225 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2226 UniformBlockMap linkedUniformBlocks;
2227
2228 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2229 {
2230 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2231 }
2232
Jamie Madille473dee2015-08-18 14:49:01 -04002233 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002234 {
Jamie Madille473dee2015-08-18 14:49:01 -04002235 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002236 if (entry != linkedUniformBlocks.end())
2237 {
2238 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002239 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2240 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002241 {
2242 return false;
2243 }
2244 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002245 }
2246 return true;
2247}
Jamie Madille473dee2015-08-18 14:49:01 -04002248
Jamie Madillbd044ed2017-06-05 12:59:21 -04002249bool Program::linkUniformBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002250{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002251 const auto &caps = context->getCaps();
2252
Martin Radev4c4c8e72016-08-04 12:25:34 +03002253 if (mState.mAttachedComputeShader)
2254 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002255 Shader &computeShader = *mState.mAttachedComputeShader;
2256 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002257
2258 if (!validateUniformBlocksCount(
2259 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2260 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2261 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002262 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002263 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002264 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002265 return true;
2266 }
2267
Jamie Madillbd044ed2017-06-05 12:59:21 -04002268 Shader &vertexShader = *mState.mAttachedVertexShader;
2269 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002270
Jamie Madillbd044ed2017-06-05 12:59:21 -04002271 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(context);
2272 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002273
2274 if (!validateUniformBlocksCount(
2275 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2276 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2277 {
2278 return false;
2279 }
2280 if (!validateUniformBlocksCount(
2281 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2282 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2283 infoLog))
2284 {
2285
2286 return false;
2287 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002288
2289 bool webglCompatibility = context->getExtensions().webglCompatibility;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002290 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002291 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002292 {
2293 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002294 }
Jamie Madille473dee2015-08-18 14:49:01 -04002295
Geoff Lang7dd2e102014-11-10 15:19:26 -05002296 return true;
2297}
2298
Jamie Madilla2c74982016-12-12 11:20:42 -05002299bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002300 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002301 const sh::InterfaceBlock &fragmentInterfaceBlock,
2302 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002303{
2304 const char* blockName = vertexInterfaceBlock.name.c_str();
2305 // validate blocks for the same member types
2306 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2307 {
Jamie Madillf6113162015-05-07 11:49:21 -04002308 infoLog << "Types for interface block '" << blockName
2309 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002310 return false;
2311 }
2312 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2313 {
Jamie Madillf6113162015-05-07 11:49:21 -04002314 infoLog << "Array sizes differ for interface block '" << blockName
2315 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002316 return false;
2317 }
jchen10af713a22017-04-19 09:10:56 +08002318 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2319 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2320 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002321 {
Jamie Madillf6113162015-05-07 11:49:21 -04002322 infoLog << "Layout qualifiers differ for interface block '" << blockName
2323 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002324 return false;
2325 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002326 const unsigned int numBlockMembers =
2327 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002328 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2329 {
2330 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2331 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2332 if (vertexMember.name != fragmentMember.name)
2333 {
Jamie Madillf6113162015-05-07 11:49:21 -04002334 infoLog << "Name mismatch for field " << blockMemberIndex
2335 << " of interface block '" << blockName
2336 << "': (in vertex: '" << vertexMember.name
2337 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002338 return false;
2339 }
2340 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002341 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2342 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002343 {
2344 return false;
2345 }
2346 }
2347 return true;
2348}
2349
2350bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2351 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2352{
2353 if (vertexVariable.type != fragmentVariable.type)
2354 {
Jamie Madillf6113162015-05-07 11:49:21 -04002355 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002356 return false;
2357 }
2358 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2359 {
Jamie Madillf6113162015-05-07 11:49:21 -04002360 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002361 return false;
2362 }
2363 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2364 {
Jamie Madillf6113162015-05-07 11:49:21 -04002365 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002366 return false;
2367 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002368 if (vertexVariable.structName != fragmentVariable.structName)
2369 {
2370 infoLog << "Structure names for " << variableName
2371 << " differ between vertex and fragment shaders";
2372 return false;
2373 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002374
2375 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2376 {
Jamie Madillf6113162015-05-07 11:49:21 -04002377 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002378 return false;
2379 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002380 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002381 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2382 {
2383 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2384 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2385
2386 if (vertexMember.name != fragmentMember.name)
2387 {
Jamie Madillf6113162015-05-07 11:49:21 -04002388 infoLog << "Name mismatch for field '" << memberIndex
2389 << "' of " << variableName
2390 << ": (in vertex: '" << vertexMember.name
2391 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 return false;
2393 }
2394
2395 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2396 vertexMember.name + "'";
2397
2398 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2399 {
2400 return false;
2401 }
2402 }
2403
2404 return true;
2405}
2406
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002407bool Program::linkValidateVaryings(InfoLog &infoLog,
2408 const std::string &varyingName,
2409 const sh::Varying &vertexVarying,
2410 const sh::Varying &fragmentVarying,
2411 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002412{
2413 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2414 {
2415 return false;
2416 }
2417
Jamie Madille9cc4692015-02-19 16:00:13 -05002418 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002419 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002420 infoLog << "Interpolation types for " << varyingName
2421 << " differ between vertex and fragment shaders.";
2422 return false;
2423 }
2424
2425 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2426 {
2427 infoLog << "Invariance for " << varyingName
2428 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002429 return false;
2430 }
2431
2432 return true;
2433}
2434
Jamie Madillbd044ed2017-06-05 12:59:21 -04002435bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002436{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002437 Shader *vertexShader = mState.mAttachedVertexShader;
2438 Shader *fragmentShader = mState.mAttachedFragmentShader;
2439 const auto &vertexVaryings = vertexShader->getVaryings(context);
2440 const auto &fragmentVaryings = fragmentShader->getVaryings(context);
2441 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002442
2443 if (shaderVersion != 100)
2444 {
2445 // Only ESSL 1.0 has restrictions on matching input and output invariance
2446 return true;
2447 }
2448
2449 bool glPositionIsInvariant = false;
2450 bool glPointSizeIsInvariant = false;
2451 bool glFragCoordIsInvariant = false;
2452 bool glPointCoordIsInvariant = false;
2453
2454 for (const sh::Varying &varying : vertexVaryings)
2455 {
2456 if (!varying.isBuiltIn())
2457 {
2458 continue;
2459 }
2460 if (varying.name.compare("gl_Position") == 0)
2461 {
2462 glPositionIsInvariant = varying.isInvariant;
2463 }
2464 else if (varying.name.compare("gl_PointSize") == 0)
2465 {
2466 glPointSizeIsInvariant = varying.isInvariant;
2467 }
2468 }
2469
2470 for (const sh::Varying &varying : fragmentVaryings)
2471 {
2472 if (!varying.isBuiltIn())
2473 {
2474 continue;
2475 }
2476 if (varying.name.compare("gl_FragCoord") == 0)
2477 {
2478 glFragCoordIsInvariant = varying.isInvariant;
2479 }
2480 else if (varying.name.compare("gl_PointCoord") == 0)
2481 {
2482 glPointCoordIsInvariant = varying.isInvariant;
2483 }
2484 }
2485
2486 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2487 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2488 // Not requiring invariance to match is supported by:
2489 // dEQP, WebGL CTS, Nexus 5X GLES
2490 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2491 {
2492 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2493 "declared invariant.";
2494 return false;
2495 }
2496 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2497 {
2498 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2499 "declared invariant.";
2500 return false;
2501 }
2502
2503 return true;
2504}
2505
jchen10a9042d32017-03-17 08:50:45 +08002506bool Program::linkValidateTransformFeedback(const gl::Context *context,
2507 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002508 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002509 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002510{
2511 size_t totalComponents = 0;
2512
Jamie Madillccdf74b2015-08-18 10:46:12 -04002513 std::set<std::string> uniqueNames;
2514
Jamie Madill48ef11b2016-04-27 15:21:52 -04002515 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002516 {
2517 bool found = false;
jchen10a9042d32017-03-17 08:50:45 +08002518 size_t subscript = GL_INVALID_INDEX;
2519 std::string baseName = ParseResourceName(tfVaryingName, &subscript);
2520
Jamie Madill192745a2016-12-22 15:58:21 -05002521 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002522 {
Jamie Madill192745a2016-12-22 15:58:21 -05002523 const sh::Varying *varying = ref.second.get();
2524
jchen10a9042d32017-03-17 08:50:45 +08002525 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002526 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002527 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002528 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002529 infoLog << "Two transform feedback varyings specify the same output variable ("
2530 << tfVaryingName << ").";
2531 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002532 }
jchen10a9042d32017-03-17 08:50:45 +08002533 if (context->getClientVersion() >= Version(3, 1))
2534 {
2535 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2536 {
2537 infoLog
2538 << "Two transform feedback varyings include the same array element ("
2539 << tfVaryingName << ").";
2540 return false;
2541 }
2542 }
2543 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002544 {
2545 infoLog << "Capture of arrays is undefined and not supported.";
2546 return false;
2547 }
2548
jchen10a9042d32017-03-17 08:50:45 +08002549 uniqueNames.insert(tfVaryingName);
2550
Jamie Madillccdf74b2015-08-18 10:46:12 -04002551 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002552 size_t elementCount =
2553 ((varying->isArray() && subscript == GL_INVALID_INDEX) ? varying->elementCount()
2554 : 1);
2555 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002556 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002557 componentCount > caps.maxTransformFeedbackSeparateComponents)
2558 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002559 infoLog << "Transform feedback varying's " << varying->name << " components ("
2560 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002561 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002562 return false;
2563 }
2564
2565 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002566 found = true;
2567 break;
2568 }
2569 }
jchen10a9042d32017-03-17 08:50:45 +08002570 if (context->getClientVersion() < Version(3, 1) &&
2571 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002572 {
Geoff Lang1a683462015-09-29 15:09:59 -04002573 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002574 return false;
2575 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002576 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2577 ASSERT(found);
2578 }
2579
Jamie Madill48ef11b2016-04-27 15:21:52 -04002580 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002581 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002582 {
Jamie Madillf6113162015-05-07 11:49:21 -04002583 infoLog << "Transform feedback varying total components (" << totalComponents
2584 << ") exceed the maximum interleaved components ("
2585 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002586 return false;
2587 }
2588
2589 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002590}
2591
Jamie Madill192745a2016-12-22 15:58:21 -05002592void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002593{
2594 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002595 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002596 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002597 {
jchen10a9042d32017-03-17 08:50:45 +08002598 size_t subscript = GL_INVALID_INDEX;
2599 std::string baseName = ParseResourceName(tfVaryingName, &subscript);
Jamie Madill192745a2016-12-22 15:58:21 -05002600 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002601 {
Jamie Madill192745a2016-12-22 15:58:21 -05002602 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002603 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002604 {
jchen10a9042d32017-03-17 08:50:45 +08002605 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2606 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002607 break;
2608 }
2609 }
2610 }
2611}
2612
Jamie Madillbd044ed2017-06-05 12:59:21 -04002613Program::MergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002614{
Jamie Madill192745a2016-12-22 15:58:21 -05002615 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002616
Jamie Madillbd044ed2017-06-05 12:59:21 -04002617 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002618 {
Jamie Madill192745a2016-12-22 15:58:21 -05002619 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002620 }
2621
Jamie Madillbd044ed2017-06-05 12:59:21 -04002622 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002623 {
Jamie Madill192745a2016-12-22 15:58:21 -05002624 merged[varying.name].fragment = &varying;
2625 }
2626
2627 return merged;
2628}
2629
2630std::vector<PackedVarying> Program::getPackedVaryings(
2631 const Program::MergedVaryings &mergedVaryings) const
2632{
2633 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2634 std::vector<PackedVarying> packedVaryings;
jchen10a9042d32017-03-17 08:50:45 +08002635 std::set<std::string> uniqueFullNames;
Jamie Madill192745a2016-12-22 15:58:21 -05002636
2637 for (const auto &ref : mergedVaryings)
2638 {
2639 const sh::Varying *input = ref.second.vertex;
2640 const sh::Varying *output = ref.second.fragment;
2641
2642 // Only pack varyings that have a matched input or output, plus special builtins.
2643 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002644 {
Jamie Madill192745a2016-12-22 15:58:21 -05002645 // Will get the vertex shader interpolation by default.
2646 auto interpolation = ref.second.get()->interpolation;
2647
2648 // Interpolation qualifiers must match.
2649 if (output->isStruct())
2650 {
2651 ASSERT(!output->isArray());
2652 for (const auto &field : output->fields)
2653 {
2654 ASSERT(!field.isStruct() && !field.isArray());
2655 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2656 }
2657 }
2658 else
2659 {
2660 packedVaryings.push_back(PackedVarying(*output, interpolation));
2661 }
2662 continue;
2663 }
2664
2665 // Keep Transform FB varyings in the merged list always.
2666 if (!input)
2667 {
2668 continue;
2669 }
2670
2671 for (const std::string &tfVarying : tfVaryings)
2672 {
jchen10a9042d32017-03-17 08:50:45 +08002673 size_t subscript = GL_INVALID_INDEX;
2674 std::string baseName = ParseResourceName(tfVarying, &subscript);
2675 if (uniqueFullNames.count(tfVarying) > 0)
2676 {
2677 continue;
2678 }
2679 if (baseName == input->name)
Jamie Madill192745a2016-12-22 15:58:21 -05002680 {
2681 // Transform feedback for varying structs is underspecified.
2682 // See Khronos bug 9856.
2683 // TODO(jmadill): Figure out how to be spec-compliant here.
2684 if (!input->isStruct())
2685 {
2686 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2687 packedVaryings.back().vertexOnly = true;
jchen10a9042d32017-03-17 08:50:45 +08002688 packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
2689 uniqueFullNames.insert(tfVarying);
Jamie Madill192745a2016-12-22 15:58:21 -05002690 }
jchen10a9042d32017-03-17 08:50:45 +08002691 if (subscript == GL_INVALID_INDEX)
2692 {
2693 break;
2694 }
Jamie Madill192745a2016-12-22 15:58:21 -05002695 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002696 }
2697 }
2698
Jamie Madill192745a2016-12-22 15:58:21 -05002699 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2700
2701 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002702}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002703
Jamie Madillbd044ed2017-06-05 12:59:21 -04002704void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002705{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002706 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002707 ASSERT(fragmentShader != nullptr);
2708
Geoff Lange0cff192017-05-30 13:04:56 -04002709 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002710 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002711
2712 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002713 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002714 {
2715 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2716 outputVariable.name != "gl_FragData")
2717 {
2718 continue;
2719 }
2720
2721 unsigned int baseLocation =
2722 (outputVariable.location == -1 ? 0u
2723 : static_cast<unsigned int>(outputVariable.location));
2724 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2725 elementIndex++)
2726 {
2727 const unsigned int location = baseLocation + elementIndex;
2728 if (location >= mState.mOutputVariableTypes.size())
2729 {
2730 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2731 }
Corentin Walleze7557742017-06-01 13:09:57 -04002732 ASSERT(location < mState.mActiveOutputVariables.size());
2733 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002734 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2735 }
2736 }
2737
Jamie Madill80a6fc02015-08-21 16:53:16 -04002738 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002739 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002740 return;
2741
Jamie Madillbd044ed2017-06-05 12:59:21 -04002742 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002743 // TODO(jmadill): any caps validation here?
2744
jchen1015015f72017-03-16 13:54:21 +08002745 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002746 outputVariableIndex++)
2747 {
jchen1015015f72017-03-16 13:54:21 +08002748 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002749
2750 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2751 if (outputVariable.isBuiltIn())
2752 continue;
2753
2754 // Since multiple output locations must be specified, use 0 for non-specified locations.
2755 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2756
Jamie Madill80a6fc02015-08-21 16:53:16 -04002757 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2758 elementIndex++)
2759 {
2760 const int location = baseLocation + elementIndex;
jchen1015015f72017-03-16 13:54:21 +08002761 ASSERT(mState.mOutputLocations.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002762 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08002763 mState.mOutputLocations[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002764 VariableLocation(outputVariable.name, element, outputVariableIndex);
2765 }
2766 }
2767}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002768
Olli Etuaho48fed632017-03-16 12:05:30 +00002769void Program::setUniformValuesFromBindingQualifiers()
2770{
Jamie Madill982f6e02017-06-07 14:33:04 -04002771 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002772 {
2773 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2774 if (samplerUniform.binding != -1)
2775 {
2776 GLint location = mState.getUniformLocation(samplerUniform.name);
2777 ASSERT(location != -1);
2778 std::vector<GLint> boundTextureUnits;
2779 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2780 ++elementIndex)
2781 {
2782 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2783 }
2784 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2785 boundTextureUnits.data());
2786 }
2787 }
2788}
2789
Jamie Madillbd044ed2017-06-05 12:59:21 -04002790void Program::gatherInterfaceBlockInfo(const Context *context)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002791{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002792 ASSERT(mState.mUniformBlocks.empty());
2793
2794 if (mState.mAttachedComputeShader)
2795 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002796 Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002797
Jamie Madillbd044ed2017-06-05 12:59:21 -04002798 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002799 {
2800
2801 // Only 'packed' blocks are allowed to be considered inactive.
2802 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2803 continue;
2804
Jamie Madilla2c74982016-12-12 11:20:42 -05002805 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002806 {
2807 if (block.name == computeBlock.name)
2808 {
2809 block.computeStaticUse = computeBlock.staticUse;
2810 }
2811 }
2812
2813 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2814 }
2815 return;
2816 }
2817
Jamie Madill62d31cb2015-09-11 13:25:51 -04002818 std::set<std::string> visitedList;
2819
Jamie Madillbd044ed2017-06-05 12:59:21 -04002820 Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002821
Jamie Madillbd044ed2017-06-05 12:59:21 -04002822 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks(context))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002823 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002824 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002825 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2826 continue;
2827
2828 if (visitedList.count(vertexBlock.name) > 0)
2829 continue;
2830
2831 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2832 visitedList.insert(vertexBlock.name);
2833 }
2834
Jamie Madillbd044ed2017-06-05 12:59:21 -04002835 Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002836
Jamie Madillbd044ed2017-06-05 12:59:21 -04002837 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks(context))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002838 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002839 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002840 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2841 continue;
2842
2843 if (visitedList.count(fragmentBlock.name) > 0)
2844 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002845 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002846 {
2847 if (block.name == fragmentBlock.name)
2848 {
2849 block.fragmentStaticUse = fragmentBlock.staticUse;
2850 }
2851 }
2852
2853 continue;
2854 }
2855
2856 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2857 visitedList.insert(fragmentBlock.name);
2858 }
jchen10af713a22017-04-19 09:10:56 +08002859 // Set initial bindings from shader.
2860 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2861 {
2862 UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
2863 bindUniformBlock(blockIndex, uniformBlock.binding);
2864 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002865}
2866
Jamie Madill4a3c2342015-10-08 12:58:45 -04002867template <typename VarT>
2868void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2869 const std::string &prefix,
2870 int blockIndex)
2871{
2872 for (const VarT &field : fields)
2873 {
2874 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2875
2876 if (field.isStruct())
2877 {
2878 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2879 {
2880 const std::string uniformElementName =
2881 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2882 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2883 }
2884 }
2885 else
2886 {
2887 // If getBlockMemberInfo returns false, the uniform is optimized out.
2888 sh::BlockMemberInfo memberInfo;
2889 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2890 {
2891 continue;
2892 }
2893
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002894 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04002895 blockIndex, memberInfo);
2896
2897 // Since block uniforms have no location, we don't need to store them in the uniform
2898 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002899 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002900 }
2901 }
2902}
2903
Jamie Madill62d31cb2015-09-11 13:25:51 -04002904void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2905{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002906 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002907 size_t blockSize = 0;
2908
Jamie Madill4a3c2342015-10-08 12:58:45 -04002909 // Track the first and last uniform index to determine the range of active uniforms in the
2910 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002911 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002912 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002913 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002914
2915 std::vector<unsigned int> blockUniformIndexes;
2916 for (size_t blockUniformIndex = firstBlockUniformIndex;
2917 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2918 {
2919 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2920 }
jchen10af713a22017-04-19 09:10:56 +08002921 // ESSL 3.10 section 4.4.4 page 58:
2922 // Any uniform or shader storage block declared without a binding qualifier is initially
2923 // assigned to block binding point zero.
2924 int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002925 if (interfaceBlock.arraySize > 0)
2926 {
2927 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2928 {
jchen10af713a22017-04-19 09:10:56 +08002929 // Don't define this block at all if it's not active in the implementation.
2930 if (!mProgram->getUniformBlockSize(interfaceBlock.name + ArrayString(arrayElement),
2931 &blockSize))
2932 {
2933 continue;
2934 }
2935 UniformBlock block(interfaceBlock.name, true, arrayElement,
2936 blockBinding + arrayElement);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002937 block.memberUniformIndexes = blockUniformIndexes;
2938
Martin Radev4c4c8e72016-08-04 12:25:34 +03002939 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002940 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002941 case GL_VERTEX_SHADER:
2942 {
2943 block.vertexStaticUse = interfaceBlock.staticUse;
2944 break;
2945 }
2946 case GL_FRAGMENT_SHADER:
2947 {
2948 block.fragmentStaticUse = interfaceBlock.staticUse;
2949 break;
2950 }
2951 case GL_COMPUTE_SHADER:
2952 {
2953 block.computeStaticUse = interfaceBlock.staticUse;
2954 break;
2955 }
2956 default:
2957 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002958 }
2959
Qin Jiajia0350a642016-11-01 17:01:51 +08002960 // Since all block elements in an array share the same active uniforms, they will all be
2961 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2962 // here we will add every block element in the array.
2963 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002964 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002965 }
2966 }
2967 else
2968 {
jchen10af713a22017-04-19 09:10:56 +08002969 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2970 {
2971 return;
2972 }
2973 UniformBlock block(interfaceBlock.name, false, 0, blockBinding);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002974 block.memberUniformIndexes = blockUniformIndexes;
2975
Martin Radev4c4c8e72016-08-04 12:25:34 +03002976 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002977 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002978 case GL_VERTEX_SHADER:
2979 {
2980 block.vertexStaticUse = interfaceBlock.staticUse;
2981 break;
2982 }
2983 case GL_FRAGMENT_SHADER:
2984 {
2985 block.fragmentStaticUse = interfaceBlock.staticUse;
2986 break;
2987 }
2988 case GL_COMPUTE_SHADER:
2989 {
2990 block.computeStaticUse = interfaceBlock.staticUse;
2991 break;
2992 }
2993 default:
2994 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002995 }
2996
Jamie Madill4a3c2342015-10-08 12:58:45 -04002997 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002998 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002999 }
3000}
3001
Jamie Madille7d84322017-01-10 18:21:59 -05003002template <>
3003void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3004 const uint8_t *destPointer,
3005 GLsizei clampedCount,
3006 const GLint *v)
3007{
3008 // Invalidate the validation cache only if we modify the sampler data.
3009 if (mState.isSamplerUniformIndex(locationInfo.index) &&
3010 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
3011 {
3012 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3013 std::vector<GLuint> *boundTextureUnits =
3014 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
3015
3016 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
3017 mCachedValidateSamplersResult.reset();
3018 }
3019}
3020
3021template <typename T>
3022void Program::updateSamplerUniform(const VariableLocation &locationInfo,
3023 const uint8_t *destPointer,
3024 GLsizei clampedCount,
3025 const T *v)
3026{
3027}
3028
Jamie Madill62d31cb2015-09-11 13:25:51 -04003029template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003030GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003031{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003032 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3033 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003034 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
3035
Corentin Wallez15ac5342016-11-03 17:06:39 -04003036 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3037 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3038 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003039 GLsizei maxElementCount =
3040 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
3041
3042 GLsizei count = countIn;
3043 GLsizei clampedCount = count * vectorSize;
3044 if (clampedCount > maxElementCount)
3045 {
3046 clampedCount = maxElementCount;
3047 count = maxElementCount / vectorSize;
3048 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04003049
Jamie Madill62d31cb2015-09-11 13:25:51 -04003050 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
3051 {
3052 // Do a cast conversion for boolean types. From the spec:
3053 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
3054 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003055 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003056 {
3057 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
3058 }
3059 }
3060 else
3061 {
Jamie Madille7d84322017-01-10 18:21:59 -05003062 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003063 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003064 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003065
3066 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003067}
3068
3069template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003070GLsizei Program::setMatrixUniformInternal(GLint location,
3071 GLsizei count,
3072 GLboolean transpose,
3073 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003074{
3075 if (!transpose)
3076 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003077 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003078 }
3079
3080 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003081 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3082 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003083 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04003084
3085 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3086 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3087 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
3088 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
3089
3090 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003091 {
3092 size_t elementOffset = element * rows * cols;
3093
3094 for (size_t row = 0; row < rows; ++row)
3095 {
3096 for (size_t col = 0; col < cols; ++col)
3097 {
3098 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
3099 }
3100 }
3101 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003102
3103 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003104}
3105
3106template <typename DestT>
3107void Program::getUniformInternal(GLint location, DestT *dataOut) const
3108{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003109 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3110 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003111
3112 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
3113
3114 GLenum componentType = VariableComponentType(uniform.type);
3115 if (componentType == GLTypeToGLenum<DestT>::value)
3116 {
3117 memcpy(dataOut, srcPointer, uniform.getElementSize());
3118 return;
3119 }
3120
Corentin Wallez6596c462016-03-17 17:26:58 -04003121 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003122
3123 switch (componentType)
3124 {
3125 case GL_INT:
3126 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
3127 break;
3128 case GL_UNSIGNED_INT:
3129 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
3130 break;
3131 case GL_BOOL:
3132 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
3133 break;
3134 case GL_FLOAT:
3135 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
3136 break;
3137 default:
3138 UNREACHABLE();
3139 }
3140}
Jamie Madilla4595b82017-01-11 17:36:34 -05003141
3142bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3143{
3144 // Must be called after samplers are validated.
3145 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3146
3147 for (const auto &binding : mState.mSamplerBindings)
3148 {
3149 GLenum textureType = binding.textureType;
3150 for (const auto &unit : binding.boundTextureUnits)
3151 {
3152 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3153 if (programTextureID == textureID)
3154 {
3155 // TODO(jmadill): Check for appropriate overlap.
3156 return true;
3157 }
3158 }
3159 }
3160
3161 return false;
3162}
3163
Jamie Madilla2c74982016-12-12 11:20:42 -05003164} // namespace gl