blob: e150711bab0a664f01875fd78367088640f57c8b [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"
Olli Etuahod2551232017-10-26 20:03:33 +030017#include "common/string_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "common/utilities.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021#include "libANGLE/MemoryProgramCache.h"
Jamie Madill437d2662014-12-05 14:23:35 -050022#include "libANGLE/ResourceManager.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040023#include "libANGLE/Uniform.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000024#include "libANGLE/UniformLinker.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040025#include "libANGLE/VaryingPacking.h"
26#include "libANGLE/features.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040027#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040028#include "libANGLE/queryconversions.h"
29#include "libANGLE/renderer/GLImplFactory.h"
30#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040031#include "platform/Platform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050032
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033namespace gl
34{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000035
Geoff Lang7dd2e102014-11-10 15:19:26 -050036namespace
37{
38
Jamie Madill62d31cb2015-09-11 13:25:51 -040039// This simplified cast function doesn't need to worry about advanced concepts like
40// depth range values, or casting to bool.
41template <typename DestT, typename SrcT>
42DestT UniformStateQueryCast(SrcT value);
43
44// From-Float-To-Integer Casts
45template <>
46GLint UniformStateQueryCast(GLfloat value)
47{
48 return clampCast<GLint>(roundf(value));
49}
50
51template <>
52GLuint UniformStateQueryCast(GLfloat value)
53{
54 return clampCast<GLuint>(roundf(value));
55}
56
57// From-Integer-to-Integer Casts
58template <>
59GLint UniformStateQueryCast(GLuint value)
60{
61 return clampCast<GLint>(value);
62}
63
64template <>
65GLuint UniformStateQueryCast(GLint value)
66{
67 return clampCast<GLuint>(value);
68}
69
70// From-Boolean-to-Anything Casts
71template <>
72GLfloat UniformStateQueryCast(GLboolean value)
73{
74 return (value == GL_TRUE ? 1.0f : 0.0f);
75}
76
77template <>
78GLint UniformStateQueryCast(GLboolean value)
79{
80 return (value == GL_TRUE ? 1 : 0);
81}
82
83template <>
84GLuint UniformStateQueryCast(GLboolean value)
85{
86 return (value == GL_TRUE ? 1u : 0u);
87}
88
89// Default to static_cast
90template <typename DestT, typename SrcT>
91DestT UniformStateQueryCast(SrcT value)
92{
93 return static_cast<DestT>(value);
94}
95
96template <typename SrcT, typename DestT>
97void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
98{
99 for (int comp = 0; comp < components; ++comp)
100 {
101 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
102 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
103 size_t offset = comp * 4;
104 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
105 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
106 }
107}
108
Jamie Madill192745a2016-12-22 15:58:21 -0500109// true if varying x has a higher priority in packing than y
110bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
111{
jchen10a9042d32017-03-17 08:50:45 +0800112 // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent
113 // non-array shader variable 'vx' or 'vy' for actual comparison instead.
114 sh::ShaderVariable vx, vy;
115 const sh::ShaderVariable *px, *py;
116 if (x.isArrayElement())
117 {
118 vx = *x.varying;
119 vx.arraySize = 0;
120 px = &vx;
121 }
122 else
123 {
124 px = x.varying;
125 }
126
127 if (y.isArrayElement())
128 {
129 vy = *y.varying;
130 vy.arraySize = 0;
131 py = &vy;
132 }
133 else
134 {
135 py = y.varying;
136 }
137
138 return gl::CompareShaderVar(*px, *py);
Jamie Madill192745a2016-12-22 15:58:21 -0500139}
140
jchen1015015f72017-03-16 13:54:21 +0800141template <typename VarT>
142GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
143{
Olli Etuahod2551232017-10-26 20:03:33 +0300144 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800145 for (size_t index = 0; index < list.size(); index++)
146 {
147 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300148 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800149 {
Olli Etuahod2551232017-10-26 20:03:33 +0300150 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800151 }
152 }
153
154 return GL_INVALID_INDEX;
155}
156
Olli Etuahod2551232017-10-26 20:03:33 +0300157template <typename VarT>
158GLint GetVariableLocation(const std::vector<VarT> &list,
159 const std::vector<VariableLocation> &locationList,
160 const std::string &name)
161{
162 size_t nameLengthWithoutArrayIndex;
163 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
164
165 for (size_t location = 0u; location < locationList.size(); ++location)
166 {
167 const VariableLocation &variableLocation = locationList[location];
168 if (!variableLocation.used())
169 {
170 continue;
171 }
172
173 const VarT &variable = list[variableLocation.index];
174
175 if (angle::BeginsWith(variable.name, name))
176 {
177 if (name.length() == variable.name.length())
178 {
179 ASSERT(name == variable.name);
180 // GLES 3.1 November 2016 page 87.
181 // The string exactly matches the name of the active variable.
182 return static_cast<GLint>(location);
183 }
184 if (name.length() + 3u == variable.name.length() && variable.isArray())
185 {
186 ASSERT(name + "[0]" == variable.name);
187 // The string identifies the base name of an active array, where the string would
188 // exactly match the name of the variable if the suffix "[0]" were appended to the
189 // string.
190 return static_cast<GLint>(location);
191 }
192 }
193 if (variable.isArray() && variableLocation.arrayIndices[0] == arrayIndex &&
194 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
195 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
196 {
197 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
198 // The string identifies an active element of the array, where the string ends with the
199 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
200 // zeroes, or whitespace) identifying an array element, and the "]" character, the
201 // integer is less than the number of active elements of the array variable, and where
202 // the string would exactly match the enumerated name of the array if the decimal
203 // integer were replaced with zero.
204 return static_cast<GLint>(location);
205 }
206 }
207
208 return -1;
209}
210
jchen10fd7c3b52017-03-21 15:36:03 +0800211void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
212{
213 ASSERT(bufSize > 0);
214 strncpy(buffer, string.c_str(), bufSize);
215 buffer[bufSize - 1] = '\0';
216
217 if (length)
218 {
219 *length = static_cast<GLsizei>(strlen(buffer));
220 }
221}
222
jchen10a9042d32017-03-17 08:50:45 +0800223bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
224{
Olli Etuahoc8538042017-09-27 11:20:15 +0300225 std::vector<unsigned int> subscripts;
226 std::string baseName = ParseResourceName(name, &subscripts);
227 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800228 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300229 std::vector<unsigned int> arrayIndices;
230 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
231 if (baseName == arrayName &&
232 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800233 {
234 return true;
235 }
236 }
237 return false;
238}
239
Jiajia Qin729b2c62017-08-14 09:36:11 +0800240bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
241 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
242 const std::string &errorMessage,
243 InfoLog &infoLog)
244{
245 GLuint blockCount = 0;
246 for (const sh::InterfaceBlock &block : interfaceBlocks)
247 {
248 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
249 {
250 blockCount += (block.arraySize ? block.arraySize : 1);
251 if (blockCount > maxInterfaceBlocks)
252 {
253 infoLog << errorMessage << maxInterfaceBlocks << ")";
254 return false;
255 }
256 }
257 }
258 return true;
259}
260
Jamie Madillc9727f32017-11-07 12:37:07 -0500261void InitUniformBlockLinker(const gl::Context *context,
262 const ProgramState &state,
263 UniformBlockLinker *blockLinker)
264{
265 if (state.getAttachedVertexShader())
266 {
267 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
268 &state.getAttachedVertexShader()->getUniformBlocks(context));
269 }
270
271 if (state.getAttachedFragmentShader())
272 {
273 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
274 &state.getAttachedFragmentShader()->getUniformBlocks(context));
275 }
276
277 if (state.getAttachedComputeShader())
278 {
279 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
280 &state.getAttachedComputeShader()->getUniformBlocks(context));
281 }
282}
283
284void InitShaderStorageBlockLinker(const gl::Context *context,
285 const ProgramState &state,
286 ShaderStorageBlockLinker *blockLinker)
287{
288 if (state.getAttachedVertexShader())
289 {
290 blockLinker->addShaderBlocks(
291 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
292 }
293
294 if (state.getAttachedFragmentShader())
295 {
296 blockLinker->addShaderBlocks(
297 GL_FRAGMENT_SHADER,
298 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
299 }
300
301 if (state.getAttachedComputeShader())
302 {
303 blockLinker->addShaderBlocks(
304 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
305 }
306}
307
Jamie Madill62d31cb2015-09-11 13:25:51 -0400308} // anonymous namespace
309
Jamie Madill4a3c2342015-10-08 12:58:45 -0400310const char *const g_fakepath = "C:\\fakepath";
311
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400312InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000313{
314}
315
316InfoLog::~InfoLog()
317{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000318}
319
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400320size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000321{
Jamie Madill23176ce2017-07-31 14:14:33 -0400322 if (!mLazyStream)
323 {
324 return 0;
325 }
326
327 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400328 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000329}
330
Geoff Lange1a27752015-10-05 13:16:04 -0400331void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000332{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400333 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000334
335 if (bufSize > 0)
336 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400337 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400338
Jamie Madill23176ce2017-07-31 14:14:33 -0400339 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000340 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400341 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
342 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000343 }
344
345 infoLog[index] = '\0';
346 }
347
348 if (length)
349 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400350 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000351 }
352}
353
354// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300355// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356// messages, so lets remove all occurrences of this fake file path from the log.
357void InfoLog::appendSanitized(const char *message)
358{
Jamie Madill23176ce2017-07-31 14:14:33 -0400359 ensureInitialized();
360
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000361 std::string msg(message);
362
363 size_t found;
364 do
365 {
366 found = msg.find(g_fakepath);
367 if (found != std::string::npos)
368 {
369 msg.erase(found, strlen(g_fakepath));
370 }
371 }
372 while (found != std::string::npos);
373
Jamie Madill23176ce2017-07-31 14:14:33 -0400374 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000375}
376
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000377void InfoLog::reset()
378{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000379}
380
Olli Etuahoc8538042017-09-27 11:20:15 +0300381VariableLocation::VariableLocation() : index(kUnused), flattenedArrayOffset(0u), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000382{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500383}
384
Olli Etuahoc8538042017-09-27 11:20:15 +0300385VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
386 : arrayIndices(1, arrayIndex), index(index), flattenedArrayOffset(arrayIndex), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500387{
Olli Etuahoc8538042017-09-27 11:20:15 +0300388 ASSERT(arrayIndex != GL_INVALID_INDEX);
389}
390
391bool VariableLocation::areAllArrayIndicesZero() const
392{
393 for (unsigned int arrayIndex : arrayIndices)
394 {
395 if (arrayIndex != 0)
396 {
397 return false;
398 }
399 }
400 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500401}
402
Geoff Langd8605522016-04-13 10:19:12 -0400403void Program::Bindings::bindLocation(GLuint index, const std::string &name)
404{
405 mBindings[name] = index;
406}
407
408int Program::Bindings::getBinding(const std::string &name) const
409{
410 auto iter = mBindings.find(name);
411 return (iter != mBindings.end()) ? iter->second : -1;
412}
413
414Program::Bindings::const_iterator Program::Bindings::begin() const
415{
416 return mBindings.begin();
417}
418
419Program::Bindings::const_iterator Program::Bindings::end() const
420{
421 return mBindings.end();
422}
423
Jamie Madill48ef11b2016-04-27 15:21:52 -0400424ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500425 : mLabel(),
426 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400427 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300428 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500429 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400430 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500431 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800432 mImageUniformRange(0, 0),
433 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300434 mBinaryRetrieveableHint(false),
435 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400436{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300437 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400438}
439
Jamie Madill48ef11b2016-04-27 15:21:52 -0400440ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400441{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500442 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400443}
444
Jamie Madill48ef11b2016-04-27 15:21:52 -0400445const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500446{
447 return mLabel;
448}
449
Jamie Madille7d84322017-01-10 18:21:59 -0500450GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400451{
jchen1015015f72017-03-16 13:54:21 +0800452 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400453}
454
Jamie Madille7d84322017-01-10 18:21:59 -0500455GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
456{
457 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
458 return mUniformLocations[location].index;
459}
460
461Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
462{
463 GLuint index = getUniformIndexFromLocation(location);
464 if (!isSamplerUniformIndex(index))
465 {
466 return Optional<GLuint>::Invalid();
467 }
468
469 return getSamplerIndexFromUniformIndex(index);
470}
471
472bool ProgramState::isSamplerUniformIndex(GLuint index) const
473{
Jamie Madill982f6e02017-06-07 14:33:04 -0400474 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500475}
476
477GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
478{
479 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400480 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500481}
482
Jamie Madill34ca4f52017-06-13 11:49:39 -0400483GLuint ProgramState::getAttributeLocation(const std::string &name) const
484{
485 for (const sh::Attribute &attribute : mAttributes)
486 {
487 if (attribute.name == name)
488 {
489 return attribute.location;
490 }
491 }
492
493 return static_cast<GLuint>(-1);
494}
495
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500496Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400497 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400498 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500499 mLinked(false),
500 mDeleteStatus(false),
501 mRefCount(0),
502 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500503 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500504{
505 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000506
Geoff Lang7dd2e102014-11-10 15:19:26 -0500507 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508}
509
510Program::~Program()
511{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400512 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513}
514
Jamie Madill4928b7c2017-06-20 12:57:39 -0400515void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500516{
517 if (mState.mAttachedVertexShader != nullptr)
518 {
519 mState.mAttachedVertexShader->release(context);
520 mState.mAttachedVertexShader = nullptr;
521 }
522
523 if (mState.mAttachedFragmentShader != nullptr)
524 {
525 mState.mAttachedFragmentShader->release(context);
526 mState.mAttachedFragmentShader = nullptr;
527 }
528
529 if (mState.mAttachedComputeShader != nullptr)
530 {
531 mState.mAttachedComputeShader->release(context);
532 mState.mAttachedComputeShader = nullptr;
533 }
534
Jamie Madillc564c072017-06-01 12:45:42 -0400535 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400536
537 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
538 !mState.mAttachedComputeShader);
539 SafeDelete(mProgram);
540
541 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500542}
543
Geoff Lang70d0f492015-12-10 17:45:46 -0500544void Program::setLabel(const std::string &label)
545{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400546 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500547}
548
549const std::string &Program::getLabel() const
550{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400551 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500552}
553
Jamie Madillef300b12016-10-07 15:12:09 -0400554void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000555{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300556 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300558 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000559 {
Jamie Madillef300b12016-10-07 15:12:09 -0400560 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300561 mState.mAttachedVertexShader = shader;
562 mState.mAttachedVertexShader->addRef();
563 break;
564 }
565 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000566 {
Jamie Madillef300b12016-10-07 15:12:09 -0400567 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300568 mState.mAttachedFragmentShader = shader;
569 mState.mAttachedFragmentShader->addRef();
570 break;
571 }
572 case GL_COMPUTE_SHADER:
573 {
Jamie Madillef300b12016-10-07 15:12:09 -0400574 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300575 mState.mAttachedComputeShader = shader;
576 mState.mAttachedComputeShader->addRef();
577 break;
578 }
579 default:
580 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000581 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000582}
583
Jamie Madillc1d770e2017-04-13 17:31:24 -0400584void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000585{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300586 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000587 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300588 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000589 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400590 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500591 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300592 mState.mAttachedVertexShader = nullptr;
593 break;
594 }
595 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400597 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500598 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300599 mState.mAttachedFragmentShader = nullptr;
600 break;
601 }
602 case GL_COMPUTE_SHADER:
603 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400604 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500605 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300606 mState.mAttachedComputeShader = nullptr;
607 break;
608 }
609 default:
610 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612}
613
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000614int Program::getAttachedShadersCount() const
615{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300616 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
617 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000618}
619
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620void Program::bindAttributeLocation(GLuint index, const char *name)
621{
Geoff Langd8605522016-04-13 10:19:12 -0400622 mAttributeBindings.bindLocation(index, name);
623}
624
625void Program::bindUniformLocation(GLuint index, const char *name)
626{
Olli Etuahod2551232017-10-26 20:03:33 +0300627 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628}
629
Sami Väisänen46eaa942016-06-29 10:26:37 +0300630void Program::bindFragmentInputLocation(GLint index, const char *name)
631{
632 mFragmentInputBindings.bindLocation(index, name);
633}
634
Jamie Madillbd044ed2017-06-05 12:59:21 -0400635BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300636{
637 BindingInfo ret;
638 ret.type = GL_NONE;
639 ret.valid = false;
640
Jamie Madillbd044ed2017-06-05 12:59:21 -0400641 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300642 ASSERT(fragmentShader);
643
644 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800645 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300646
647 for (const auto &binding : mFragmentInputBindings)
648 {
649 if (binding.second != static_cast<GLuint>(index))
650 continue;
651
652 ret.valid = true;
653
Olli Etuahod2551232017-10-26 20:03:33 +0300654 size_t nameLengthWithoutArrayIndex;
655 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300656
657 for (const auto &in : inputs)
658 {
Olli Etuahod2551232017-10-26 20:03:33 +0300659 if (in.name.length() == nameLengthWithoutArrayIndex &&
660 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300661 {
662 if (in.isArray())
663 {
664 // The client wants to bind either "name" or "name[0]".
665 // GL ES 3.1 spec refers to active array names with language such as:
666 // "if the string identifies the base name of an active array, where the
667 // string would exactly match the name of the variable if the suffix "[0]"
668 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400669 if (arrayIndex == GL_INVALID_INDEX)
670 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300671
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400672 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300673 }
674 else
675 {
676 ret.name = in.mappedName;
677 }
678 ret.type = in.type;
679 return ret;
680 }
681 }
682 }
683
684 return ret;
685}
686
Jamie Madillbd044ed2017-06-05 12:59:21 -0400687void Program::pathFragmentInputGen(const Context *context,
688 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300689 GLenum genMode,
690 GLint components,
691 const GLfloat *coeffs)
692{
693 // If the location is -1 then the command is silently ignored
694 if (index == -1)
695 return;
696
Jamie Madillbd044ed2017-06-05 12:59:21 -0400697 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300698
699 // If the input doesn't exist then then the command is silently ignored
700 // This could happen through optimization for example, the shader translator
701 // decides that a variable is not actually being used and optimizes it away.
702 if (binding.name.empty())
703 return;
704
705 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
706}
707
Martin Radev4c4c8e72016-08-04 12:25:34 +0300708// The attached shaders are checked for linking errors by matching up their variables.
709// Uniform, input and output variables get collected.
710// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500711Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000712{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500713 const auto &data = context->getContextState();
714
Jamie Madill6c58b062017-08-01 13:44:25 -0400715 auto *platform = ANGLEPlatformCurrent();
716 double startTime = platform->currentTime(platform);
717
Jamie Madill6c1f6712017-02-14 19:08:04 -0500718 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000719
Jamie Madill32447362017-06-28 14:53:52 -0400720 ProgramHash programHash;
721 auto *cache = context->getMemoryProgramCache();
722 if (cache)
723 {
724 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400725 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400726 }
727
728 if (mLinked)
729 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400730 double delta = platform->currentTime(platform) - startTime;
731 int us = static_cast<int>(delta * 1000000.0);
732 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400733 return NoError();
734 }
735
736 // Cache load failed, fall through to normal linking.
737 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000738 mInfoLog.reset();
739
Martin Radev4c4c8e72016-08-04 12:25:34 +0300740 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500741
Jamie Madill192745a2016-12-22 15:58:21 -0500742 auto vertexShader = mState.mAttachedVertexShader;
743 auto fragmentShader = mState.mAttachedFragmentShader;
744 auto computeShader = mState.mAttachedComputeShader;
745
746 bool isComputeShaderAttached = (computeShader != nullptr);
747 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300748 // Check whether we both have a compute and non-compute shaders attached.
749 // If there are of both types attached, then linking should fail.
750 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
751 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300753 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
754 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400755 }
756
Jamie Madill192745a2016-12-22 15:58:21 -0500757 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500758 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400759 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300760 {
761 mInfoLog << "Attached compute shader is not compiled.";
762 return NoError();
763 }
Jamie Madill192745a2016-12-22 15:58:21 -0500764 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300765
Jamie Madillbd044ed2017-06-05 12:59:21 -0400766 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300767
768 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
769 // If the work group size is not specified, a link time error should occur.
770 if (!mState.mComputeShaderLocalSize.isDeclared())
771 {
772 mInfoLog << "Work group size is not specified.";
773 return NoError();
774 }
775
Jamie Madillbd044ed2017-06-05 12:59:21 -0400776 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300777 {
778 return NoError();
779 }
780
Jiajia Qin729b2c62017-08-14 09:36:11 +0800781 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300782 {
783 return NoError();
784 }
785
Jamie Madillc9727f32017-11-07 12:37:07 -0500786 ProgramLinkedResources resources = {{0, PackMode::ANGLE_RELAXED},
787 {&mState.mUniformBlocks, &mState.mUniforms},
788 {&mState.mShaderStorageBlocks}};
789
790 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
791 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
792
793 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500794 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300795 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500796 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300797 }
798 }
799 else
800 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400801 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300802 {
803 return NoError();
804 }
Jamie Madill192745a2016-12-22 15:58:21 -0500805 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300806
Jamie Madillbd044ed2017-06-05 12:59:21 -0400807 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300808 {
809 return NoError();
810 }
Jamie Madill192745a2016-12-22 15:58:21 -0500811 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300812
Jamie Madillbd044ed2017-06-05 12:59:21 -0400813 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300814 {
815 mInfoLog << "Fragment shader version does not match vertex shader version.";
816 return NoError();
817 }
818
Jamie Madillbd044ed2017-06-05 12:59:21 -0400819 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300820 {
821 return NoError();
822 }
823
Jamie Madillbd044ed2017-06-05 12:59:21 -0400824 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300825 {
826 return NoError();
827 }
828
Jamie Madillbd044ed2017-06-05 12:59:21 -0400829 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300830 {
831 return NoError();
832 }
833
Jiajia Qin729b2c62017-08-14 09:36:11 +0800834 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300835 {
836 return NoError();
837 }
838
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400839 if (!linkValidateGlobalNames(context, mInfoLog))
840 {
841 return NoError();
842 }
843
Jamie Madillbd044ed2017-06-05 12:59:21 -0400844 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300845
Martin Radev7cf61662017-07-26 17:10:53 +0300846 mState.mNumViews = vertexShader->getNumViews(context);
847
Jamie Madillbd044ed2017-06-05 12:59:21 -0400848 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300849
Jamie Madill192745a2016-12-22 15:58:21 -0500850 // Validate we can pack the varyings.
851 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
852
853 // Map the varyings to the register file
854 // In WebGL, we use a slightly different handling for packing variables.
855 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
856 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500857
858 ProgramLinkedResources resources = {{data.getCaps().maxVaryingVectors, packMode},
859 {&mState.mUniformBlocks, &mState.mUniforms},
860 {&mState.mShaderStorageBlocks}};
861
862 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
863 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
864
865 if (!resources.varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
866 mState.getTransformFeedbackVaryingNames()))
Jamie Madill192745a2016-12-22 15:58:21 -0500867 {
868 return NoError();
869 }
870
Olli Etuaho39e78122017-08-29 14:34:22 +0300871 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
872 {
873 return NoError();
874 }
875
Jamie Madillc9727f32017-11-07 12:37:07 -0500876 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500877 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300878 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500879 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300880 }
881
882 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500883 }
884
jchen10eaef1e52017-06-13 10:44:11 +0800885 gatherAtomicCounterBuffers();
Jamie Madillbd044ed2017-06-05 12:59:21 -0400886 gatherInterfaceBlockInfo(context);
Jamie Madillccdf74b2015-08-18 10:46:12 -0400887
jchen10eaef1e52017-06-13 10:44:11 +0800888 setUniformValuesFromBindingQualifiers();
889
Jamie Madill54164b02017-08-28 15:17:37 -0400890 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400891 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400892
Jamie Madill32447362017-06-28 14:53:52 -0400893 // Save to the program cache.
894 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
895 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
896 {
897 cache->putProgram(programHash, context, this);
898 }
899
Jamie Madill6c58b062017-08-01 13:44:25 -0400900 double delta = platform->currentTime(platform) - startTime;
901 int us = static_cast<int>(delta * 1000000.0);
902 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
903
Martin Radev4c4c8e72016-08-04 12:25:34 +0300904 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000905}
906
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000907// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500908void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000909{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400910 mState.mAttributes.clear();
911 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -0400912 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +0800913 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400914 mState.mUniforms.clear();
915 mState.mUniformLocations.clear();
916 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +0800917 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +0800918 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400919 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800920 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -0400921 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -0400922 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300923 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500924 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +0800925 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +0300926 mState.mNumViews = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500927
Geoff Lang7dd2e102014-11-10 15:19:26 -0500928 mValidated = false;
929
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000930 mLinked = false;
931}
932
Geoff Lange1a27752015-10-05 13:16:04 -0400933bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000934{
935 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936}
937
Jamie Madilla2c74982016-12-12 11:20:42 -0500938Error Program::loadBinary(const Context *context,
939 GLenum binaryFormat,
940 const void *binary,
941 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000942{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500943 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000944
Geoff Lang7dd2e102014-11-10 15:19:26 -0500945#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800946 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500947#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400948 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
949 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000950 {
Jamie Madillf6113162015-05-07 11:49:21 -0400951 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800952 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500953 }
954
Jamie Madill4f86d052017-06-05 12:59:26 -0400955 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
956 ANGLE_TRY_RESULT(
957 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400958
959 // Currently we require the full shader text to compute the program hash.
960 // TODO(jmadill): Store the binary in the internal program cache.
961
Jamie Madillb0a838b2016-11-13 20:02:12 -0500962 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500963#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500964}
965
Jamie Madilla2c74982016-12-12 11:20:42 -0500966Error Program::saveBinary(const Context *context,
967 GLenum *binaryFormat,
968 void *binary,
969 GLsizei bufSize,
970 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500971{
972 if (binaryFormat)
973 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400974 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500975 }
976
Jamie Madill4f86d052017-06-05 12:59:26 -0400977 angle::MemoryBuffer memoryBuf;
978 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500979
Jamie Madill4f86d052017-06-05 12:59:26 -0400980 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
981 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500982
983 if (streamLength > bufSize)
984 {
985 if (length)
986 {
987 *length = 0;
988 }
989
990 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
991 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
992 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500993 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500994 }
995
996 if (binary)
997 {
998 char *ptr = reinterpret_cast<char*>(binary);
999
Jamie Madill48ef11b2016-04-27 15:21:52 -04001000 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001 ptr += streamLength;
1002
1003 ASSERT(ptr - streamLength == binary);
1004 }
1005
1006 if (length)
1007 {
1008 *length = streamLength;
1009 }
1010
He Yunchaoacd18982017-01-04 10:46:42 +08001011 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001012}
1013
Jamie Madillffe00c02017-06-27 16:26:55 -04001014GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001015{
1016 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001017 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001018 if (error.isError())
1019 {
1020 return 0;
1021 }
1022
1023 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001024}
1025
Geoff Langc5629752015-12-07 16:29:04 -05001026void Program::setBinaryRetrievableHint(bool retrievable)
1027{
1028 // TODO(jmadill) : replace with dirty bits
1029 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001030 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001031}
1032
1033bool Program::getBinaryRetrievableHint() const
1034{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001035 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001036}
1037
Yunchao He61afff12017-03-14 15:34:03 +08001038void Program::setSeparable(bool separable)
1039{
1040 // TODO(yunchao) : replace with dirty bits
1041 if (mState.mSeparable != separable)
1042 {
1043 mProgram->setSeparable(separable);
1044 mState.mSeparable = separable;
1045 }
1046}
1047
1048bool Program::isSeparable() const
1049{
1050 return mState.mSeparable;
1051}
1052
Jamie Madill6c1f6712017-02-14 19:08:04 -05001053void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001054{
1055 mRefCount--;
1056
1057 if (mRefCount == 0 && mDeleteStatus)
1058 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001059 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001060 }
1061}
1062
1063void Program::addRef()
1064{
1065 mRefCount++;
1066}
1067
1068unsigned int Program::getRefCount() const
1069{
1070 return mRefCount;
1071}
1072
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001073int Program::getInfoLogLength() const
1074{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001075 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001076}
1077
Geoff Lange1a27752015-10-05 13:16:04 -04001078void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001079{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001080 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001081}
1082
Geoff Lange1a27752015-10-05 13:16:04 -04001083void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001084{
1085 int total = 0;
1086
Martin Radev4c4c8e72016-08-04 12:25:34 +03001087 if (mState.mAttachedComputeShader)
1088 {
1089 if (total < maxCount)
1090 {
1091 shaders[total] = mState.mAttachedComputeShader->getHandle();
1092 total++;
1093 }
1094 }
1095
Jamie Madill48ef11b2016-04-27 15:21:52 -04001096 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001097 {
1098 if (total < maxCount)
1099 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001100 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001101 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001102 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001103 }
1104
Jamie Madill48ef11b2016-04-27 15:21:52 -04001105 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001106 {
1107 if (total < maxCount)
1108 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001109 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001110 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001111 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001112 }
1113
1114 if (count)
1115 {
1116 *count = total;
1117 }
1118}
1119
Geoff Lange1a27752015-10-05 13:16:04 -04001120GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001121{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001122 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001123}
1124
Jamie Madill63805b42015-08-25 13:17:39 -04001125bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001126{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001127 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1128 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001129}
1130
jchen10fd7c3b52017-03-21 15:36:03 +08001131void Program::getActiveAttribute(GLuint index,
1132 GLsizei bufsize,
1133 GLsizei *length,
1134 GLint *size,
1135 GLenum *type,
1136 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001137{
Jamie Madillc349ec02015-08-21 16:53:12 -04001138 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001139 {
1140 if (bufsize > 0)
1141 {
1142 name[0] = '\0';
1143 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001144
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001145 if (length)
1146 {
1147 *length = 0;
1148 }
1149
1150 *type = GL_NONE;
1151 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001152 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001153 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001154
jchen1036e120e2017-03-14 14:53:58 +08001155 ASSERT(index < mState.mAttributes.size());
1156 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001157
1158 if (bufsize > 0)
1159 {
jchen10fd7c3b52017-03-21 15:36:03 +08001160 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001161 }
1162
1163 // Always a single 'type' instance
1164 *size = 1;
1165 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001166}
1167
Geoff Lange1a27752015-10-05 13:16:04 -04001168GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001169{
Jamie Madillc349ec02015-08-21 16:53:12 -04001170 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001171 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001172 return 0;
1173 }
1174
jchen1036e120e2017-03-14 14:53:58 +08001175 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001176}
1177
Geoff Lange1a27752015-10-05 13:16:04 -04001178GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001179{
Jamie Madillc349ec02015-08-21 16:53:12 -04001180 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001181 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001182 return 0;
1183 }
1184
1185 size_t maxLength = 0;
1186
Jamie Madill48ef11b2016-04-27 15:21:52 -04001187 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001188 {
jchen1036e120e2017-03-14 14:53:58 +08001189 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001190 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001191
Jamie Madillc349ec02015-08-21 16:53:12 -04001192 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001193}
1194
jchen1015015f72017-03-16 13:54:21 +08001195GLuint Program::getInputResourceIndex(const GLchar *name) const
1196{
Olli Etuahod2551232017-10-26 20:03:33 +03001197 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001198}
1199
1200GLuint Program::getOutputResourceIndex(const GLchar *name) const
1201{
1202 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1203}
1204
jchen10fd7c3b52017-03-21 15:36:03 +08001205size_t Program::getOutputResourceCount() const
1206{
1207 return (mLinked ? mState.mOutputVariables.size() : 0);
1208}
1209
jchen10baf5d942017-08-28 20:45:48 +08001210template <typename T>
1211void Program::getResourceName(GLuint index,
1212 const std::vector<T> &resources,
1213 GLsizei bufSize,
1214 GLsizei *length,
1215 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001216{
1217 if (length)
1218 {
1219 *length = 0;
1220 }
1221
1222 if (!mLinked)
1223 {
1224 if (bufSize > 0)
1225 {
1226 name[0] = '\0';
1227 }
1228 return;
1229 }
jchen10baf5d942017-08-28 20:45:48 +08001230 ASSERT(index < resources.size());
1231 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001232
1233 if (bufSize > 0)
1234 {
Olli Etuahod2551232017-10-26 20:03:33 +03001235 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001236 }
1237}
1238
jchen10baf5d942017-08-28 20:45:48 +08001239void Program::getInputResourceName(GLuint index,
1240 GLsizei bufSize,
1241 GLsizei *length,
1242 GLchar *name) const
1243{
1244 getResourceName(index, mState.mAttributes, bufSize, length, name);
1245}
1246
1247void Program::getOutputResourceName(GLuint index,
1248 GLsizei bufSize,
1249 GLsizei *length,
1250 GLchar *name) const
1251{
1252 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1253}
1254
1255void Program::getUniformResourceName(GLuint index,
1256 GLsizei bufSize,
1257 GLsizei *length,
1258 GLchar *name) const
1259{
1260 getResourceName(index, mState.mUniforms, bufSize, length, name);
1261}
1262
jchen10880683b2017-04-12 16:21:55 +08001263const sh::Attribute &Program::getInputResource(GLuint index) const
1264{
1265 ASSERT(index < mState.mAttributes.size());
1266 return mState.mAttributes[index];
1267}
1268
1269const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1270{
1271 ASSERT(index < mState.mOutputVariables.size());
1272 return mState.mOutputVariables[index];
1273}
1274
Geoff Lang7dd2e102014-11-10 15:19:26 -05001275GLint Program::getFragDataLocation(const std::string &name) const
1276{
Olli Etuahod2551232017-10-26 20:03:33 +03001277 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001278}
1279
Geoff Lange1a27752015-10-05 13:16:04 -04001280void Program::getActiveUniform(GLuint index,
1281 GLsizei bufsize,
1282 GLsizei *length,
1283 GLint *size,
1284 GLenum *type,
1285 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001286{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001287 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001288 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001289 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001290 ASSERT(index < mState.mUniforms.size());
1291 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001292
1293 if (bufsize > 0)
1294 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001295 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001296 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001297 }
1298
Jamie Madill62d31cb2015-09-11 13:25:51 -04001299 *size = uniform.elementCount();
1300 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001301 }
1302 else
1303 {
1304 if (bufsize > 0)
1305 {
1306 name[0] = '\0';
1307 }
1308
1309 if (length)
1310 {
1311 *length = 0;
1312 }
1313
1314 *size = 0;
1315 *type = GL_NONE;
1316 }
1317}
1318
Geoff Lange1a27752015-10-05 13:16:04 -04001319GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001320{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001321 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001322 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001323 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001324 }
1325 else
1326 {
1327 return 0;
1328 }
1329}
1330
Geoff Lange1a27752015-10-05 13:16:04 -04001331GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001332{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001333 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001334
1335 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001336 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001337 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001338 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001339 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001340 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001341 size_t length = uniform.name.length() + 1u;
1342 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001343 {
1344 length += 3; // Counting in "[0]".
1345 }
1346 maxLength = std::max(length, maxLength);
1347 }
1348 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001349 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001350
Jamie Madill62d31cb2015-09-11 13:25:51 -04001351 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001352}
1353
Geoff Lang7dd2e102014-11-10 15:19:26 -05001354bool Program::isValidUniformLocation(GLint location) const
1355{
Jamie Madille2e406c2016-06-02 13:04:10 -04001356 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001357 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001358 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001359}
1360
Jamie Madill62d31cb2015-09-11 13:25:51 -04001361const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001362{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001363 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001364 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001365}
1366
Jamie Madillac4e9c32017-01-13 14:07:12 -05001367const VariableLocation &Program::getUniformLocation(GLint location) const
1368{
1369 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1370 return mState.mUniformLocations[location];
1371}
1372
1373const std::vector<VariableLocation> &Program::getUniformLocations() const
1374{
1375 return mState.mUniformLocations;
1376}
1377
1378const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1379{
1380 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1381 return mState.mUniforms[index];
1382}
1383
Jamie Madill62d31cb2015-09-11 13:25:51 -04001384GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385{
Olli Etuahod2551232017-10-26 20:03:33 +03001386 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387}
1388
Jamie Madill62d31cb2015-09-11 13:25:51 -04001389GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390{
Jamie Madille7d84322017-01-10 18:21:59 -05001391 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392}
1393
1394void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1395{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001396 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1397 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001398 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399}
1400
1401void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1402{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001403 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1404 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001405 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001406}
1407
1408void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1409{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001410 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1411 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001412 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001413}
1414
1415void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1416{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001417 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1418 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001419 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001420}
1421
Jamie Madill81c2e252017-09-09 23:32:46 -04001422Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001423{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001424 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1425 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1426
Jamie Madill81c2e252017-09-09 23:32:46 -04001427 mProgram->setUniform1iv(location, clampedCount, v);
1428
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001429 if (mState.isSamplerUniformIndex(locationInfo.index))
1430 {
1431 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001432 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001433 }
1434
Jamie Madill81c2e252017-09-09 23:32:46 -04001435 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001436}
1437
1438void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1439{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001440 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1441 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001442 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443}
1444
1445void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1446{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001447 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1448 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001449 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001450}
1451
1452void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1453{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001454 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1455 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001456 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001457}
1458
1459void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1460{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001461 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1462 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001463 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001464}
1465
1466void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1467{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001468 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1469 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001470 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471}
1472
1473void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1474{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001475 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1476 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001477 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478}
1479
1480void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1481{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001482 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1483 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001484 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1488{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001489 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001490 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
1493void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1494{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001495 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001496 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1500{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001501 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001502 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503}
1504
1505void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1506{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001507 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001508 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1512{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001513 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001514 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1518{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001519 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001520 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521}
1522
1523void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1524{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001525 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001526 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
1529void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1530{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001531 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001532 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001533}
1534
1535void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1536{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001537 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001538 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539}
1540
Jamie Madill54164b02017-08-28 15:17:37 -04001541void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001542{
Jamie Madill54164b02017-08-28 15:17:37 -04001543 const auto &uniformLocation = mState.getUniformLocations()[location];
1544 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1545
1546 GLenum nativeType = gl::VariableComponentType(uniform.type);
1547 if (nativeType == GL_FLOAT)
1548 {
1549 mProgram->getUniformfv(context, location, v);
1550 }
1551 else
1552 {
1553 getUniformInternal(context, v, location, nativeType,
1554 gl::VariableComponentCount(uniform.type));
1555 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001556}
1557
Jamie Madill54164b02017-08-28 15:17:37 -04001558void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001559{
Jamie Madill54164b02017-08-28 15:17:37 -04001560 const auto &uniformLocation = mState.getUniformLocations()[location];
1561 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1562
1563 GLenum nativeType = gl::VariableComponentType(uniform.type);
1564 if (nativeType == GL_INT || nativeType == GL_BOOL)
1565 {
1566 mProgram->getUniformiv(context, location, v);
1567 }
1568 else
1569 {
1570 getUniformInternal(context, v, location, nativeType,
1571 gl::VariableComponentCount(uniform.type));
1572 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001573}
1574
Jamie Madill54164b02017-08-28 15:17:37 -04001575void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001576{
Jamie Madill54164b02017-08-28 15:17:37 -04001577 const auto &uniformLocation = mState.getUniformLocations()[location];
1578 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1579
1580 GLenum nativeType = gl::VariableComponentType(uniform.type);
1581 if (nativeType == GL_UNSIGNED_INT)
1582 {
1583 mProgram->getUniformuiv(context, location, v);
1584 }
1585 else
1586 {
1587 getUniformInternal(context, v, location, nativeType,
1588 gl::VariableComponentCount(uniform.type));
1589 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001590}
1591
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001592void Program::flagForDeletion()
1593{
1594 mDeleteStatus = true;
1595}
1596
1597bool Program::isFlaggedForDeletion() const
1598{
1599 return mDeleteStatus;
1600}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001601
Brandon Jones43a53e22014-08-28 16:23:22 -07001602void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001603{
1604 mInfoLog.reset();
1605
Geoff Lang7dd2e102014-11-10 15:19:26 -05001606 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001607 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001608 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001609 }
1610 else
1611 {
Jamie Madillf6113162015-05-07 11:49:21 -04001612 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001613 }
1614}
1615
Geoff Lang7dd2e102014-11-10 15:19:26 -05001616bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1617{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001618 // Skip cache if we're using an infolog, so we get the full error.
1619 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1620 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1621 {
1622 return mCachedValidateSamplersResult.value();
1623 }
1624
1625 if (mTextureUnitTypesCache.empty())
1626 {
1627 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1628 }
1629 else
1630 {
1631 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1632 }
1633
1634 // if any two active samplers in a program are of different types, but refer to the same
1635 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1636 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001637 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001638 {
Jamie Madill54164b02017-08-28 15:17:37 -04001639 if (samplerBinding.unreferenced)
1640 continue;
1641
Jamie Madille7d84322017-01-10 18:21:59 -05001642 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001643
Jamie Madille7d84322017-01-10 18:21:59 -05001644 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001645 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001646 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1647 {
1648 if (infoLog)
1649 {
1650 (*infoLog) << "Sampler uniform (" << textureUnit
1651 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1652 << caps.maxCombinedTextureImageUnits << ")";
1653 }
1654
1655 mCachedValidateSamplersResult = false;
1656 return false;
1657 }
1658
1659 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1660 {
1661 if (textureType != mTextureUnitTypesCache[textureUnit])
1662 {
1663 if (infoLog)
1664 {
1665 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1666 "image unit ("
1667 << textureUnit << ").";
1668 }
1669
1670 mCachedValidateSamplersResult = false;
1671 return false;
1672 }
1673 }
1674 else
1675 {
1676 mTextureUnitTypesCache[textureUnit] = textureType;
1677 }
1678 }
1679 }
1680
1681 mCachedValidateSamplersResult = true;
1682 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001683}
1684
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001685bool Program::isValidated() const
1686{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001687 return mValidated;
1688}
1689
Geoff Lange1a27752015-10-05 13:16:04 -04001690GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001692 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693}
1694
jchen1058f67be2017-10-27 08:59:27 +08001695GLuint Program::getActiveAtomicCounterBufferCount() const
1696{
1697 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1698}
1699
Jiajia Qin729b2c62017-08-14 09:36:11 +08001700GLuint Program::getActiveShaderStorageBlockCount() const
1701{
1702 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1703}
1704
Geoff Lang7dd2e102014-11-10 15:19:26 -05001705void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1706{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001707 ASSERT(
1708 uniformBlockIndex <
1709 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001710
Jiajia Qin729b2c62017-08-14 09:36:11 +08001711 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001712
1713 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001714 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715 std::string string = uniformBlock.name;
1716
Jamie Madill62d31cb2015-09-11 13:25:51 -04001717 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001718 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001719 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001720 }
jchen10fd7c3b52017-03-21 15:36:03 +08001721 CopyStringToBuffer(uniformBlockName, string, bufSize, length);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001722 }
1723}
1724
Geoff Lange1a27752015-10-05 13:16:04 -04001725GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001726{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001727 int maxLength = 0;
1728
1729 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001730 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001731 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001732 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1733 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001734 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001735 if (!uniformBlock.name.empty())
1736 {
jchen10af713a22017-04-19 09:10:56 +08001737 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1738 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001739 }
1740 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001741 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001742
1743 return maxLength;
1744}
1745
Geoff Lange1a27752015-10-05 13:16:04 -04001746GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001747{
Olli Etuahoc8538042017-09-27 11:20:15 +03001748 std::vector<unsigned int> subscripts;
1749 std::string baseName = ParseResourceName(name, &subscripts);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001750
Jamie Madill48ef11b2016-04-27 15:21:52 -04001751 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001752 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1753 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001754 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001755 if (uniformBlock.name == baseName)
1756 {
1757 const bool arrayElementZero =
Olli Etuahoc8538042017-09-27 11:20:15 +03001758 (subscripts.empty() && (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1759 const bool arrayElementMatches =
1760 (subscripts.size() == 1 && subscripts[0] == uniformBlock.arrayElement);
1761 if (arrayElementMatches || arrayElementZero)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001762 {
1763 return blockIndex;
1764 }
1765 }
1766 }
1767
1768 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001769}
1770
Jiajia Qin729b2c62017-08-14 09:36:11 +08001771const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001772{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001773 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1774 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001775}
1776
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001777void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1778{
jchen107a20b972017-06-13 14:25:26 +08001779 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001780 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001781 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001782}
1783
1784GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1785{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001787}
1788
Jiajia Qin729b2c62017-08-14 09:36:11 +08001789GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1790{
1791 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1792}
1793
Geoff Lang48dcae72014-02-05 16:28:24 -05001794void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1795{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001796 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001797 for (GLsizei i = 0; i < count; i++)
1798 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001799 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001800 }
1801
Jamie Madill48ef11b2016-04-27 15:21:52 -04001802 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001803}
1804
1805void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1806{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001807 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001808 {
jchen10a9042d32017-03-17 08:50:45 +08001809 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1810 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1811 std::string varName = var.nameWithArrayIndex();
1812 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001813 if (length)
1814 {
1815 *length = lastNameIdx;
1816 }
1817 if (size)
1818 {
jchen10a9042d32017-03-17 08:50:45 +08001819 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001820 }
1821 if (type)
1822 {
jchen10a9042d32017-03-17 08:50:45 +08001823 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001824 }
1825 if (name)
1826 {
jchen10a9042d32017-03-17 08:50:45 +08001827 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001828 name[lastNameIdx] = '\0';
1829 }
1830 }
1831}
1832
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001833GLsizei Program::getTransformFeedbackVaryingCount() const
1834{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001835 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001836 {
jchen10a9042d32017-03-17 08:50:45 +08001837 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001838 }
1839 else
1840 {
1841 return 0;
1842 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001843}
1844
1845GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1846{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001847 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001848 {
1849 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001850 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001851 {
jchen10a9042d32017-03-17 08:50:45 +08001852 maxSize =
1853 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001854 }
1855
1856 return maxSize;
1857 }
1858 else
1859 {
1860 return 0;
1861 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001862}
1863
1864GLenum Program::getTransformFeedbackBufferMode() const
1865{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001866 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001867}
1868
Jamie Madillbd044ed2017-06-05 12:59:21 -04001869bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001870{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001871 Shader *vertexShader = mState.mAttachedVertexShader;
1872 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001873
Jamie Madillbd044ed2017-06-05 12:59:21 -04001874 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001875
Jiawei Shao3d404882017-10-16 13:30:48 +08001876 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
1877 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878
Sami Väisänen46eaa942016-06-29 10:26:37 +03001879 std::map<GLuint, std::string> staticFragmentInputLocations;
1880
Jamie Madill4cff2472015-08-21 16:53:18 -04001881 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001883 bool matched = false;
1884
1885 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001886 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 {
1888 continue;
1889 }
1890
Jamie Madill4cff2472015-08-21 16:53:18 -04001891 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001892 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001893 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001895 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001896 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04001897 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001898 {
1899 return false;
1900 }
1901
Geoff Lang7dd2e102014-11-10 15:19:26 -05001902 matched = true;
1903 break;
1904 }
1905 }
1906
1907 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001908 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001909 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001910 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001911 return false;
1912 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001913
1914 // Check for aliased path rendering input bindings (if any).
1915 // If more than one binding refer statically to the same
1916 // location the link must fail.
1917
1918 if (!output.staticUse)
1919 continue;
1920
1921 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1922 if (inputBinding == -1)
1923 continue;
1924
1925 const auto it = staticFragmentInputLocations.find(inputBinding);
1926 if (it == std::end(staticFragmentInputLocations))
1927 {
1928 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1929 }
1930 else
1931 {
1932 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1933 << it->second;
1934 return false;
1935 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001936 }
1937
Jamie Madillbd044ed2017-06-05 12:59:21 -04001938 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05001939 {
1940 return false;
1941 }
1942
Jamie Madillada9ecc2015-08-17 12:53:37 -04001943 // TODO(jmadill): verify no unmatched vertex varyings?
1944
Geoff Lang7dd2e102014-11-10 15:19:26 -05001945 return true;
1946}
1947
Jamie Madillbd044ed2017-06-05 12:59:21 -04001948bool Program::linkUniforms(const Context *context,
1949 InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001950 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001951{
Olli Etuahob78707c2017-03-09 15:03:11 +00001952 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04001953 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04001954 {
1955 return false;
1956 }
1957
Olli Etuahob78707c2017-03-09 15:03:11 +00001958 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001959
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001960 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001961
jchen10eaef1e52017-06-13 10:44:11 +08001962 if (!linkAtomicCounterBuffers())
1963 {
1964 return false;
1965 }
1966
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001967 return true;
1968}
1969
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001970void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001971{
Jamie Madill982f6e02017-06-07 14:33:04 -04001972 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
1973 unsigned int low = high;
1974
jchen10eaef1e52017-06-13 10:44:11 +08001975 for (auto counterIter = mState.mUniforms.rbegin();
1976 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
1977 {
1978 --low;
1979 }
1980
1981 mState.mAtomicCounterUniformRange = RangeUI(low, high);
1982
1983 high = low;
1984
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001985 for (auto imageIter = mState.mUniforms.rbegin();
1986 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
1987 {
1988 --low;
1989 }
1990
1991 mState.mImageUniformRange = RangeUI(low, high);
1992
1993 // If uniform is a image type, insert it into the mImageBindings array.
1994 for (unsigned int imageIndex : mState.mImageUniformRange)
1995 {
Xinghua Cao0328b572017-06-26 15:51:36 +08001996 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
1997 // cannot load values into a uniform defined as an image. if declare without a
1998 // binding qualifier, any uniform image variable (include all elements of
1999 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002000 auto &imageUniform = mState.mUniforms[imageIndex];
2001 if (imageUniform.binding == -1)
2002 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002003 mState.mImageBindings.emplace_back(ImageBinding(imageUniform.elementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002004 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002005 else
2006 {
2007 mState.mImageBindings.emplace_back(
2008 ImageBinding(imageUniform.binding, imageUniform.elementCount()));
2009 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002010 }
2011
2012 high = low;
2013
2014 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002015 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002016 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002017 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002018 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002019
2020 mState.mSamplerUniformRange = RangeUI(low, high);
2021
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002022 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002023 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002024 {
2025 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2026 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2027 mState.mSamplerBindings.emplace_back(
Jamie Madill54164b02017-08-28 15:17:37 -04002028 SamplerBinding(textureType, samplerUniform.elementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002029 }
2030}
2031
jchen10eaef1e52017-06-13 10:44:11 +08002032bool Program::linkAtomicCounterBuffers()
2033{
2034 for (unsigned int index : mState.mAtomicCounterUniformRange)
2035 {
2036 auto &uniform = mState.mUniforms[index];
2037 bool found = false;
2038 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2039 ++bufferIndex)
2040 {
2041 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2042 if (buffer.binding == uniform.binding)
2043 {
2044 buffer.memberIndexes.push_back(index);
2045 uniform.bufferIndex = bufferIndex;
2046 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002047 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002048 break;
2049 }
2050 }
2051 if (!found)
2052 {
2053 AtomicCounterBuffer atomicCounterBuffer;
2054 atomicCounterBuffer.binding = uniform.binding;
2055 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002056 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002057 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2058 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2059 }
2060 }
2061 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2062 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2063
2064 return true;
2065}
2066
Martin Radev4c4c8e72016-08-04 12:25:34 +03002067bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2068 const std::string &uniformName,
2069 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002070 const sh::InterfaceBlockField &fragmentUniform,
2071 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002072{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002073 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2074 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2075 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002076 {
2077 return false;
2078 }
2079
2080 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2081 {
Jamie Madillf6113162015-05-07 11:49:21 -04002082 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002083 return false;
2084 }
2085
2086 return true;
2087}
2088
Jamie Madilleb979bf2016-11-15 12:28:46 -05002089// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002090bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002091{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002092 const ContextState &data = context->getContextState();
2093 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002094
Geoff Lang7dd2e102014-11-10 15:19:26 -05002095 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002096 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002097 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002098
2099 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002100 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002101 {
Jamie Madillf6113162015-05-07 11:49:21 -04002102 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002103 return false;
2104 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002105
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002106 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002107
Jamie Madillc349ec02015-08-21 16:53:12 -04002108 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002109 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002110 {
Olli Etuahod2551232017-10-26 20:03:33 +03002111 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2112 // structures, so we don't need to worry about adjusting their names or generating entries
2113 // for each member/element (unlike uniforms for example).
2114 ASSERT(!attribute.isArray() && !attribute.isStruct());
2115
Jamie Madilleb979bf2016-11-15 12:28:46 -05002116 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002117 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002118 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002119 attribute.location = bindingLocation;
2120 }
2121
2122 if (attribute.location != -1)
2123 {
2124 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002125 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002126
Jamie Madill63805b42015-08-25 13:17:39 -04002127 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002128 {
Jamie Madillf6113162015-05-07 11:49:21 -04002129 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002130 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131
2132 return false;
2133 }
2134
Jamie Madill63805b42015-08-25 13:17:39 -04002135 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002136 {
Jamie Madill63805b42015-08-25 13:17:39 -04002137 const int regLocation = attribute.location + reg;
2138 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002139
2140 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002141 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002142 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002143 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002144 // TODO(jmadill): fix aliasing on ES2
2145 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002147 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002148 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002149 return false;
2150 }
2151 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002152 else
2153 {
Jamie Madill63805b42015-08-25 13:17:39 -04002154 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002155 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002156
Jamie Madill63805b42015-08-25 13:17:39 -04002157 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002158 }
2159 }
2160 }
2161
2162 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002163 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002164 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002165 // Not set by glBindAttribLocation or by location layout qualifier
2166 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002167 {
Jamie Madill63805b42015-08-25 13:17:39 -04002168 int regs = VariableRegisterCount(attribute.type);
2169 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002170
Jamie Madill63805b42015-08-25 13:17:39 -04002171 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002172 {
Jamie Madillf6113162015-05-07 11:49:21 -04002173 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002174 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175 }
2176
Jamie Madillc349ec02015-08-21 16:53:12 -04002177 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178 }
2179 }
2180
Jamie Madill48ef11b2016-04-27 15:21:52 -04002181 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002182 {
Jamie Madill63805b42015-08-25 13:17:39 -04002183 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002184 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002185
Jamie Madillbd159f02017-10-09 19:39:06 -04002186 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002187 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002188 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2189 mState.mActiveAttribLocationsMask.set(location);
2190 mState.mMaxActiveAttribLocation =
2191 std::max(mState.mMaxActiveAttribLocation, location + 1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002192 }
2193 }
2194
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195 return true;
2196}
2197
Martin Radev4c4c8e72016-08-04 12:25:34 +03002198bool Program::validateVertexAndFragmentInterfaceBlocks(
2199 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2200 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002201 InfoLog &infoLog,
2202 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002203{
2204 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002205 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2206 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002207
2208 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2209 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002210 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002211 }
2212
Jamie Madille473dee2015-08-18 14:49:01 -04002213 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002214 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002215 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2216 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002217 {
2218 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002219 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2220 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221 {
2222 return false;
2223 }
2224 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002225 // TODO(jiajia.qin@intel.com): Add
2226 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002227 }
2228 return true;
2229}
Jamie Madille473dee2015-08-18 14:49:01 -04002230
Jiajia Qin729b2c62017-08-14 09:36:11 +08002231bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002232{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002233 const auto &caps = context->getCaps();
2234
Martin Radev4c4c8e72016-08-04 12:25:34 +03002235 if (mState.mAttachedComputeShader)
2236 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002237 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002238 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002239
Jiajia Qin729b2c62017-08-14 09:36:11 +08002240 if (!validateInterfaceBlocksCount(
2241 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002242 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2243 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002244 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002245 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002246 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002247
2248 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2249 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2250 computeShaderStorageBlocks,
2251 "Compute shader shader storage block count exceeds "
2252 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2253 infoLog))
2254 {
2255 return false;
2256 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002257 return true;
2258 }
2259
Jamie Madillbd044ed2017-06-05 12:59:21 -04002260 Shader &vertexShader = *mState.mAttachedVertexShader;
2261 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002262
Jiajia Qin729b2c62017-08-14 09:36:11 +08002263 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2264 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002265
Jiajia Qin729b2c62017-08-14 09:36:11 +08002266 if (!validateInterfaceBlocksCount(
2267 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002268 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2269 {
2270 return false;
2271 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002272 if (!validateInterfaceBlocksCount(
2273 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002274 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2275 infoLog))
2276 {
2277
2278 return false;
2279 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002280
2281 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002282 if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002283 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002284 {
2285 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002286 }
Jamie Madille473dee2015-08-18 14:49:01 -04002287
Jiajia Qin729b2c62017-08-14 09:36:11 +08002288 if (context->getClientVersion() >= Version(3, 1))
2289 {
2290 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2291 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2292
2293 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2294 vertexShaderStorageBlocks,
2295 "Vertex shader shader storage block count exceeds "
2296 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2297 infoLog))
2298 {
2299 return false;
2300 }
2301 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2302 fragmentShaderStorageBlocks,
2303 "Fragment shader shader storage block count exceeds "
2304 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2305 infoLog))
2306 {
2307
2308 return false;
2309 }
2310
2311 if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
2312 fragmentShaderStorageBlocks, infoLog,
2313 webglCompatibility))
2314 {
2315 return false;
2316 }
2317 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002318 return true;
2319}
2320
Jamie Madilla2c74982016-12-12 11:20:42 -05002321bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002322 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002323 const sh::InterfaceBlock &fragmentInterfaceBlock,
2324 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002325{
2326 const char* blockName = vertexInterfaceBlock.name.c_str();
2327 // validate blocks for the same member types
2328 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2329 {
Jamie Madillf6113162015-05-07 11:49:21 -04002330 infoLog << "Types for interface block '" << blockName
2331 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002332 return false;
2333 }
2334 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2335 {
Jamie Madillf6113162015-05-07 11:49:21 -04002336 infoLog << "Array sizes differ for interface block '" << blockName
2337 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002338 return false;
2339 }
jchen10af713a22017-04-19 09:10:56 +08002340 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2341 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2342 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002343 {
Jamie Madillf6113162015-05-07 11:49:21 -04002344 infoLog << "Layout qualifiers differ for interface block '" << blockName
2345 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002346 return false;
2347 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002348 const unsigned int numBlockMembers =
2349 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002350 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2351 {
2352 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2353 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2354 if (vertexMember.name != fragmentMember.name)
2355 {
Jamie Madillf6113162015-05-07 11:49:21 -04002356 infoLog << "Name mismatch for field " << blockMemberIndex
2357 << " of interface block '" << blockName
2358 << "': (in vertex: '" << vertexMember.name
2359 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002360 return false;
2361 }
2362 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002363 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2364 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002365 {
2366 return false;
2367 }
2368 }
2369 return true;
2370}
2371
2372bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2373 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2374{
2375 if (vertexVariable.type != fragmentVariable.type)
2376 {
Jamie Madillf6113162015-05-07 11:49:21 -04002377 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002378 return false;
2379 }
2380 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2381 {
Jamie Madillf6113162015-05-07 11:49:21 -04002382 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002383 return false;
2384 }
2385 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2386 {
Jamie Madillf6113162015-05-07 11:49:21 -04002387 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002388 return false;
2389 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002390 if (vertexVariable.structName != fragmentVariable.structName)
2391 {
2392 infoLog << "Structure names for " << variableName
2393 << " differ between vertex and fragment shaders";
2394 return false;
2395 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002396
2397 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2398 {
Jamie Madillf6113162015-05-07 11:49:21 -04002399 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002400 return false;
2401 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002402 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002403 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2404 {
2405 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2406 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2407
2408 if (vertexMember.name != fragmentMember.name)
2409 {
Jamie Madillf6113162015-05-07 11:49:21 -04002410 infoLog << "Name mismatch for field '" << memberIndex
2411 << "' of " << variableName
2412 << ": (in vertex: '" << vertexMember.name
2413 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002414 return false;
2415 }
2416
2417 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2418 vertexMember.name + "'";
2419
2420 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2421 {
2422 return false;
2423 }
2424 }
2425
2426 return true;
2427}
2428
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002429bool Program::linkValidateVaryings(InfoLog &infoLog,
2430 const std::string &varyingName,
2431 const sh::Varying &vertexVarying,
2432 const sh::Varying &fragmentVarying,
2433 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002434{
2435 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2436 {
2437 return false;
2438 }
2439
Jamie Madille9cc4692015-02-19 16:00:13 -05002440 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002441 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002442 infoLog << "Interpolation types for " << varyingName
2443 << " differ between vertex and fragment shaders.";
2444 return false;
2445 }
2446
2447 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2448 {
2449 infoLog << "Invariance for " << varyingName
2450 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002451 return false;
2452 }
2453
2454 return true;
2455}
2456
Jamie Madillbd044ed2017-06-05 12:59:21 -04002457bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002458{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002459 Shader *vertexShader = mState.mAttachedVertexShader;
2460 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002461 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2462 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002463 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002464
2465 if (shaderVersion != 100)
2466 {
2467 // Only ESSL 1.0 has restrictions on matching input and output invariance
2468 return true;
2469 }
2470
2471 bool glPositionIsInvariant = false;
2472 bool glPointSizeIsInvariant = false;
2473 bool glFragCoordIsInvariant = false;
2474 bool glPointCoordIsInvariant = false;
2475
2476 for (const sh::Varying &varying : vertexVaryings)
2477 {
2478 if (!varying.isBuiltIn())
2479 {
2480 continue;
2481 }
2482 if (varying.name.compare("gl_Position") == 0)
2483 {
2484 glPositionIsInvariant = varying.isInvariant;
2485 }
2486 else if (varying.name.compare("gl_PointSize") == 0)
2487 {
2488 glPointSizeIsInvariant = varying.isInvariant;
2489 }
2490 }
2491
2492 for (const sh::Varying &varying : fragmentVaryings)
2493 {
2494 if (!varying.isBuiltIn())
2495 {
2496 continue;
2497 }
2498 if (varying.name.compare("gl_FragCoord") == 0)
2499 {
2500 glFragCoordIsInvariant = varying.isInvariant;
2501 }
2502 else if (varying.name.compare("gl_PointCoord") == 0)
2503 {
2504 glPointCoordIsInvariant = varying.isInvariant;
2505 }
2506 }
2507
2508 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2509 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2510 // Not requiring invariance to match is supported by:
2511 // dEQP, WebGL CTS, Nexus 5X GLES
2512 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2513 {
2514 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2515 "declared invariant.";
2516 return false;
2517 }
2518 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2519 {
2520 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2521 "declared invariant.";
2522 return false;
2523 }
2524
2525 return true;
2526}
2527
jchen10a9042d32017-03-17 08:50:45 +08002528bool Program::linkValidateTransformFeedback(const gl::Context *context,
2529 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002530 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002531 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002532{
2533 size_t totalComponents = 0;
2534
Jamie Madillccdf74b2015-08-18 10:46:12 -04002535 std::set<std::string> uniqueNames;
2536
Jamie Madill48ef11b2016-04-27 15:21:52 -04002537 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002538 {
2539 bool found = false;
Olli Etuahoc8538042017-09-27 11:20:15 +03002540 std::vector<unsigned int> subscripts;
2541 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002542
Jamie Madill192745a2016-12-22 15:58:21 -05002543 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002544 {
Jamie Madill192745a2016-12-22 15:58:21 -05002545 const sh::Varying *varying = ref.second.get();
2546
jchen10a9042d32017-03-17 08:50:45 +08002547 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002548 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002549 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002550 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002551 infoLog << "Two transform feedback varyings specify the same output variable ("
2552 << tfVaryingName << ").";
2553 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002554 }
jchen10a9042d32017-03-17 08:50:45 +08002555 if (context->getClientVersion() >= Version(3, 1))
2556 {
2557 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2558 {
2559 infoLog
2560 << "Two transform feedback varyings include the same array element ("
2561 << tfVaryingName << ").";
2562 return false;
2563 }
2564 }
2565 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002566 {
2567 infoLog << "Capture of arrays is undefined and not supported.";
2568 return false;
2569 }
2570
jchen10a9042d32017-03-17 08:50:45 +08002571 uniqueNames.insert(tfVaryingName);
2572
Jamie Madillccdf74b2015-08-18 10:46:12 -04002573 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002574 size_t elementCount =
Olli Etuahoc8538042017-09-27 11:20:15 +03002575 ((varying->isArray() && subscripts.empty()) ? varying->elementCount() : 1);
jchen10a9042d32017-03-17 08:50:45 +08002576 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002577 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002578 componentCount > caps.maxTransformFeedbackSeparateComponents)
2579 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002580 infoLog << "Transform feedback varying's " << varying->name << " components ("
2581 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002582 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002583 return false;
2584 }
2585
2586 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002587 found = true;
2588 break;
2589 }
2590 }
jchen10a9042d32017-03-17 08:50:45 +08002591 if (context->getClientVersion() < Version(3, 1) &&
2592 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002593 {
Geoff Lang1a683462015-09-29 15:09:59 -04002594 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002595 return false;
2596 }
Olli Etuaho39e78122017-08-29 14:34:22 +03002597 // All transform feedback varyings are expected to exist since packUserVaryings checks for
2598 // them.
Geoff Lang7dd2e102014-11-10 15:19:26 -05002599 ASSERT(found);
2600 }
2601
Jamie Madill48ef11b2016-04-27 15:21:52 -04002602 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002603 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002604 {
Jamie Madillf6113162015-05-07 11:49:21 -04002605 infoLog << "Transform feedback varying total components (" << totalComponents
2606 << ") exceed the maximum interleaved components ("
2607 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002608 return false;
2609 }
2610
2611 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002612}
2613
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002614bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
2615{
2616 const std::vector<sh::Uniform> &vertexUniforms =
2617 mState.mAttachedVertexShader->getUniforms(context);
2618 const std::vector<sh::Uniform> &fragmentUniforms =
2619 mState.mAttachedFragmentShader->getUniforms(context);
2620 const std::vector<sh::Attribute> &attributes =
2621 mState.mAttachedVertexShader->getActiveAttributes(context);
2622 for (const auto &attrib : attributes)
2623 {
2624 for (const auto &uniform : vertexUniforms)
2625 {
2626 if (uniform.name == attrib.name)
2627 {
2628 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2629 return false;
2630 }
2631 }
2632 for (const auto &uniform : fragmentUniforms)
2633 {
2634 if (uniform.name == attrib.name)
2635 {
2636 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2637 return false;
2638 }
2639 }
2640 }
2641 return true;
2642}
2643
Jamie Madill192745a2016-12-22 15:58:21 -05002644void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002645{
2646 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002647 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002648 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002649 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002650 std::vector<unsigned int> subscripts;
2651 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002652 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002653 if (!subscripts.empty())
2654 {
2655 subscript = subscripts.back();
2656 }
Jamie Madill192745a2016-12-22 15:58:21 -05002657 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002658 {
Jamie Madill192745a2016-12-22 15:58:21 -05002659 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002660 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002661 {
jchen10a9042d32017-03-17 08:50:45 +08002662 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2663 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002664 break;
2665 }
2666 }
2667 }
2668}
2669
Jamie Madillbd044ed2017-06-05 12:59:21 -04002670Program::MergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002671{
Jamie Madill192745a2016-12-22 15:58:21 -05002672 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002673
Jiawei Shao3d404882017-10-16 13:30:48 +08002674 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002675 {
Jamie Madill192745a2016-12-22 15:58:21 -05002676 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002677 }
2678
Jiawei Shao3d404882017-10-16 13:30:48 +08002679 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002680 {
Jamie Madill192745a2016-12-22 15:58:21 -05002681 merged[varying.name].fragment = &varying;
2682 }
2683
2684 return merged;
2685}
2686
2687std::vector<PackedVarying> Program::getPackedVaryings(
2688 const Program::MergedVaryings &mergedVaryings) const
2689{
2690 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2691 std::vector<PackedVarying> packedVaryings;
jchen10a9042d32017-03-17 08:50:45 +08002692 std::set<std::string> uniqueFullNames;
Jamie Madill192745a2016-12-22 15:58:21 -05002693
2694 for (const auto &ref : mergedVaryings)
2695 {
2696 const sh::Varying *input = ref.second.vertex;
2697 const sh::Varying *output = ref.second.fragment;
2698
2699 // Only pack varyings that have a matched input or output, plus special builtins.
2700 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002701 {
Jamie Madill192745a2016-12-22 15:58:21 -05002702 // Will get the vertex shader interpolation by default.
2703 auto interpolation = ref.second.get()->interpolation;
2704
Olli Etuaho06a06f52017-07-12 12:22:15 +03002705 // Note that we lose the vertex shader static use information here. The data for the
2706 // variable is taken from the fragment shader.
Jamie Madill192745a2016-12-22 15:58:21 -05002707 if (output->isStruct())
2708 {
2709 ASSERT(!output->isArray());
2710 for (const auto &field : output->fields)
2711 {
2712 ASSERT(!field.isStruct() && !field.isArray());
2713 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2714 }
2715 }
2716 else
2717 {
2718 packedVaryings.push_back(PackedVarying(*output, interpolation));
2719 }
2720 continue;
2721 }
2722
2723 // Keep Transform FB varyings in the merged list always.
2724 if (!input)
2725 {
2726 continue;
2727 }
2728
2729 for (const std::string &tfVarying : tfVaryings)
2730 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002731 std::vector<unsigned int> subscripts;
2732 std::string baseName = ParseResourceName(tfVarying, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002733 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002734 if (!subscripts.empty())
2735 {
2736 subscript = subscripts.back();
2737 }
jchen10a9042d32017-03-17 08:50:45 +08002738 if (uniqueFullNames.count(tfVarying) > 0)
2739 {
2740 continue;
2741 }
2742 if (baseName == input->name)
Jamie Madill192745a2016-12-22 15:58:21 -05002743 {
2744 // Transform feedback for varying structs is underspecified.
2745 // See Khronos bug 9856.
2746 // TODO(jmadill): Figure out how to be spec-compliant here.
2747 if (!input->isStruct())
2748 {
2749 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2750 packedVaryings.back().vertexOnly = true;
jchen10a9042d32017-03-17 08:50:45 +08002751 packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
2752 uniqueFullNames.insert(tfVarying);
Jamie Madill192745a2016-12-22 15:58:21 -05002753 }
jchen10a9042d32017-03-17 08:50:45 +08002754 if (subscript == GL_INVALID_INDEX)
2755 {
2756 break;
2757 }
Jamie Madill192745a2016-12-22 15:58:21 -05002758 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002759 }
2760 }
2761
Jamie Madill192745a2016-12-22 15:58:21 -05002762 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2763
2764 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002765}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002766
Jamie Madillbd044ed2017-06-05 12:59:21 -04002767void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002768{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002769 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002770 ASSERT(fragmentShader != nullptr);
2771
Geoff Lange0cff192017-05-30 13:04:56 -04002772 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002773 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002774
2775 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002776 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002777 {
2778 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2779 outputVariable.name != "gl_FragData")
2780 {
2781 continue;
2782 }
2783
2784 unsigned int baseLocation =
2785 (outputVariable.location == -1 ? 0u
2786 : static_cast<unsigned int>(outputVariable.location));
2787 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2788 elementIndex++)
2789 {
2790 const unsigned int location = baseLocation + elementIndex;
2791 if (location >= mState.mOutputVariableTypes.size())
2792 {
2793 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2794 }
Corentin Walleze7557742017-06-01 13:09:57 -04002795 ASSERT(location < mState.mActiveOutputVariables.size());
2796 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002797 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2798 }
2799 }
2800
Jamie Madill80a6fc02015-08-21 16:53:16 -04002801 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002802 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002803 return;
2804
Jamie Madillbd044ed2017-06-05 12:59:21 -04002805 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002806 // TODO(jmadill): any caps validation here?
2807
jchen1015015f72017-03-16 13:54:21 +08002808 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002809 outputVariableIndex++)
2810 {
jchen1015015f72017-03-16 13:54:21 +08002811 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002812
Olli Etuahod2551232017-10-26 20:03:33 +03002813 if (outputVariable.isArray())
2814 {
2815 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2816 // Resources and including [0] at the end of array variable names.
2817 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2818 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2819 }
2820
Jamie Madill80a6fc02015-08-21 16:53:16 -04002821 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2822 if (outputVariable.isBuiltIn())
2823 continue;
2824
2825 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002826 unsigned int baseLocation =
2827 (outputVariable.location == -1 ? 0u
2828 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002829
Jamie Madill80a6fc02015-08-21 16:53:16 -04002830 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2831 elementIndex++)
2832 {
Olli Etuahod2551232017-10-26 20:03:33 +03002833 const unsigned int location = baseLocation + elementIndex;
2834 if (location >= mState.mOutputLocations.size())
2835 {
2836 mState.mOutputLocations.resize(location + 1);
2837 }
2838 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03002839 if (outputVariable.isArray())
2840 {
2841 mState.mOutputLocations[location] =
2842 VariableLocation(elementIndex, outputVariableIndex);
2843 }
2844 else
2845 {
2846 VariableLocation locationInfo;
2847 locationInfo.index = outputVariableIndex;
2848 mState.mOutputLocations[location] = locationInfo;
2849 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04002850 }
2851 }
2852}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002853
Olli Etuaho48fed632017-03-16 12:05:30 +00002854void Program::setUniformValuesFromBindingQualifiers()
2855{
Jamie Madill982f6e02017-06-07 14:33:04 -04002856 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002857 {
2858 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2859 if (samplerUniform.binding != -1)
2860 {
Olli Etuahod2551232017-10-26 20:03:33 +03002861 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00002862 ASSERT(location != -1);
2863 std::vector<GLint> boundTextureUnits;
2864 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2865 ++elementIndex)
2866 {
2867 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2868 }
2869 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2870 boundTextureUnits.data());
2871 }
2872 }
2873}
2874
jchen10eaef1e52017-06-13 10:44:11 +08002875void Program::gatherAtomicCounterBuffers()
2876{
jchen10baf5d942017-08-28 20:45:48 +08002877 for (unsigned int index : mState.mAtomicCounterUniformRange)
2878 {
2879 auto &uniform = mState.mUniforms[index];
2880 uniform.blockInfo.offset = uniform.offset;
2881 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2882 uniform.blockInfo.matrixStride = 0;
2883 uniform.blockInfo.isRowMajorMatrix = false;
2884 }
2885
jchen10eaef1e52017-06-13 10:44:11 +08002886 // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
2887}
2888
Jamie Madill977abce2017-11-07 08:03:19 -05002889void Program::gatherUniformBlockInfo(const gl::Context *context)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002890{
Jamie Madill977abce2017-11-07 08:03:19 -05002891 UniformBlockLinker blockLinker(&mState.mUniformBlocks, &mState.mUniforms);
Jamie Madillc9727f32017-11-07 12:37:07 -05002892 InitUniformBlockLinker(context, mState, &blockLinker);
Jamie Madill977abce2017-11-07 08:03:19 -05002893
2894 auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
2895 size_t *sizeOut) {
2896 return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
2897 };
2898
2899 auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
2900 sh::BlockMemberInfo *infoOut) {
2901 return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
2902 };
2903
2904 blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002905}
Martin Radev4c4c8e72016-08-04 12:25:34 +03002906
Jamie Madill977abce2017-11-07 08:03:19 -05002907void Program::gatherShaderStorageBlockInfo(const gl::Context *context)
Jiajia Qin729b2c62017-08-14 09:36:11 +08002908{
Jamie Madill977abce2017-11-07 08:03:19 -05002909 ShaderStorageBlockLinker blockLinker(&mState.mShaderStorageBlocks);
Jamie Madillc9727f32017-11-07 12:37:07 -05002910 InitShaderStorageBlockLinker(context, mState, &blockLinker);
Jamie Madill977abce2017-11-07 08:03:19 -05002911
2912 // We don't have a way of determining block info for shader storage blocks yet.
2913 // TODO(jiajia.qin@intel.com): Determine correct block size and layout.
2914 auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
2915 size_t *sizeOut) {
2916 return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
2917 };
2918
2919 auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
2920 sh::BlockMemberInfo *infoOut) {
2921 return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
2922 };
2923
2924 blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002925}
2926
2927void Program::gatherInterfaceBlockInfo(const Context *context)
2928{
2929 ASSERT(mState.mUniformBlocks.empty());
2930 ASSERT(mState.mShaderStorageBlocks.empty());
2931
Jamie Madill977abce2017-11-07 08:03:19 -05002932 gatherUniformBlockInfo(context);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002933 if (context->getClientVersion() >= Version(3, 1))
2934 {
Jamie Madill977abce2017-11-07 08:03:19 -05002935 gatherShaderStorageBlockInfo(context);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002936 }
2937
jchen10af713a22017-04-19 09:10:56 +08002938 // Set initial bindings from shader.
2939 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2940 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002941 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08002942 bindUniformBlock(blockIndex, uniformBlock.binding);
2943 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002944}
2945
Jamie Madille7d84322017-01-10 18:21:59 -05002946void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05002947 GLsizei clampedCount,
2948 const GLint *v)
2949{
Jamie Madill81c2e252017-09-09 23:32:46 -04002950 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
2951 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2952 std::vector<GLuint> *boundTextureUnits =
2953 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05002954
Olli Etuahoc8538042017-09-27 11:20:15 +03002955 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.flattenedArrayOffset);
Jamie Madilld68248b2017-09-11 14:34:14 -04002956
2957 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04002958 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05002959}
2960
2961template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002962GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
2963 GLsizei count,
2964 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05002965 const T *v)
2966{
Jamie Madill134f93d2017-08-31 17:11:00 -04002967 if (count == 1)
2968 return 1;
2969
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002970 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002971
Corentin Wallez15ac5342016-11-03 17:06:39 -04002972 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2973 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuahoc8538042017-09-27 11:20:15 +03002974 unsigned int remainingElements =
2975 linkedUniform.elementCount() - locationInfo.flattenedArrayOffset;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002976 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002977 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002978
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002979 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002980 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002981 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002982 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002983
2984 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002985}
2986
2987template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002988GLsizei Program::clampMatrixUniformCount(GLint location,
2989 GLsizei count,
2990 GLboolean transpose,
2991 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002992{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002993 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2994
Jamie Madill62d31cb2015-09-11 13:25:51 -04002995 if (!transpose)
2996 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002997 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002998 }
2999
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003000 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003001
3002 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3003 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuahoc8538042017-09-27 11:20:15 +03003004 unsigned int remainingElements =
3005 linkedUniform.elementCount() - locationInfo.flattenedArrayOffset;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003006 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003007}
3008
Jamie Madill54164b02017-08-28 15:17:37 -04003009// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3010// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003011template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003012void Program::getUniformInternal(const Context *context,
3013 DestT *dataOut,
3014 GLint location,
3015 GLenum nativeType,
3016 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003017{
Jamie Madill54164b02017-08-28 15:17:37 -04003018 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003019 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003020 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003021 {
3022 GLint tempValue[16] = {0};
3023 mProgram->getUniformiv(context, location, tempValue);
3024 UniformStateQueryCastLoop<GLboolean>(
3025 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003026 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003027 }
3028 case GL_INT:
3029 {
3030 GLint tempValue[16] = {0};
3031 mProgram->getUniformiv(context, location, tempValue);
3032 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3033 components);
3034 break;
3035 }
3036 case GL_UNSIGNED_INT:
3037 {
3038 GLuint tempValue[16] = {0};
3039 mProgram->getUniformuiv(context, location, tempValue);
3040 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3041 components);
3042 break;
3043 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003044 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003045 {
3046 GLfloat tempValue[16] = {0};
3047 mProgram->getUniformfv(context, location, tempValue);
3048 UniformStateQueryCastLoop<GLfloat>(
3049 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003050 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003051 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003052 default:
3053 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003054 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003055 }
3056}
Jamie Madilla4595b82017-01-11 17:36:34 -05003057
3058bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3059{
3060 // Must be called after samplers are validated.
3061 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3062
3063 for (const auto &binding : mState.mSamplerBindings)
3064 {
3065 GLenum textureType = binding.textureType;
3066 for (const auto &unit : binding.boundTextureUnits)
3067 {
3068 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3069 if (programTextureID == textureID)
3070 {
3071 // TODO(jmadill): Check for appropriate overlap.
3072 return true;
3073 }
3074 }
3075 }
3076
3077 return false;
3078}
3079
Jamie Madilla2c74982016-12-12 11:20:42 -05003080} // namespace gl