blob: 037283bc1807c8c0475536c9cb0747abeac03c5f [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{
399 return index >= mSamplerUniformRange.start && index < mSamplerUniformRange.end;
400}
401
402GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
403{
404 ASSERT(isSamplerUniformIndex(uniformIndex));
405 return uniformIndex - mSamplerUniformRange.start;
406}
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
450 mProgram->destroy(rx::SafeGetImpl(context));
451}
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 Madill6c1f6712017-02-14 19:08:04 -0500493bool 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 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300499 if (mState.mAttachedVertexShader != shader)
500 {
501 return false;
502 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503
Jamie Madill6c1f6712017-02-14 19:08:04 -0500504 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300505 mState.mAttachedVertexShader = nullptr;
506 break;
507 }
508 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300510 if (mState.mAttachedFragmentShader != shader)
511 {
512 return false;
513 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514
Jamie Madill6c1f6712017-02-14 19:08:04 -0500515 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300516 mState.mAttachedFragmentShader = nullptr;
517 break;
518 }
519 case GL_COMPUTE_SHADER:
520 {
521 if (mState.mAttachedComputeShader != shader)
522 {
523 return false;
524 }
525
Jamie Madill6c1f6712017-02-14 19:08:04 -0500526 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300527 mState.mAttachedComputeShader = nullptr;
528 break;
529 }
530 default:
531 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000533
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534 return true;
535}
536
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000537int Program::getAttachedShadersCount() const
538{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300539 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
540 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000541}
542
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543void Program::bindAttributeLocation(GLuint index, const char *name)
544{
Geoff Langd8605522016-04-13 10:19:12 -0400545 mAttributeBindings.bindLocation(index, name);
546}
547
548void Program::bindUniformLocation(GLuint index, const char *name)
549{
550 // Bind the base uniform name only since array indices other than 0 cannot be bound
jchen1015015f72017-03-16 13:54:21 +0800551 mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000552}
553
Sami Väisänen46eaa942016-06-29 10:26:37 +0300554void Program::bindFragmentInputLocation(GLint index, const char *name)
555{
556 mFragmentInputBindings.bindLocation(index, name);
557}
558
559BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
560{
561 BindingInfo ret;
562 ret.type = GL_NONE;
563 ret.valid = false;
564
565 const Shader *fragmentShader = mState.getAttachedFragmentShader();
566 ASSERT(fragmentShader);
567
568 // Find the actual fragment shader varying we're interested in
569 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
570
571 for (const auto &binding : mFragmentInputBindings)
572 {
573 if (binding.second != static_cast<GLuint>(index))
574 continue;
575
576 ret.valid = true;
577
578 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400579 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300580
581 for (const auto &in : inputs)
582 {
583 if (in.name == originalName)
584 {
585 if (in.isArray())
586 {
587 // The client wants to bind either "name" or "name[0]".
588 // GL ES 3.1 spec refers to active array names with language such as:
589 // "if the string identifies the base name of an active array, where the
590 // string would exactly match the name of the variable if the suffix "[0]"
591 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400592 if (arrayIndex == GL_INVALID_INDEX)
593 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300594
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400595 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300596 }
597 else
598 {
599 ret.name = in.mappedName;
600 }
601 ret.type = in.type;
602 return ret;
603 }
604 }
605 }
606
607 return ret;
608}
609
610void Program::pathFragmentInputGen(GLint index,
611 GLenum genMode,
612 GLint components,
613 const GLfloat *coeffs)
614{
615 // If the location is -1 then the command is silently ignored
616 if (index == -1)
617 return;
618
619 const auto &binding = getFragmentInputBindingInfo(index);
620
621 // If the input doesn't exist then then the command is silently ignored
622 // This could happen through optimization for example, the shader translator
623 // decides that a variable is not actually being used and optimizes it away.
624 if (binding.name.empty())
625 return;
626
627 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
628}
629
Martin Radev4c4c8e72016-08-04 12:25:34 +0300630// The attached shaders are checked for linking errors by matching up their variables.
631// Uniform, input and output variables get collected.
632// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500633Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000634{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500635 const auto &data = context->getContextState();
636
Jamie Madill6c1f6712017-02-14 19:08:04 -0500637 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000638
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000639 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000640 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000641
Martin Radev4c4c8e72016-08-04 12:25:34 +0300642 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500643
Jamie Madill192745a2016-12-22 15:58:21 -0500644 auto vertexShader = mState.mAttachedVertexShader;
645 auto fragmentShader = mState.mAttachedFragmentShader;
646 auto computeShader = mState.mAttachedComputeShader;
647
648 bool isComputeShaderAttached = (computeShader != nullptr);
649 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300650 // Check whether we both have a compute and non-compute shaders attached.
651 // If there are of both types attached, then linking should fail.
652 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
653 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500654 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300655 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
656 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400657 }
658
Jamie Madill192745a2016-12-22 15:58:21 -0500659 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500660 {
Jamie Madill192745a2016-12-22 15:58:21 -0500661 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300662 {
663 mInfoLog << "Attached compute shader is not compiled.";
664 return NoError();
665 }
Jamie Madill192745a2016-12-22 15:58:21 -0500666 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300667
Jamie Madill192745a2016-12-22 15:58:21 -0500668 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300669
670 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
671 // If the work group size is not specified, a link time error should occur.
672 if (!mState.mComputeShaderLocalSize.isDeclared())
673 {
674 mInfoLog << "Work group size is not specified.";
675 return NoError();
676 }
677
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000678 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300679 {
680 return NoError();
681 }
682
683 if (!linkUniformBlocks(mInfoLog, caps))
684 {
685 return NoError();
686 }
687
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500688 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
689 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), noPacking, mInfoLog),
690 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500691 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300692 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500693 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300694 }
695 }
696 else
697 {
Jamie Madill192745a2016-12-22 15:58:21 -0500698 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300699 {
700 return NoError();
701 }
Jamie Madill192745a2016-12-22 15:58:21 -0500702 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300703
Jamie Madill192745a2016-12-22 15:58:21 -0500704 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300705 {
706 return NoError();
707 }
Jamie Madill192745a2016-12-22 15:58:21 -0500708 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300709
Jamie Madill192745a2016-12-22 15:58:21 -0500710 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300711 {
712 mInfoLog << "Fragment shader version does not match vertex shader version.";
713 return NoError();
714 }
715
Jamie Madilleb979bf2016-11-15 12:28:46 -0500716 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300717 {
718 return NoError();
719 }
720
Jamie Madill192745a2016-12-22 15:58:21 -0500721 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300722 {
723 return NoError();
724 }
725
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000726 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300727 {
728 return NoError();
729 }
730
731 if (!linkUniformBlocks(mInfoLog, caps))
732 {
733 return NoError();
734 }
735
736 const auto &mergedVaryings = getMergedVaryings();
737
jchen10a9042d32017-03-17 08:50:45 +0800738 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300739 {
740 return NoError();
741 }
742
743 linkOutputVariables();
744
Jamie Madill192745a2016-12-22 15:58:21 -0500745 // Validate we can pack the varyings.
746 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
747
748 // Map the varyings to the register file
749 // In WebGL, we use a slightly different handling for packing variables.
750 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
751 : PackMode::ANGLE_RELAXED;
752 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
753 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
754 mState.getTransformFeedbackVaryingNames()))
755 {
756 return NoError();
757 }
758
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500759 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), varyingPacking, mInfoLog),
760 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500761 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300762 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500763 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300764 }
765
766 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500767 }
768
Olli Etuaho48fed632017-03-16 12:05:30 +0000769 setUniformValuesFromBindingQualifiers();
770
Jamie Madill4a3c2342015-10-08 12:58:45 -0400771 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400772
Martin Radev4c4c8e72016-08-04 12:25:34 +0300773 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000774}
775
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000776// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500777void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400779 mState.mAttributes.clear();
780 mState.mActiveAttribLocationsMask.reset();
jchen10a9042d32017-03-17 08:50:45 +0800781 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400782 mState.mUniforms.clear();
783 mState.mUniformLocations.clear();
784 mState.mUniformBlocks.clear();
785 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800786 mState.mOutputLocations.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300787 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500788 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500789
Geoff Lang7dd2e102014-11-10 15:19:26 -0500790 mValidated = false;
791
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000792 mLinked = false;
793}
794
Geoff Lange1a27752015-10-05 13:16:04 -0400795bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000796{
797 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798}
799
Jamie Madilla2c74982016-12-12 11:20:42 -0500800Error Program::loadBinary(const Context *context,
801 GLenum binaryFormat,
802 const void *binary,
803 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000804{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500805 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000806
Geoff Lang7dd2e102014-11-10 15:19:26 -0500807#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800808 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500809#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400810 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
811 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000812 {
Jamie Madillf6113162015-05-07 11:49:21 -0400813 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800814 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500815 }
816
Geoff Langc46cc2f2015-10-01 17:16:20 -0400817 BinaryInputStream stream(binary, length);
818
Jamie Madilla2c74982016-12-12 11:20:42 -0500819 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
820 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
821 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
822 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500823 {
Jamie Madillf6113162015-05-07 11:49:21 -0400824 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800825 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500826 }
827
Jamie Madilla2c74982016-12-12 11:20:42 -0500828 int majorVersion = stream.readInt<int>();
829 int minorVersion = stream.readInt<int>();
830 if (majorVersion != context->getClientMajorVersion() ||
831 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500832 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500833 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800834 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500835 }
836
Martin Radev4c4c8e72016-08-04 12:25:34 +0300837 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
838 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
839 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
840
Jamie Madill63805b42015-08-25 13:17:39 -0400841 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
842 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400843 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500844
Jamie Madill3da79b72015-04-27 11:09:17 -0400845 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400846 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400847 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
848 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400849 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400850 LoadShaderVar(&stream, &attrib);
851 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400852 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400853 }
854
Jamie Madill62d31cb2015-09-11 13:25:51 -0400855 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400856 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400857 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
858 {
859 LinkedUniform uniform;
860 LoadShaderVar(&stream, &uniform);
861
862 uniform.blockIndex = stream.readInt<int>();
863 uniform.blockInfo.offset = stream.readInt<int>();
864 uniform.blockInfo.arrayStride = stream.readInt<int>();
865 uniform.blockInfo.matrixStride = stream.readInt<int>();
866 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
867
Jamie Madill48ef11b2016-04-27 15:21:52 -0400868 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400869 }
870
871 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400872 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400873 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
874 uniformIndexIndex++)
875 {
876 VariableLocation variable;
877 stream.readString(&variable.name);
878 stream.readInt(&variable.element);
879 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400880 stream.readBool(&variable.used);
881 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400882
Jamie Madill48ef11b2016-04-27 15:21:52 -0400883 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400884 }
885
886 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400887 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400888 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
889 ++uniformBlockIndex)
890 {
891 UniformBlock uniformBlock;
892 stream.readString(&uniformBlock.name);
893 stream.readBool(&uniformBlock.isArray);
894 stream.readInt(&uniformBlock.arrayElement);
895 stream.readInt(&uniformBlock.dataSize);
896 stream.readBool(&uniformBlock.vertexStaticUse);
897 stream.readBool(&uniformBlock.fragmentStaticUse);
898
899 unsigned int numMembers = stream.readInt<unsigned int>();
900 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
901 {
902 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
903 }
904
Jamie Madill48ef11b2016-04-27 15:21:52 -0400905 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400906 }
907
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500908 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
909 ++bindingIndex)
910 {
911 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
912 mState.mActiveUniformBlockBindings.set(bindingIndex,
913 mState.mUniformBlockBindings[bindingIndex] != 0);
914 }
915
Brandon Jones1048ea72015-10-06 15:34:52 -0700916 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
jchen10a9042d32017-03-17 08:50:45 +0800917 ASSERT(mState.mLinkedTransformFeedbackVaryings.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700918 for (unsigned int transformFeedbackVaryingIndex = 0;
919 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
920 ++transformFeedbackVaryingIndex)
921 {
922 sh::Varying varying;
923 stream.readInt(&varying.arraySize);
924 stream.readInt(&varying.type);
925 stream.readString(&varying.name);
926
jchen10a9042d32017-03-17 08:50:45 +0800927 GLuint arrayIndex = stream.readInt<GLuint>();
928
929 mState.mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
Brandon Jones1048ea72015-10-06 15:34:52 -0700930 }
931
Jamie Madill48ef11b2016-04-27 15:21:52 -0400932 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400933
jchen1015015f72017-03-16 13:54:21 +0800934 unsigned int outputCount = stream.readInt<unsigned int>();
935 ASSERT(mState.mOutputVariables.empty());
936 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
937 {
938 sh::OutputVariable output;
939 LoadShaderVar(&stream, &output);
940 output.location = stream.readInt<int>();
941 mState.mOutputVariables.push_back(output);
942 }
943
Jamie Madill80a6fc02015-08-21 16:53:16 -0400944 unsigned int outputVarCount = stream.readInt<unsigned int>();
945 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
946 {
947 int locationIndex = stream.readInt<int>();
948 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400949 stream.readInt(&locationData.element);
950 stream.readInt(&locationData.index);
951 stream.readString(&locationData.name);
jchen1015015f72017-03-16 13:54:21 +0800952 mState.mOutputLocations[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400953 }
954
Jamie Madille7d84322017-01-10 18:21:59 -0500955 stream.readInt(&mState.mSamplerUniformRange.start);
956 stream.readInt(&mState.mSamplerUniformRange.end);
957
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 Madilla7d12dc2016-12-13 15:08:19 -0500966 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), 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);
1042 stream.writeInt(uniformBlock.dataSize);
1043
1044 stream.writeInt(uniformBlock.vertexStaticUse);
1045 stream.writeInt(uniformBlock.fragmentStaticUse);
1046
1047 stream.writeInt(uniformBlock.memberUniformIndexes.size());
1048 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
1049 {
1050 stream.writeInt(memberUniformIndex);
1051 }
Jamie Madill3da79b72015-04-27 11:09:17 -04001052 }
1053
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001054 for (GLuint binding : mState.mUniformBlockBindings)
1055 {
1056 stream.writeInt(binding);
1057 }
1058
jchen10a9042d32017-03-17 08:50:45 +08001059 stream.writeInt(mState.mLinkedTransformFeedbackVaryings.size());
1060 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Brandon Jones1048ea72015-10-06 15:34:52 -07001061 {
jchen10a9042d32017-03-17 08:50:45 +08001062 stream.writeInt(var.arraySize);
1063 stream.writeInt(var.type);
1064 stream.writeString(var.name);
1065
1066 stream.writeIntOrNegOne(var.arrayIndex);
Brandon Jones1048ea72015-10-06 15:34:52 -07001067 }
1068
Jamie Madill48ef11b2016-04-27 15:21:52 -04001069 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001070
Jamie Madill48ef11b2016-04-27 15:21:52 -04001071 stream.writeInt(mState.mOutputVariables.size());
jchen1015015f72017-03-16 13:54:21 +08001072 for (const sh::OutputVariable &output : mState.mOutputVariables)
1073 {
1074 WriteShaderVar(&stream, output);
1075 stream.writeInt(output.location);
1076 }
1077
1078 stream.writeInt(mState.mOutputLocations.size());
1079 for (const auto &outputPair : mState.mOutputLocations)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001080 {
1081 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001082 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001083 stream.writeInt(outputPair.second.index);
1084 stream.writeString(outputPair.second.name);
1085 }
1086
Jamie Madille7d84322017-01-10 18:21:59 -05001087 stream.writeInt(mState.mSamplerUniformRange.start);
1088 stream.writeInt(mState.mSamplerUniformRange.end);
1089
1090 stream.writeInt(mState.mSamplerBindings.size());
1091 for (const auto &samplerBinding : mState.mSamplerBindings)
1092 {
1093 stream.writeInt(samplerBinding.textureType);
1094 stream.writeInt(samplerBinding.boundTextureUnits.size());
1095 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001096
Jamie Madilla2c74982016-12-12 11:20:42 -05001097 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001098
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001099 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001100 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001101
1102 if (streamLength > bufSize)
1103 {
1104 if (length)
1105 {
1106 *length = 0;
1107 }
1108
1109 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1110 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1111 // sizes and then copy it.
1112 return Error(GL_INVALID_OPERATION);
1113 }
1114
1115 if (binary)
1116 {
1117 char *ptr = reinterpret_cast<char*>(binary);
1118
Jamie Madill48ef11b2016-04-27 15:21:52 -04001119 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001120 ptr += streamLength;
1121
1122 ASSERT(ptr - streamLength == binary);
1123 }
1124
1125 if (length)
1126 {
1127 *length = streamLength;
1128 }
1129
He Yunchaoacd18982017-01-04 10:46:42 +08001130 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001131}
1132
1133GLint Program::getBinaryLength() const
1134{
1135 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001136 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001137 if (error.isError())
1138 {
1139 return 0;
1140 }
1141
1142 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001143}
1144
Geoff Langc5629752015-12-07 16:29:04 -05001145void Program::setBinaryRetrievableHint(bool retrievable)
1146{
1147 // TODO(jmadill) : replace with dirty bits
1148 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001149 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001150}
1151
1152bool Program::getBinaryRetrievableHint() const
1153{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001154 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001155}
1156
Yunchao He61afff12017-03-14 15:34:03 +08001157void Program::setSeparable(bool separable)
1158{
1159 // TODO(yunchao) : replace with dirty bits
1160 if (mState.mSeparable != separable)
1161 {
1162 mProgram->setSeparable(separable);
1163 mState.mSeparable = separable;
1164 }
1165}
1166
1167bool Program::isSeparable() const
1168{
1169 return mState.mSeparable;
1170}
1171
Jamie Madill6c1f6712017-02-14 19:08:04 -05001172void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001173{
1174 mRefCount--;
1175
1176 if (mRefCount == 0 && mDeleteStatus)
1177 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001178 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001179 }
1180}
1181
1182void Program::addRef()
1183{
1184 mRefCount++;
1185}
1186
1187unsigned int Program::getRefCount() const
1188{
1189 return mRefCount;
1190}
1191
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001192int Program::getInfoLogLength() const
1193{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001194 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001195}
1196
Geoff Lange1a27752015-10-05 13:16:04 -04001197void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001198{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001199 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001200}
1201
Geoff Lange1a27752015-10-05 13:16:04 -04001202void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001203{
1204 int total = 0;
1205
Martin Radev4c4c8e72016-08-04 12:25:34 +03001206 if (mState.mAttachedComputeShader)
1207 {
1208 if (total < maxCount)
1209 {
1210 shaders[total] = mState.mAttachedComputeShader->getHandle();
1211 total++;
1212 }
1213 }
1214
Jamie Madill48ef11b2016-04-27 15:21:52 -04001215 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001216 {
1217 if (total < maxCount)
1218 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001219 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001220 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001221 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001222 }
1223
Jamie Madill48ef11b2016-04-27 15:21:52 -04001224 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001225 {
1226 if (total < maxCount)
1227 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001228 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001229 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001230 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001231 }
1232
1233 if (count)
1234 {
1235 *count = total;
1236 }
1237}
1238
Geoff Lange1a27752015-10-05 13:16:04 -04001239GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001240{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001241 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001242 {
jchen1036e120e2017-03-14 14:53:58 +08001243 if (attribute.name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001244 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001245 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001246 }
1247 }
1248
Austin Kinrossb8af7232015-03-16 22:33:25 -07001249 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001250}
1251
Jamie Madill63805b42015-08-25 13:17:39 -04001252bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001253{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001254 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1255 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001256}
1257
jchen10fd7c3b52017-03-21 15:36:03 +08001258void Program::getActiveAttribute(GLuint index,
1259 GLsizei bufsize,
1260 GLsizei *length,
1261 GLint *size,
1262 GLenum *type,
1263 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001264{
Jamie Madillc349ec02015-08-21 16:53:12 -04001265 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001266 {
1267 if (bufsize > 0)
1268 {
1269 name[0] = '\0';
1270 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001271
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001272 if (length)
1273 {
1274 *length = 0;
1275 }
1276
1277 *type = GL_NONE;
1278 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001279 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001280 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001281
jchen1036e120e2017-03-14 14:53:58 +08001282 ASSERT(index < mState.mAttributes.size());
1283 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001284
1285 if (bufsize > 0)
1286 {
jchen10fd7c3b52017-03-21 15:36:03 +08001287 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001288 }
1289
1290 // Always a single 'type' instance
1291 *size = 1;
1292 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001293}
1294
Geoff Lange1a27752015-10-05 13:16:04 -04001295GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001296{
Jamie Madillc349ec02015-08-21 16:53:12 -04001297 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001298 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001299 return 0;
1300 }
1301
jchen1036e120e2017-03-14 14:53:58 +08001302 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001303}
1304
Geoff Lange1a27752015-10-05 13:16:04 -04001305GLint Program::getActiveAttributeMaxLength() 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
1312 size_t maxLength = 0;
1313
Jamie Madill48ef11b2016-04-27 15:21:52 -04001314 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001315 {
jchen1036e120e2017-03-14 14:53:58 +08001316 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001317 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001318
Jamie Madillc349ec02015-08-21 16:53:12 -04001319 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001320}
1321
jchen1015015f72017-03-16 13:54:21 +08001322GLuint Program::getInputResourceIndex(const GLchar *name) const
1323{
1324 for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
1325 {
1326 const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
1327 if (attribute.name == name)
1328 {
1329 return attributeIndex;
1330 }
1331 }
1332 return GL_INVALID_INDEX;
1333}
1334
1335GLuint Program::getOutputResourceIndex(const GLchar *name) const
1336{
1337 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1338}
1339
jchen10fd7c3b52017-03-21 15:36:03 +08001340size_t Program::getOutputResourceCount() const
1341{
1342 return (mLinked ? mState.mOutputVariables.size() : 0);
1343}
1344
1345void Program::getInputResourceName(GLuint index,
1346 GLsizei bufSize,
1347 GLsizei *length,
1348 GLchar *name) const
1349{
1350 GLint size;
1351 GLenum type;
1352 getActiveAttribute(index, bufSize, length, &size, &type, name);
1353}
1354
1355void Program::getOutputResourceName(GLuint index,
1356 GLsizei bufSize,
1357 GLsizei *length,
1358 GLchar *name) const
1359{
1360 if (length)
1361 {
1362 *length = 0;
1363 }
1364
1365 if (!mLinked)
1366 {
1367 if (bufSize > 0)
1368 {
1369 name[0] = '\0';
1370 }
1371 return;
1372 }
1373 ASSERT(index < mState.mOutputVariables.size());
1374 const auto &output = mState.mOutputVariables[index];
1375
1376 if (bufSize > 0)
1377 {
1378 std::string nameWithArray = (output.isArray() ? output.name + "[0]" : output.name);
1379
1380 CopyStringToBuffer(name, nameWithArray, bufSize, length);
1381 }
1382}
1383
Geoff Lang7dd2e102014-11-10 15:19:26 -05001384GLint Program::getFragDataLocation(const std::string &name) const
1385{
1386 std::string baseName(name);
1387 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
jchen1015015f72017-03-16 13:54:21 +08001388 for (auto outputPair : mState.mOutputLocations)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001389 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001390 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001391 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1392 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001393 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001395 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001396 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001397}
1398
Geoff Lange1a27752015-10-05 13:16:04 -04001399void Program::getActiveUniform(GLuint index,
1400 GLsizei bufsize,
1401 GLsizei *length,
1402 GLint *size,
1403 GLenum *type,
1404 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001405{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001406 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001407 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001408 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001409 ASSERT(index < mState.mUniforms.size());
1410 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411
1412 if (bufsize > 0)
1413 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001414 std::string string = uniform.name;
1415 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416 {
1417 string += "[0]";
1418 }
jchen10fd7c3b52017-03-21 15:36:03 +08001419 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001420 }
1421
Jamie Madill62d31cb2015-09-11 13:25:51 -04001422 *size = uniform.elementCount();
1423 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001424 }
1425 else
1426 {
1427 if (bufsize > 0)
1428 {
1429 name[0] = '\0';
1430 }
1431
1432 if (length)
1433 {
1434 *length = 0;
1435 }
1436
1437 *size = 0;
1438 *type = GL_NONE;
1439 }
1440}
1441
Geoff Lange1a27752015-10-05 13:16:04 -04001442GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001443{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001444 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001445 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001446 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001447 }
1448 else
1449 {
1450 return 0;
1451 }
1452}
1453
Geoff Lange1a27752015-10-05 13:16:04 -04001454GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001455{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001456 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001457
1458 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001459 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001460 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001462 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001463 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001464 size_t length = uniform.name.length() + 1u;
1465 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001466 {
1467 length += 3; // Counting in "[0]".
1468 }
1469 maxLength = std::max(length, maxLength);
1470 }
1471 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001472 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473
Jamie Madill62d31cb2015-09-11 13:25:51 -04001474 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001475}
1476
1477GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1478{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001479 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001480 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001482 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001483 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1484 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1485 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1486 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1487 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1488 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1489 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1490 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1491 default:
1492 UNREACHABLE();
1493 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001494 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001495 return 0;
1496}
1497
1498bool Program::isValidUniformLocation(GLint location) const
1499{
Jamie Madille2e406c2016-06-02 13:04:10 -04001500 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001501 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1502 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001503}
1504
Jamie Madill62d31cb2015-09-11 13:25:51 -04001505const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001506{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001507 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001508 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
Jamie Madillac4e9c32017-01-13 14:07:12 -05001511const VariableLocation &Program::getUniformLocation(GLint location) const
1512{
1513 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1514 return mState.mUniformLocations[location];
1515}
1516
1517const std::vector<VariableLocation> &Program::getUniformLocations() const
1518{
1519 return mState.mUniformLocations;
1520}
1521
1522const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1523{
1524 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1525 return mState.mUniforms[index];
1526}
1527
Jamie Madill62d31cb2015-09-11 13:25:51 -04001528GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001529{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001530 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001531}
1532
Jamie Madill62d31cb2015-09-11 13:25:51 -04001533GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001534{
Jamie Madille7d84322017-01-10 18:21:59 -05001535 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001536}
1537
1538void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1539{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001540 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1541 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001542}
1543
1544void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1545{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001546 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1547 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001548}
1549
1550void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1551{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001552 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1553 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001554}
1555
1556void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1557{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001558 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1559 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001560}
1561
1562void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1563{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001564 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1565 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001566}
1567
1568void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1569{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001570 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1571 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001572}
1573
1574void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1575{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001576 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1577 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001578}
1579
1580void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1581{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001582 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1583 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001584}
1585
1586void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1587{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001588 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1589 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001590}
1591
1592void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1593{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001594 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1595 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001596}
1597
1598void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1599{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001600 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1601 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001602}
1603
1604void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1605{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001606 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1607 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001608}
1609
1610void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1611{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001612 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1613 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001614}
1615
1616void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1617{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001618 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1619 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620}
1621
1622void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1623{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001624 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1625 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626}
1627
1628void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1629{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001630 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1631 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001632}
1633
1634void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1635{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001636 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1637 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638}
1639
1640void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1641{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001642 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1643 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001644}
1645
1646void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1647{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001648 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1649 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650}
1651
1652void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1653{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001654 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1655 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656}
1657
1658void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1659{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001660 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1661 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001662}
1663
Geoff Lange1a27752015-10-05 13:16:04 -04001664void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001665{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001666 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001667}
1668
Geoff Lange1a27752015-10-05 13:16:04 -04001669void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001670{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001671 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001672}
1673
Geoff Lange1a27752015-10-05 13:16:04 -04001674void Program::getUniformuiv(GLint location, GLuint *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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001679void Program::flagForDeletion()
1680{
1681 mDeleteStatus = true;
1682}
1683
1684bool Program::isFlaggedForDeletion() const
1685{
1686 return mDeleteStatus;
1687}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001688
Brandon Jones43a53e22014-08-28 16:23:22 -07001689void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001690{
1691 mInfoLog.reset();
1692
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001694 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001695 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001696 }
1697 else
1698 {
Jamie Madillf6113162015-05-07 11:49:21 -04001699 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001700 }
1701}
1702
Geoff Lang7dd2e102014-11-10 15:19:26 -05001703bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1704{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001705 // Skip cache if we're using an infolog, so we get the full error.
1706 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1707 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1708 {
1709 return mCachedValidateSamplersResult.value();
1710 }
1711
1712 if (mTextureUnitTypesCache.empty())
1713 {
1714 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1715 }
1716 else
1717 {
1718 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1719 }
1720
1721 // if any two active samplers in a program are of different types, but refer to the same
1722 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1723 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001724 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001725 {
Jamie Madille7d84322017-01-10 18:21:59 -05001726 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001727
Jamie Madille7d84322017-01-10 18:21:59 -05001728 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001729 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001730 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1731 {
1732 if (infoLog)
1733 {
1734 (*infoLog) << "Sampler uniform (" << textureUnit
1735 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1736 << caps.maxCombinedTextureImageUnits << ")";
1737 }
1738
1739 mCachedValidateSamplersResult = false;
1740 return false;
1741 }
1742
1743 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1744 {
1745 if (textureType != mTextureUnitTypesCache[textureUnit])
1746 {
1747 if (infoLog)
1748 {
1749 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1750 "image unit ("
1751 << textureUnit << ").";
1752 }
1753
1754 mCachedValidateSamplersResult = false;
1755 return false;
1756 }
1757 }
1758 else
1759 {
1760 mTextureUnitTypesCache[textureUnit] = textureType;
1761 }
1762 }
1763 }
1764
1765 mCachedValidateSamplersResult = true;
1766 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001767}
1768
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001769bool Program::isValidated() const
1770{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001771 return mValidated;
1772}
1773
Geoff Lange1a27752015-10-05 13:16:04 -04001774GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001775{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001776 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001777}
1778
1779void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1780{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001781 ASSERT(
1782 uniformBlockIndex <
1783 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001784
Jamie Madill48ef11b2016-04-27 15:21:52 -04001785 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786
1787 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001788 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001789 std::string string = uniformBlock.name;
1790
Jamie Madill62d31cb2015-09-11 13:25:51 -04001791 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001792 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001793 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001794 }
jchen10fd7c3b52017-03-21 15:36:03 +08001795 CopyStringToBuffer(uniformBlockName, string, bufSize, length);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001796 }
1797}
1798
Geoff Lange1a27752015-10-05 13:16:04 -04001799GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001800{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001801 int maxLength = 0;
1802
1803 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001804 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001805 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001806 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1807 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001808 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001809 if (!uniformBlock.name.empty())
1810 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001811 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001812
1813 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001814 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001815
1816 maxLength = std::max(length + arrayLength, maxLength);
1817 }
1818 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001819 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001820
1821 return maxLength;
1822}
1823
Geoff Lange1a27752015-10-05 13:16:04 -04001824GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001825{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001826 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08001827 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001828
Jamie Madill48ef11b2016-04-27 15:21:52 -04001829 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001830 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1831 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001832 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001833 if (uniformBlock.name == baseName)
1834 {
1835 const bool arrayElementZero =
1836 (subscript == GL_INVALID_INDEX &&
1837 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1838 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1839 {
1840 return blockIndex;
1841 }
1842 }
1843 }
1844
1845 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001846}
1847
Jamie Madill62d31cb2015-09-11 13:25:51 -04001848const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001849{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001850 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1851 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001852}
1853
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001854void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1855{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001856 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001857 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001858 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001859}
1860
1861GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1862{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001863 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001864}
1865
1866void Program::resetUniformBlockBindings()
1867{
1868 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1869 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001870 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001871 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001872 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001873}
1874
Geoff Lang48dcae72014-02-05 16:28:24 -05001875void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1876{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001877 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001878 for (GLsizei i = 0; i < count; i++)
1879 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001880 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001881 }
1882
Jamie Madill48ef11b2016-04-27 15:21:52 -04001883 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001884}
1885
1886void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1887{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001888 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001889 {
jchen10a9042d32017-03-17 08:50:45 +08001890 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1891 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1892 std::string varName = var.nameWithArrayIndex();
1893 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001894 if (length)
1895 {
1896 *length = lastNameIdx;
1897 }
1898 if (size)
1899 {
jchen10a9042d32017-03-17 08:50:45 +08001900 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001901 }
1902 if (type)
1903 {
jchen10a9042d32017-03-17 08:50:45 +08001904 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001905 }
1906 if (name)
1907 {
jchen10a9042d32017-03-17 08:50:45 +08001908 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001909 name[lastNameIdx] = '\0';
1910 }
1911 }
1912}
1913
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001914GLsizei Program::getTransformFeedbackVaryingCount() const
1915{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001916 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001917 {
jchen10a9042d32017-03-17 08:50:45 +08001918 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001919 }
1920 else
1921 {
1922 return 0;
1923 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001924}
1925
1926GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1927{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001928 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001929 {
1930 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001931 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001932 {
jchen10a9042d32017-03-17 08:50:45 +08001933 maxSize =
1934 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001935 }
1936
1937 return maxSize;
1938 }
1939 else
1940 {
1941 return 0;
1942 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001943}
1944
1945GLenum Program::getTransformFeedbackBufferMode() const
1946{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001947 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001948}
1949
Jamie Madill192745a2016-12-22 15:58:21 -05001950bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951{
Jamie Madill192745a2016-12-22 15:58:21 -05001952 const Shader *vertexShader = mState.mAttachedVertexShader;
1953 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1954
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001955 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1956
Jamie Madill4cff2472015-08-21 16:53:18 -04001957 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1958 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001959
Sami Väisänen46eaa942016-06-29 10:26:37 +03001960 std::map<GLuint, std::string> staticFragmentInputLocations;
1961
Jamie Madill4cff2472015-08-21 16:53:18 -04001962 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001963 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001964 bool matched = false;
1965
1966 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001967 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001968 {
1969 continue;
1970 }
1971
Jamie Madill4cff2472015-08-21 16:53:18 -04001972 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001973 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001974 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001975 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001976 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001977 if (!linkValidateVaryings(infoLog, output.name, input, output,
1978 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001979 {
1980 return false;
1981 }
1982
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983 matched = true;
1984 break;
1985 }
1986 }
1987
1988 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001989 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001990 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001991 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001992 return false;
1993 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001994
1995 // Check for aliased path rendering input bindings (if any).
1996 // If more than one binding refer statically to the same
1997 // location the link must fail.
1998
1999 if (!output.staticUse)
2000 continue;
2001
2002 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
2003 if (inputBinding == -1)
2004 continue;
2005
2006 const auto it = staticFragmentInputLocations.find(inputBinding);
2007 if (it == std::end(staticFragmentInputLocations))
2008 {
2009 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
2010 }
2011 else
2012 {
2013 infoLog << "Binding for fragment input " << output.name << " conflicts with "
2014 << it->second;
2015 return false;
2016 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017 }
2018
Yuly Novikov817232e2017-02-22 18:36:10 -05002019 if (!linkValidateBuiltInVaryings(infoLog))
2020 {
2021 return false;
2022 }
2023
Jamie Madillada9ecc2015-08-17 12:53:37 -04002024 // TODO(jmadill): verify no unmatched vertex varyings?
2025
Geoff Lang7dd2e102014-11-10 15:19:26 -05002026 return true;
2027}
2028
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00002029bool Program::linkUniforms(InfoLog &infoLog,
2030 const Caps &caps,
2031 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002032{
Olli Etuahob78707c2017-03-09 15:03:11 +00002033 UniformLinker linker(mState);
2034 if (!linker.link(infoLog, caps, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002035 {
2036 return false;
2037 }
2038
Olli Etuahob78707c2017-03-09 15:03:11 +00002039 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002040
Olli Etuaho48fed632017-03-16 12:05:30 +00002041 linkSamplerBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002042
2043 return true;
2044}
2045
Olli Etuaho48fed632017-03-16 12:05:30 +00002046void Program::linkSamplerBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002047{
2048 mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
2049 mState.mSamplerUniformRange.start = mState.mSamplerUniformRange.end;
2050 auto samplerIter = mState.mUniforms.rbegin();
2051 while (samplerIter != mState.mUniforms.rend() && samplerIter->isSampler())
2052 {
2053 --mState.mSamplerUniformRange.start;
2054 ++samplerIter;
2055 }
2056 // If uniform is a sampler type, insert it into the mSamplerBindings array.
2057 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
2058 samplerIndex < mState.mUniforms.size(); ++samplerIndex)
2059 {
2060 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2061 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2062 mState.mSamplerBindings.emplace_back(
2063 SamplerBinding(textureType, samplerUniform.elementCount()));
2064 }
2065}
2066
Martin Radev4c4c8e72016-08-04 12:25:34 +03002067bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2068 const std::string &uniformName,
2069 const sh::InterfaceBlockField &vertexUniform,
2070 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071{
Jamie Madillc4c744222015-11-04 09:39:47 -05002072 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
2073 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002074 {
2075 return false;
2076 }
2077
2078 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2079 {
Jamie Madillf6113162015-05-07 11:49:21 -04002080 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002081 return false;
2082 }
2083
2084 return true;
2085}
2086
Jamie Madilleb979bf2016-11-15 12:28:46 -05002087// Assigns locations to all attributes from the bindings and program locations.
2088bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002089{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002090 const auto *vertexShader = mState.getAttachedVertexShader();
2091
Geoff Lang7dd2e102014-11-10 15:19:26 -05002092 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002093 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002094 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002095
2096 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002097 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002098 {
Jamie Madillf6113162015-05-07 11:49:21 -04002099 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002100 return false;
2101 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002102
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002103 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002104
Jamie Madillc349ec02015-08-21 16:53:12 -04002105 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002106 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002107 {
Jamie Madilleb979bf2016-11-15 12:28:46 -05002108 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002109 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002110 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002111 attribute.location = bindingLocation;
2112 }
2113
2114 if (attribute.location != -1)
2115 {
2116 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002117 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002118
Jamie Madill63805b42015-08-25 13:17:39 -04002119 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002120 {
Jamie Madillf6113162015-05-07 11:49:21 -04002121 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002122 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002123
2124 return false;
2125 }
2126
Jamie Madill63805b42015-08-25 13:17:39 -04002127 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002128 {
Jamie Madill63805b42015-08-25 13:17:39 -04002129 const int regLocation = attribute.location + reg;
2130 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131
2132 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002133 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002134 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002135 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002136 // TODO(jmadill): fix aliasing on ES2
2137 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002138 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002139 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002140 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002141 return false;
2142 }
2143 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002144 else
2145 {
Jamie Madill63805b42015-08-25 13:17:39 -04002146 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002147 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002148
Jamie Madill63805b42015-08-25 13:17:39 -04002149 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002150 }
2151 }
2152 }
2153
2154 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002155 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002156 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002157 // Not set by glBindAttribLocation or by location layout qualifier
2158 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159 {
Jamie Madill63805b42015-08-25 13:17:39 -04002160 int regs = VariableRegisterCount(attribute.type);
2161 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002162
Jamie Madill63805b42015-08-25 13:17:39 -04002163 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002164 {
Jamie Madillf6113162015-05-07 11:49:21 -04002165 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002166 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002167 }
2168
Jamie Madillc349ec02015-08-21 16:53:12 -04002169 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002170 }
2171 }
2172
Jamie Madill48ef11b2016-04-27 15:21:52 -04002173 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 {
Jamie Madill63805b42015-08-25 13:17:39 -04002175 ASSERT(attribute.location != -1);
2176 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002177
Jamie Madill63805b42015-08-25 13:17:39 -04002178 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002179 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002180 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002181 }
2182 }
2183
Geoff Lang7dd2e102014-11-10 15:19:26 -05002184 return true;
2185}
2186
Martin Radev4c4c8e72016-08-04 12:25:34 +03002187bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2188 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2189 const std::string &errorMessage,
2190 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002191{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002192 GLuint blockCount = 0;
2193 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002194 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002195 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002196 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002197 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002198 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002199 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002200 return false;
2201 }
2202 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002203 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002204 return true;
2205}
Jamie Madille473dee2015-08-18 14:49:01 -04002206
Martin Radev4c4c8e72016-08-04 12:25:34 +03002207bool Program::validateVertexAndFragmentInterfaceBlocks(
2208 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2209 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2210 InfoLog &infoLog) const
2211{
2212 // Check that interface blocks defined in the vertex and fragment shaders are identical
2213 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2214 UniformBlockMap linkedUniformBlocks;
2215
2216 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2217 {
2218 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2219 }
2220
Jamie Madille473dee2015-08-18 14:49:01 -04002221 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002222 {
Jamie Madille473dee2015-08-18 14:49:01 -04002223 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002224 if (entry != linkedUniformBlocks.end())
2225 {
2226 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2227 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2228 {
2229 return false;
2230 }
2231 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002232 }
2233 return true;
2234}
Jamie Madille473dee2015-08-18 14:49:01 -04002235
Martin Radev4c4c8e72016-08-04 12:25:34 +03002236bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2237{
2238 if (mState.mAttachedComputeShader)
2239 {
2240 const Shader &computeShader = *mState.mAttachedComputeShader;
2241 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2242
2243 if (!validateUniformBlocksCount(
2244 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2245 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2246 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002247 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002248 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002249 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002250 return true;
2251 }
2252
2253 const Shader &vertexShader = *mState.mAttachedVertexShader;
2254 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2255
2256 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2257 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2258
2259 if (!validateUniformBlocksCount(
2260 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2261 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2262 {
2263 return false;
2264 }
2265 if (!validateUniformBlocksCount(
2266 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2267 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2268 infoLog))
2269 {
2270
2271 return false;
2272 }
2273 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2274 infoLog))
2275 {
2276 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002277 }
Jamie Madille473dee2015-08-18 14:49:01 -04002278
Geoff Lang7dd2e102014-11-10 15:19:26 -05002279 return true;
2280}
2281
Jamie Madilla2c74982016-12-12 11:20:42 -05002282bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002283 const sh::InterfaceBlock &vertexInterfaceBlock,
2284 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002285{
2286 const char* blockName = vertexInterfaceBlock.name.c_str();
2287 // validate blocks for the same member types
2288 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2289 {
Jamie Madillf6113162015-05-07 11:49:21 -04002290 infoLog << "Types for interface block '" << blockName
2291 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002292 return false;
2293 }
2294 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2295 {
Jamie Madillf6113162015-05-07 11:49:21 -04002296 infoLog << "Array sizes differ for interface block '" << blockName
2297 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002298 return false;
2299 }
2300 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2301 {
Jamie Madillf6113162015-05-07 11:49:21 -04002302 infoLog << "Layout qualifiers differ for interface block '" << blockName
2303 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002304 return false;
2305 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002306 const unsigned int numBlockMembers =
2307 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002308 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2309 {
2310 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2311 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2312 if (vertexMember.name != fragmentMember.name)
2313 {
Jamie Madillf6113162015-05-07 11:49:21 -04002314 infoLog << "Name mismatch for field " << blockMemberIndex
2315 << " of interface block '" << blockName
2316 << "': (in vertex: '" << vertexMember.name
2317 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002318 return false;
2319 }
2320 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2321 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2322 {
2323 return false;
2324 }
2325 }
2326 return true;
2327}
2328
2329bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2330 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2331{
2332 if (vertexVariable.type != fragmentVariable.type)
2333 {
Jamie Madillf6113162015-05-07 11:49:21 -04002334 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002335 return false;
2336 }
2337 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2338 {
Jamie Madillf6113162015-05-07 11:49:21 -04002339 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002340 return false;
2341 }
2342 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2343 {
Jamie Madillf6113162015-05-07 11:49:21 -04002344 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002345 return false;
2346 }
2347
2348 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2349 {
Jamie Madillf6113162015-05-07 11:49:21 -04002350 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002351 return false;
2352 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002353 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002354 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2355 {
2356 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2357 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2358
2359 if (vertexMember.name != fragmentMember.name)
2360 {
Jamie Madillf6113162015-05-07 11:49:21 -04002361 infoLog << "Name mismatch for field '" << memberIndex
2362 << "' of " << variableName
2363 << ": (in vertex: '" << vertexMember.name
2364 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002365 return false;
2366 }
2367
2368 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2369 vertexMember.name + "'";
2370
2371 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2372 {
2373 return false;
2374 }
2375 }
2376
2377 return true;
2378}
2379
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002380bool Program::linkValidateVaryings(InfoLog &infoLog,
2381 const std::string &varyingName,
2382 const sh::Varying &vertexVarying,
2383 const sh::Varying &fragmentVarying,
2384 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002385{
2386 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2387 {
2388 return false;
2389 }
2390
Jamie Madille9cc4692015-02-19 16:00:13 -05002391 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002393 infoLog << "Interpolation types for " << varyingName
2394 << " differ between vertex and fragment shaders.";
2395 return false;
2396 }
2397
2398 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2399 {
2400 infoLog << "Invariance for " << varyingName
2401 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002402 return false;
2403 }
2404
2405 return true;
2406}
2407
Yuly Novikov817232e2017-02-22 18:36:10 -05002408bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
2409{
2410 const Shader *vertexShader = mState.mAttachedVertexShader;
2411 const Shader *fragmentShader = mState.mAttachedFragmentShader;
2412 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
2413 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
2414 int shaderVersion = vertexShader->getShaderVersion();
2415
2416 if (shaderVersion != 100)
2417 {
2418 // Only ESSL 1.0 has restrictions on matching input and output invariance
2419 return true;
2420 }
2421
2422 bool glPositionIsInvariant = false;
2423 bool glPointSizeIsInvariant = false;
2424 bool glFragCoordIsInvariant = false;
2425 bool glPointCoordIsInvariant = false;
2426
2427 for (const sh::Varying &varying : vertexVaryings)
2428 {
2429 if (!varying.isBuiltIn())
2430 {
2431 continue;
2432 }
2433 if (varying.name.compare("gl_Position") == 0)
2434 {
2435 glPositionIsInvariant = varying.isInvariant;
2436 }
2437 else if (varying.name.compare("gl_PointSize") == 0)
2438 {
2439 glPointSizeIsInvariant = varying.isInvariant;
2440 }
2441 }
2442
2443 for (const sh::Varying &varying : fragmentVaryings)
2444 {
2445 if (!varying.isBuiltIn())
2446 {
2447 continue;
2448 }
2449 if (varying.name.compare("gl_FragCoord") == 0)
2450 {
2451 glFragCoordIsInvariant = varying.isInvariant;
2452 }
2453 else if (varying.name.compare("gl_PointCoord") == 0)
2454 {
2455 glPointCoordIsInvariant = varying.isInvariant;
2456 }
2457 }
2458
2459 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2460 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2461 // Not requiring invariance to match is supported by:
2462 // dEQP, WebGL CTS, Nexus 5X GLES
2463 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2464 {
2465 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2466 "declared invariant.";
2467 return false;
2468 }
2469 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2470 {
2471 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2472 "declared invariant.";
2473 return false;
2474 }
2475
2476 return true;
2477}
2478
jchen10a9042d32017-03-17 08:50:45 +08002479bool Program::linkValidateTransformFeedback(const gl::Context *context,
2480 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002481 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002482 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002483{
2484 size_t totalComponents = 0;
2485
Jamie Madillccdf74b2015-08-18 10:46:12 -04002486 std::set<std::string> uniqueNames;
2487
Jamie Madill48ef11b2016-04-27 15:21:52 -04002488 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002489 {
2490 bool found = false;
jchen10a9042d32017-03-17 08:50:45 +08002491 size_t subscript = GL_INVALID_INDEX;
2492 std::string baseName = ParseResourceName(tfVaryingName, &subscript);
2493
Jamie Madill192745a2016-12-22 15:58:21 -05002494 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002495 {
Jamie Madill192745a2016-12-22 15:58:21 -05002496 const sh::Varying *varying = ref.second.get();
2497
jchen10a9042d32017-03-17 08:50:45 +08002498 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002499 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002500 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002501 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002502 infoLog << "Two transform feedback varyings specify the same output variable ("
2503 << tfVaryingName << ").";
2504 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002505 }
jchen10a9042d32017-03-17 08:50:45 +08002506 if (context->getClientVersion() >= Version(3, 1))
2507 {
2508 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2509 {
2510 infoLog
2511 << "Two transform feedback varyings include the same array element ("
2512 << tfVaryingName << ").";
2513 return false;
2514 }
2515 }
2516 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002517 {
2518 infoLog << "Capture of arrays is undefined and not supported.";
2519 return false;
2520 }
2521
jchen10a9042d32017-03-17 08:50:45 +08002522 uniqueNames.insert(tfVaryingName);
2523
Jamie Madillccdf74b2015-08-18 10:46:12 -04002524 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002525 size_t elementCount =
2526 ((varying->isArray() && subscript == GL_INVALID_INDEX) ? varying->elementCount()
2527 : 1);
2528 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002529 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002530 componentCount > caps.maxTransformFeedbackSeparateComponents)
2531 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002532 infoLog << "Transform feedback varying's " << varying->name << " components ("
2533 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002534 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002535 return false;
2536 }
2537
2538 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002539 found = true;
2540 break;
2541 }
2542 }
jchen10a9042d32017-03-17 08:50:45 +08002543 if (context->getClientVersion() < Version(3, 1) &&
2544 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002545 {
Geoff Lang1a683462015-09-29 15:09:59 -04002546 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002547 return false;
2548 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002549 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2550 ASSERT(found);
2551 }
2552
Jamie Madill48ef11b2016-04-27 15:21:52 -04002553 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002554 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002555 {
Jamie Madillf6113162015-05-07 11:49:21 -04002556 infoLog << "Transform feedback varying total components (" << totalComponents
2557 << ") exceed the maximum interleaved components ("
2558 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002559 return false;
2560 }
2561
2562 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002563}
2564
Jamie Madill192745a2016-12-22 15:58:21 -05002565void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002566{
2567 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002568 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002569 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002570 {
jchen10a9042d32017-03-17 08:50:45 +08002571 size_t subscript = GL_INVALID_INDEX;
2572 std::string baseName = ParseResourceName(tfVaryingName, &subscript);
Jamie Madill192745a2016-12-22 15:58:21 -05002573 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002574 {
Jamie Madill192745a2016-12-22 15:58:21 -05002575 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002576 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002577 {
jchen10a9042d32017-03-17 08:50:45 +08002578 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2579 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002580 break;
2581 }
2582 }
2583 }
2584}
2585
Jamie Madill192745a2016-12-22 15:58:21 -05002586Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002587{
Jamie Madill192745a2016-12-22 15:58:21 -05002588 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002589
Jamie Madill48ef11b2016-04-27 15:21:52 -04002590 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002591 {
Jamie Madill192745a2016-12-22 15:58:21 -05002592 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002593 }
2594
Jamie Madill48ef11b2016-04-27 15:21:52 -04002595 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002596 {
Jamie Madill192745a2016-12-22 15:58:21 -05002597 merged[varying.name].fragment = &varying;
2598 }
2599
2600 return merged;
2601}
2602
2603std::vector<PackedVarying> Program::getPackedVaryings(
2604 const Program::MergedVaryings &mergedVaryings) const
2605{
2606 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2607 std::vector<PackedVarying> packedVaryings;
jchen10a9042d32017-03-17 08:50:45 +08002608 std::set<std::string> uniqueFullNames;
Jamie Madill192745a2016-12-22 15:58:21 -05002609
2610 for (const auto &ref : mergedVaryings)
2611 {
2612 const sh::Varying *input = ref.second.vertex;
2613 const sh::Varying *output = ref.second.fragment;
2614
2615 // Only pack varyings that have a matched input or output, plus special builtins.
2616 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002617 {
Jamie Madill192745a2016-12-22 15:58:21 -05002618 // Will get the vertex shader interpolation by default.
2619 auto interpolation = ref.second.get()->interpolation;
2620
2621 // Interpolation qualifiers must match.
2622 if (output->isStruct())
2623 {
2624 ASSERT(!output->isArray());
2625 for (const auto &field : output->fields)
2626 {
2627 ASSERT(!field.isStruct() && !field.isArray());
2628 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2629 }
2630 }
2631 else
2632 {
2633 packedVaryings.push_back(PackedVarying(*output, interpolation));
2634 }
2635 continue;
2636 }
2637
2638 // Keep Transform FB varyings in the merged list always.
2639 if (!input)
2640 {
2641 continue;
2642 }
2643
2644 for (const std::string &tfVarying : tfVaryings)
2645 {
jchen10a9042d32017-03-17 08:50:45 +08002646 size_t subscript = GL_INVALID_INDEX;
2647 std::string baseName = ParseResourceName(tfVarying, &subscript);
2648 if (uniqueFullNames.count(tfVarying) > 0)
2649 {
2650 continue;
2651 }
2652 if (baseName == input->name)
Jamie Madill192745a2016-12-22 15:58:21 -05002653 {
2654 // Transform feedback for varying structs is underspecified.
2655 // See Khronos bug 9856.
2656 // TODO(jmadill): Figure out how to be spec-compliant here.
2657 if (!input->isStruct())
2658 {
2659 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2660 packedVaryings.back().vertexOnly = true;
jchen10a9042d32017-03-17 08:50:45 +08002661 packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
2662 uniqueFullNames.insert(tfVarying);
Jamie Madill192745a2016-12-22 15:58:21 -05002663 }
jchen10a9042d32017-03-17 08:50:45 +08002664 if (subscript == GL_INVALID_INDEX)
2665 {
2666 break;
2667 }
Jamie Madill192745a2016-12-22 15:58:21 -05002668 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002669 }
2670 }
2671
Jamie Madill192745a2016-12-22 15:58:21 -05002672 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2673
2674 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002675}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002676
2677void Program::linkOutputVariables()
2678{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002679 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002680 ASSERT(fragmentShader != nullptr);
2681
2682 // Skip this step for GLES2 shaders.
2683 if (fragmentShader->getShaderVersion() == 100)
2684 return;
2685
jchen1015015f72017-03-16 13:54:21 +08002686 mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002687 // TODO(jmadill): any caps validation here?
2688
jchen1015015f72017-03-16 13:54:21 +08002689 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002690 outputVariableIndex++)
2691 {
jchen1015015f72017-03-16 13:54:21 +08002692 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002693
2694 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2695 if (outputVariable.isBuiltIn())
2696 continue;
2697
2698 // Since multiple output locations must be specified, use 0 for non-specified locations.
2699 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2700
Jamie Madill80a6fc02015-08-21 16:53:16 -04002701 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2702 elementIndex++)
2703 {
2704 const int location = baseLocation + elementIndex;
jchen1015015f72017-03-16 13:54:21 +08002705 ASSERT(mState.mOutputLocations.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002706 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08002707 mState.mOutputLocations[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002708 VariableLocation(outputVariable.name, element, outputVariableIndex);
2709 }
2710 }
2711}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002712
Olli Etuaho48fed632017-03-16 12:05:30 +00002713void Program::setUniformValuesFromBindingQualifiers()
2714{
2715 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
2716 samplerIndex < mState.mSamplerUniformRange.end; ++samplerIndex)
2717 {
2718 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2719 if (samplerUniform.binding != -1)
2720 {
2721 GLint location = mState.getUniformLocation(samplerUniform.name);
2722 ASSERT(location != -1);
2723 std::vector<GLint> boundTextureUnits;
2724 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2725 ++elementIndex)
2726 {
2727 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2728 }
2729 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2730 boundTextureUnits.data());
2731 }
2732 }
2733}
2734
Jamie Madill62d31cb2015-09-11 13:25:51 -04002735void Program::gatherInterfaceBlockInfo()
2736{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002737 ASSERT(mState.mUniformBlocks.empty());
2738
2739 if (mState.mAttachedComputeShader)
2740 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002741 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002742
2743 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2744 {
2745
2746 // Only 'packed' blocks are allowed to be considered inactive.
2747 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2748 continue;
2749
Jamie Madilla2c74982016-12-12 11:20:42 -05002750 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002751 {
2752 if (block.name == computeBlock.name)
2753 {
2754 block.computeStaticUse = computeBlock.staticUse;
2755 }
2756 }
2757
2758 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2759 }
2760 return;
2761 }
2762
Jamie Madill62d31cb2015-09-11 13:25:51 -04002763 std::set<std::string> visitedList;
2764
Jamie Madilla2c74982016-12-12 11:20:42 -05002765 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002766
Jamie Madill62d31cb2015-09-11 13:25:51 -04002767 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2768 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002769 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002770 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2771 continue;
2772
2773 if (visitedList.count(vertexBlock.name) > 0)
2774 continue;
2775
2776 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2777 visitedList.insert(vertexBlock.name);
2778 }
2779
Jamie Madilla2c74982016-12-12 11:20:42 -05002780 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002781
2782 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2783 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002784 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002785 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2786 continue;
2787
2788 if (visitedList.count(fragmentBlock.name) > 0)
2789 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002790 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002791 {
2792 if (block.name == fragmentBlock.name)
2793 {
2794 block.fragmentStaticUse = fragmentBlock.staticUse;
2795 }
2796 }
2797
2798 continue;
2799 }
2800
2801 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2802 visitedList.insert(fragmentBlock.name);
2803 }
2804}
2805
Jamie Madill4a3c2342015-10-08 12:58:45 -04002806template <typename VarT>
2807void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2808 const std::string &prefix,
2809 int blockIndex)
2810{
2811 for (const VarT &field : fields)
2812 {
2813 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2814
2815 if (field.isStruct())
2816 {
2817 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2818 {
2819 const std::string uniformElementName =
2820 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2821 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2822 }
2823 }
2824 else
2825 {
2826 // If getBlockMemberInfo returns false, the uniform is optimized out.
2827 sh::BlockMemberInfo memberInfo;
2828 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2829 {
2830 continue;
2831 }
2832
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002833 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04002834 blockIndex, memberInfo);
2835
2836 // Since block uniforms have no location, we don't need to store them in the uniform
2837 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002838 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002839 }
2840 }
2841}
2842
Jamie Madill62d31cb2015-09-11 13:25:51 -04002843void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2844{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002845 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002846 size_t blockSize = 0;
2847
2848 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002849 std::stringstream blockNameStr;
2850 blockNameStr << interfaceBlock.name;
2851 if (interfaceBlock.arraySize > 0)
2852 {
2853 blockNameStr << "[0]";
2854 }
2855 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002856 {
2857 return;
2858 }
2859
2860 // Track the first and last uniform index to determine the range of active uniforms in the
2861 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002862 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002863 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002864 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002865
2866 std::vector<unsigned int> blockUniformIndexes;
2867 for (size_t blockUniformIndex = firstBlockUniformIndex;
2868 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2869 {
2870 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2871 }
2872
2873 if (interfaceBlock.arraySize > 0)
2874 {
2875 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2876 {
2877 UniformBlock block(interfaceBlock.name, true, arrayElement);
2878 block.memberUniformIndexes = blockUniformIndexes;
2879
Martin Radev4c4c8e72016-08-04 12:25:34 +03002880 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002881 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002882 case GL_VERTEX_SHADER:
2883 {
2884 block.vertexStaticUse = interfaceBlock.staticUse;
2885 break;
2886 }
2887 case GL_FRAGMENT_SHADER:
2888 {
2889 block.fragmentStaticUse = interfaceBlock.staticUse;
2890 break;
2891 }
2892 case GL_COMPUTE_SHADER:
2893 {
2894 block.computeStaticUse = interfaceBlock.staticUse;
2895 break;
2896 }
2897 default:
2898 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002899 }
2900
Qin Jiajia0350a642016-11-01 17:01:51 +08002901 // Since all block elements in an array share the same active uniforms, they will all be
2902 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2903 // here we will add every block element in the array.
2904 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002905 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002906 }
2907 }
2908 else
2909 {
2910 UniformBlock block(interfaceBlock.name, false, 0);
2911 block.memberUniformIndexes = blockUniformIndexes;
2912
Martin Radev4c4c8e72016-08-04 12:25:34 +03002913 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002914 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002915 case GL_VERTEX_SHADER:
2916 {
2917 block.vertexStaticUse = interfaceBlock.staticUse;
2918 break;
2919 }
2920 case GL_FRAGMENT_SHADER:
2921 {
2922 block.fragmentStaticUse = interfaceBlock.staticUse;
2923 break;
2924 }
2925 case GL_COMPUTE_SHADER:
2926 {
2927 block.computeStaticUse = interfaceBlock.staticUse;
2928 break;
2929 }
2930 default:
2931 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002932 }
2933
Jamie Madill4a3c2342015-10-08 12:58:45 -04002934 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002935 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002936 }
2937}
2938
Jamie Madille7d84322017-01-10 18:21:59 -05002939template <>
2940void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2941 const uint8_t *destPointer,
2942 GLsizei clampedCount,
2943 const GLint *v)
2944{
2945 // Invalidate the validation cache only if we modify the sampler data.
2946 if (mState.isSamplerUniformIndex(locationInfo.index) &&
2947 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
2948 {
2949 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2950 std::vector<GLuint> *boundTextureUnits =
2951 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
2952
2953 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
2954 mCachedValidateSamplersResult.reset();
2955 }
2956}
2957
2958template <typename T>
2959void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2960 const uint8_t *destPointer,
2961 GLsizei clampedCount,
2962 const T *v)
2963{
2964}
2965
Jamie Madill62d31cb2015-09-11 13:25:51 -04002966template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002967GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002968{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002969 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2970 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002971 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2972
Corentin Wallez15ac5342016-11-03 17:06:39 -04002973 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2974 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2975 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002976 GLsizei maxElementCount =
2977 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2978
2979 GLsizei count = countIn;
2980 GLsizei clampedCount = count * vectorSize;
2981 if (clampedCount > maxElementCount)
2982 {
2983 clampedCount = maxElementCount;
2984 count = maxElementCount / vectorSize;
2985 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002986
Jamie Madill62d31cb2015-09-11 13:25:51 -04002987 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2988 {
2989 // Do a cast conversion for boolean types. From the spec:
2990 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2991 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002992 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002993 {
2994 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2995 }
2996 }
2997 else
2998 {
Jamie Madille7d84322017-01-10 18:21:59 -05002999 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04003000 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003001 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003002
3003 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003004}
3005
3006template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003007GLsizei Program::setMatrixUniformInternal(GLint location,
3008 GLsizei count,
3009 GLboolean transpose,
3010 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003011{
3012 if (!transpose)
3013 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003014 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003015 }
3016
3017 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003018 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3019 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003020 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04003021
3022 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3023 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3024 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
3025 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
3026
3027 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003028 {
3029 size_t elementOffset = element * rows * cols;
3030
3031 for (size_t row = 0; row < rows; ++row)
3032 {
3033 for (size_t col = 0; col < cols; ++col)
3034 {
3035 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
3036 }
3037 }
3038 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003039
3040 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003041}
3042
3043template <typename DestT>
3044void Program::getUniformInternal(GLint location, DestT *dataOut) const
3045{
Jamie Madill48ef11b2016-04-27 15:21:52 -04003046 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3047 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003048
3049 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
3050
3051 GLenum componentType = VariableComponentType(uniform.type);
3052 if (componentType == GLTypeToGLenum<DestT>::value)
3053 {
3054 memcpy(dataOut, srcPointer, uniform.getElementSize());
3055 return;
3056 }
3057
Corentin Wallez6596c462016-03-17 17:26:58 -04003058 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003059
3060 switch (componentType)
3061 {
3062 case GL_INT:
3063 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
3064 break;
3065 case GL_UNSIGNED_INT:
3066 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
3067 break;
3068 case GL_BOOL:
3069 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
3070 break;
3071 case GL_FLOAT:
3072 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
3073 break;
3074 default:
3075 UNREACHABLE();
3076 }
3077}
Jamie Madilla4595b82017-01-11 17:36:34 -05003078
3079bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3080{
3081 // Must be called after samplers are validated.
3082 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3083
3084 for (const auto &binding : mState.mSamplerBindings)
3085 {
3086 GLenum textureType = binding.textureType;
3087 for (const auto &unit : binding.boundTextureUnits)
3088 {
3089 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3090 if (programTextureID == textureID)
3091 {
3092 // TODO(jmadill): Check for appropriate overlap.
3093 return true;
3094 }
3095 }
3096 }
3097
3098 return false;
3099}
3100
Jamie Madilla2c74982016-12-12 11:20:42 -05003101} // namespace gl