blob: 22d0a3aeff7dbddeb72f74596df2acb67184daae [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 Madill7af0de52017-11-06 17:09:33 -050022#include "libANGLE/ProgramLinkedResources.h"
Jamie Madill437d2662014-12-05 14:23:35 -050023#include "libANGLE/ResourceManager.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040024#include "libANGLE/Uniform.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 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300193 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300194 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
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800261GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
262{
263 std::vector<unsigned int> subscripts;
264 std::string baseName = ParseResourceName(name, &subscripts);
265
266 unsigned int numBlocks = static_cast<unsigned int>(list.size());
267 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
268 {
269 const auto &block = list[blockIndex];
270 if (block.name == baseName)
271 {
272 const bool arrayElementZero =
273 (subscripts.empty() && (!block.isArray || block.arrayElement == 0));
274 const bool arrayElementMatches =
275 (subscripts.size() == 1 && subscripts[0] == block.arrayElement);
276 if (arrayElementMatches || arrayElementZero)
277 {
278 return blockIndex;
279 }
280 }
281 }
282
283 return GL_INVALID_INDEX;
284}
285
286void GetInterfaceBlockName(const GLuint index,
287 const std::vector<InterfaceBlock> &list,
288 GLsizei bufSize,
289 GLsizei *length,
290 GLchar *name)
291{
292 ASSERT(index < list.size());
293
294 const auto &block = list[index];
295
296 if (bufSize > 0)
297 {
298 std::string blockName = block.name;
299
300 if (block.isArray)
301 {
302 blockName += ArrayString(block.arrayElement);
303 }
304 CopyStringToBuffer(name, blockName, bufSize, length);
305 }
306}
307
Jamie Madillc9727f32017-11-07 12:37:07 -0500308void InitUniformBlockLinker(const gl::Context *context,
309 const ProgramState &state,
310 UniformBlockLinker *blockLinker)
311{
312 if (state.getAttachedVertexShader())
313 {
314 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
315 &state.getAttachedVertexShader()->getUniformBlocks(context));
316 }
317
318 if (state.getAttachedFragmentShader())
319 {
320 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
321 &state.getAttachedFragmentShader()->getUniformBlocks(context));
322 }
323
324 if (state.getAttachedComputeShader())
325 {
326 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
327 &state.getAttachedComputeShader()->getUniformBlocks(context));
328 }
329}
330
331void InitShaderStorageBlockLinker(const gl::Context *context,
332 const ProgramState &state,
333 ShaderStorageBlockLinker *blockLinker)
334{
335 if (state.getAttachedVertexShader())
336 {
337 blockLinker->addShaderBlocks(
338 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
339 }
340
341 if (state.getAttachedFragmentShader())
342 {
343 blockLinker->addShaderBlocks(
344 GL_FRAGMENT_SHADER,
345 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
346 }
347
348 if (state.getAttachedComputeShader())
349 {
350 blockLinker->addShaderBlocks(
351 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
352 }
353}
354
Jamie Madill62d31cb2015-09-11 13:25:51 -0400355} // anonymous namespace
356
Jamie Madill4a3c2342015-10-08 12:58:45 -0400357const char *const g_fakepath = "C:\\fakepath";
358
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400359InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000360{
361}
362
363InfoLog::~InfoLog()
364{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000365}
366
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400367size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000368{
Jamie Madill23176ce2017-07-31 14:14:33 -0400369 if (!mLazyStream)
370 {
371 return 0;
372 }
373
374 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400375 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000376}
377
Geoff Lange1a27752015-10-05 13:16:04 -0400378void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000379{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400380 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000381
382 if (bufSize > 0)
383 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400384 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400385
Jamie Madill23176ce2017-07-31 14:14:33 -0400386 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000387 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400388 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
389 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000390 }
391
392 infoLog[index] = '\0';
393 }
394
395 if (length)
396 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400397 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000398 }
399}
400
401// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300402// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000403// messages, so lets remove all occurrences of this fake file path from the log.
404void InfoLog::appendSanitized(const char *message)
405{
Jamie Madill23176ce2017-07-31 14:14:33 -0400406 ensureInitialized();
407
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000408 std::string msg(message);
409
410 size_t found;
411 do
412 {
413 found = msg.find(g_fakepath);
414 if (found != std::string::npos)
415 {
416 msg.erase(found, strlen(g_fakepath));
417 }
418 }
419 while (found != std::string::npos);
420
Jamie Madill23176ce2017-07-31 14:14:33 -0400421 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000422}
423
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000424void InfoLog::reset()
425{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000426}
427
Olli Etuaho1734e172017-10-27 15:30:27 +0300428VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000429{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500430}
431
Olli Etuahoc8538042017-09-27 11:20:15 +0300432VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300433 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500434{
Olli Etuahoc8538042017-09-27 11:20:15 +0300435 ASSERT(arrayIndex != GL_INVALID_INDEX);
436}
437
Geoff Langd8605522016-04-13 10:19:12 -0400438void Program::Bindings::bindLocation(GLuint index, const std::string &name)
439{
440 mBindings[name] = index;
441}
442
443int Program::Bindings::getBinding(const std::string &name) const
444{
445 auto iter = mBindings.find(name);
446 return (iter != mBindings.end()) ? iter->second : -1;
447}
448
449Program::Bindings::const_iterator Program::Bindings::begin() const
450{
451 return mBindings.begin();
452}
453
454Program::Bindings::const_iterator Program::Bindings::end() const
455{
456 return mBindings.end();
457}
458
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500460 : mLabel(),
461 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400462 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300463 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500464 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400465 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500466 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800467 mImageUniformRange(0, 0),
468 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300469 mBinaryRetrieveableHint(false),
470 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400471{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300472 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400473}
474
Jamie Madill48ef11b2016-04-27 15:21:52 -0400475ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400476{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500477 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400478}
479
Jamie Madill48ef11b2016-04-27 15:21:52 -0400480const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500481{
482 return mLabel;
483}
484
Jamie Madille7d84322017-01-10 18:21:59 -0500485GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400486{
jchen1015015f72017-03-16 13:54:21 +0800487 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400488}
489
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800490GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
491{
492 return GetResourceIndexFromName(mBufferVariables, name);
493}
494
Jamie Madille7d84322017-01-10 18:21:59 -0500495GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
496{
497 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
498 return mUniformLocations[location].index;
499}
500
501Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
502{
503 GLuint index = getUniformIndexFromLocation(location);
504 if (!isSamplerUniformIndex(index))
505 {
506 return Optional<GLuint>::Invalid();
507 }
508
509 return getSamplerIndexFromUniformIndex(index);
510}
511
512bool ProgramState::isSamplerUniformIndex(GLuint index) const
513{
Jamie Madill982f6e02017-06-07 14:33:04 -0400514 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500515}
516
517GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
518{
519 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400520 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500521}
522
Jamie Madill34ca4f52017-06-13 11:49:39 -0400523GLuint ProgramState::getAttributeLocation(const std::string &name) const
524{
525 for (const sh::Attribute &attribute : mAttributes)
526 {
527 if (attribute.name == name)
528 {
529 return attribute.location;
530 }
531 }
532
533 return static_cast<GLuint>(-1);
534}
535
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500536Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400537 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400538 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500539 mLinked(false),
540 mDeleteStatus(false),
541 mRefCount(0),
542 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500543 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500544{
545 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000546
Geoff Lang7dd2e102014-11-10 15:19:26 -0500547 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548}
549
550Program::~Program()
551{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400552 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000553}
554
Jamie Madill4928b7c2017-06-20 12:57:39 -0400555void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500556{
557 if (mState.mAttachedVertexShader != nullptr)
558 {
559 mState.mAttachedVertexShader->release(context);
560 mState.mAttachedVertexShader = nullptr;
561 }
562
563 if (mState.mAttachedFragmentShader != nullptr)
564 {
565 mState.mAttachedFragmentShader->release(context);
566 mState.mAttachedFragmentShader = nullptr;
567 }
568
569 if (mState.mAttachedComputeShader != nullptr)
570 {
571 mState.mAttachedComputeShader->release(context);
572 mState.mAttachedComputeShader = nullptr;
573 }
574
Jamie Madillc564c072017-06-01 12:45:42 -0400575 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400576
577 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
578 !mState.mAttachedComputeShader);
579 SafeDelete(mProgram);
580
581 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500582}
583
Geoff Lang70d0f492015-12-10 17:45:46 -0500584void Program::setLabel(const std::string &label)
585{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400586 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500587}
588
589const std::string &Program::getLabel() const
590{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400591 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500592}
593
Jamie Madillef300b12016-10-07 15:12:09 -0400594void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000595{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300596 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300598 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 {
Jamie Madillef300b12016-10-07 15:12:09 -0400600 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300601 mState.mAttachedVertexShader = shader;
602 mState.mAttachedVertexShader->addRef();
603 break;
604 }
605 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606 {
Jamie Madillef300b12016-10-07 15:12:09 -0400607 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300608 mState.mAttachedFragmentShader = shader;
609 mState.mAttachedFragmentShader->addRef();
610 break;
611 }
612 case GL_COMPUTE_SHADER:
613 {
Jamie Madillef300b12016-10-07 15:12:09 -0400614 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300615 mState.mAttachedComputeShader = shader;
616 mState.mAttachedComputeShader->addRef();
617 break;
618 }
619 default:
620 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622}
623
Jamie Madillc1d770e2017-04-13 17:31:24 -0400624void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000625{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300626 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000627 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300628 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000629 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400630 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500631 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300632 mState.mAttachedVertexShader = nullptr;
633 break;
634 }
635 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400637 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500638 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300639 mState.mAttachedFragmentShader = nullptr;
640 break;
641 }
642 case GL_COMPUTE_SHADER:
643 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400644 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500645 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300646 mState.mAttachedComputeShader = nullptr;
647 break;
648 }
649 default:
650 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652}
653
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000654int Program::getAttachedShadersCount() const
655{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300656 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
657 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000658}
659
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660void Program::bindAttributeLocation(GLuint index, const char *name)
661{
Geoff Langd8605522016-04-13 10:19:12 -0400662 mAttributeBindings.bindLocation(index, name);
663}
664
665void Program::bindUniformLocation(GLuint index, const char *name)
666{
Olli Etuahod2551232017-10-26 20:03:33 +0300667 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668}
669
Sami Väisänen46eaa942016-06-29 10:26:37 +0300670void Program::bindFragmentInputLocation(GLint index, const char *name)
671{
672 mFragmentInputBindings.bindLocation(index, name);
673}
674
Jamie Madillbd044ed2017-06-05 12:59:21 -0400675BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300676{
677 BindingInfo ret;
678 ret.type = GL_NONE;
679 ret.valid = false;
680
Jamie Madillbd044ed2017-06-05 12:59:21 -0400681 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300682 ASSERT(fragmentShader);
683
684 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800685 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300686
687 for (const auto &binding : mFragmentInputBindings)
688 {
689 if (binding.second != static_cast<GLuint>(index))
690 continue;
691
692 ret.valid = true;
693
Olli Etuahod2551232017-10-26 20:03:33 +0300694 size_t nameLengthWithoutArrayIndex;
695 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300696
697 for (const auto &in : inputs)
698 {
Olli Etuahod2551232017-10-26 20:03:33 +0300699 if (in.name.length() == nameLengthWithoutArrayIndex &&
700 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300701 {
702 if (in.isArray())
703 {
704 // The client wants to bind either "name" or "name[0]".
705 // GL ES 3.1 spec refers to active array names with language such as:
706 // "if the string identifies the base name of an active array, where the
707 // string would exactly match the name of the variable if the suffix "[0]"
708 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400709 if (arrayIndex == GL_INVALID_INDEX)
710 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300711
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400712 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300713 }
714 else
715 {
716 ret.name = in.mappedName;
717 }
718 ret.type = in.type;
719 return ret;
720 }
721 }
722 }
723
724 return ret;
725}
726
Jamie Madillbd044ed2017-06-05 12:59:21 -0400727void Program::pathFragmentInputGen(const Context *context,
728 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300729 GLenum genMode,
730 GLint components,
731 const GLfloat *coeffs)
732{
733 // If the location is -1 then the command is silently ignored
734 if (index == -1)
735 return;
736
Jamie Madillbd044ed2017-06-05 12:59:21 -0400737 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300738
739 // If the input doesn't exist then then the command is silently ignored
740 // This could happen through optimization for example, the shader translator
741 // decides that a variable is not actually being used and optimizes it away.
742 if (binding.name.empty())
743 return;
744
745 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
746}
747
Martin Radev4c4c8e72016-08-04 12:25:34 +0300748// The attached shaders are checked for linking errors by matching up their variables.
749// Uniform, input and output variables get collected.
750// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500751Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000752{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500753 const auto &data = context->getContextState();
754
Jamie Madill6c58b062017-08-01 13:44:25 -0400755 auto *platform = ANGLEPlatformCurrent();
756 double startTime = platform->currentTime(platform);
757
Jamie Madill6c1f6712017-02-14 19:08:04 -0500758 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000759
Jamie Madill32447362017-06-28 14:53:52 -0400760 ProgramHash programHash;
761 auto *cache = context->getMemoryProgramCache();
762 if (cache)
763 {
764 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400765 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400766 }
767
768 if (mLinked)
769 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400770 double delta = platform->currentTime(platform) - startTime;
771 int us = static_cast<int>(delta * 1000000.0);
772 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400773 return NoError();
774 }
775
776 // Cache load failed, fall through to normal linking.
777 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000778 mInfoLog.reset();
779
Martin Radev4c4c8e72016-08-04 12:25:34 +0300780 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500781
Jamie Madill192745a2016-12-22 15:58:21 -0500782 auto vertexShader = mState.mAttachedVertexShader;
783 auto fragmentShader = mState.mAttachedFragmentShader;
784 auto computeShader = mState.mAttachedComputeShader;
785
786 bool isComputeShaderAttached = (computeShader != nullptr);
787 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300788 // Check whether we both have a compute and non-compute shaders attached.
789 // If there are of both types attached, then linking should fail.
790 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
791 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500792 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300793 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
794 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400795 }
796
Jamie Madill192745a2016-12-22 15:58:21 -0500797 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500798 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400799 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300800 {
801 mInfoLog << "Attached compute shader is not compiled.";
802 return NoError();
803 }
Jamie Madill192745a2016-12-22 15:58:21 -0500804 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300805
Jamie Madillbd044ed2017-06-05 12:59:21 -0400806 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300807
808 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
809 // If the work group size is not specified, a link time error should occur.
810 if (!mState.mComputeShaderLocalSize.isDeclared())
811 {
812 mInfoLog << "Work group size is not specified.";
813 return NoError();
814 }
815
Jamie Madillbd044ed2017-06-05 12:59:21 -0400816 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300817 {
818 return NoError();
819 }
820
Jiajia Qin729b2c62017-08-14 09:36:11 +0800821 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300822 {
823 return NoError();
824 }
825
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800826 ProgramLinkedResources resources = {
827 {0, PackMode::ANGLE_RELAXED},
828 {&mState.mUniformBlocks, &mState.mUniforms},
829 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500830
831 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
832 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
833
834 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500835 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300836 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500837 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300838 }
839 }
840 else
841 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400842 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300843 {
844 return NoError();
845 }
Jamie Madill192745a2016-12-22 15:58:21 -0500846 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300847
Jamie Madillbd044ed2017-06-05 12:59:21 -0400848 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300849 {
850 return NoError();
851 }
Jamie Madill192745a2016-12-22 15:58:21 -0500852 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300853
Jamie Madillbd044ed2017-06-05 12:59:21 -0400854 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300855 {
856 mInfoLog << "Fragment shader version does not match vertex shader version.";
857 return NoError();
858 }
859
Jamie Madillbd044ed2017-06-05 12:59:21 -0400860 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300861 {
862 return NoError();
863 }
864
Jamie Madillbd044ed2017-06-05 12:59:21 -0400865 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300866 {
867 return NoError();
868 }
869
Jamie Madillbd044ed2017-06-05 12:59:21 -0400870 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300871 {
872 return NoError();
873 }
874
Jiajia Qin729b2c62017-08-14 09:36:11 +0800875 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300876 {
877 return NoError();
878 }
879
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400880 if (!linkValidateGlobalNames(context, mInfoLog))
881 {
882 return NoError();
883 }
884
Jamie Madillbd044ed2017-06-05 12:59:21 -0400885 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300886
Martin Radev7cf61662017-07-26 17:10:53 +0300887 mState.mNumViews = vertexShader->getNumViews(context);
888
Jamie Madillbd044ed2017-06-05 12:59:21 -0400889 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300890
Jamie Madill192745a2016-12-22 15:58:21 -0500891 // Validate we can pack the varyings.
892 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
893
894 // Map the varyings to the register file
895 // In WebGL, we use a slightly different handling for packing variables.
896 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
897 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500898
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800899 ProgramLinkedResources resources = {
900 {data.getCaps().maxVaryingVectors, packMode},
901 {&mState.mUniformBlocks, &mState.mUniforms},
902 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500903
904 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
905 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
906
907 if (!resources.varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
908 mState.getTransformFeedbackVaryingNames()))
Jamie Madill192745a2016-12-22 15:58:21 -0500909 {
910 return NoError();
911 }
912
Olli Etuaho39e78122017-08-29 14:34:22 +0300913 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
914 {
915 return NoError();
916 }
917
Jamie Madillc9727f32017-11-07 12:37:07 -0500918 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500919 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300920 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500921 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300922 }
923
924 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500925 }
926
jchen10eaef1e52017-06-13 10:44:11 +0800927 gatherAtomicCounterBuffers();
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500928 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400929
jchen10eaef1e52017-06-13 10:44:11 +0800930 setUniformValuesFromBindingQualifiers();
931
Jamie Madill54164b02017-08-28 15:17:37 -0400932 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400933 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400934
Jamie Madill32447362017-06-28 14:53:52 -0400935 // Save to the program cache.
936 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
937 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
938 {
939 cache->putProgram(programHash, context, this);
940 }
941
Jamie Madill6c58b062017-08-01 13:44:25 -0400942 double delta = platform->currentTime(platform) - startTime;
943 int us = static_cast<int>(delta * 1000000.0);
944 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
945
Martin Radev4c4c8e72016-08-04 12:25:34 +0300946 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000947}
948
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000949// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500950void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000951{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400952 mState.mAttributes.clear();
953 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -0400954 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +0800955 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400956 mState.mUniforms.clear();
957 mState.mUniformLocations.clear();
958 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +0800959 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +0800960 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400961 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800962 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -0400963 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -0400964 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300965 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500966 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +0800967 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +0300968 mState.mNumViews = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500969
Geoff Lang7dd2e102014-11-10 15:19:26 -0500970 mValidated = false;
971
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000972 mLinked = false;
973}
974
Geoff Lange1a27752015-10-05 13:16:04 -0400975bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000976{
977 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978}
979
Jamie Madilla2c74982016-12-12 11:20:42 -0500980Error Program::loadBinary(const Context *context,
981 GLenum binaryFormat,
982 const void *binary,
983 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000984{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500985 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000986
Geoff Lang7dd2e102014-11-10 15:19:26 -0500987#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800988 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500989#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400990 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
991 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000992 {
Jamie Madillf6113162015-05-07 11:49:21 -0400993 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800994 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500995 }
996
Jamie Madill4f86d052017-06-05 12:59:26 -0400997 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
998 ANGLE_TRY_RESULT(
999 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001000
1001 // Currently we require the full shader text to compute the program hash.
1002 // TODO(jmadill): Store the binary in the internal program cache.
1003
Jamie Madillb0a838b2016-11-13 20:02:12 -05001004 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001005#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001006}
1007
Jamie Madilla2c74982016-12-12 11:20:42 -05001008Error Program::saveBinary(const Context *context,
1009 GLenum *binaryFormat,
1010 void *binary,
1011 GLsizei bufSize,
1012 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001013{
1014 if (binaryFormat)
1015 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001016 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001017 }
1018
Jamie Madill4f86d052017-06-05 12:59:26 -04001019 angle::MemoryBuffer memoryBuf;
1020 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001021
Jamie Madill4f86d052017-06-05 12:59:26 -04001022 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1023 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001024
1025 if (streamLength > bufSize)
1026 {
1027 if (length)
1028 {
1029 *length = 0;
1030 }
1031
1032 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1033 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1034 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001035 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001036 }
1037
1038 if (binary)
1039 {
1040 char *ptr = reinterpret_cast<char*>(binary);
1041
Jamie Madill48ef11b2016-04-27 15:21:52 -04001042 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001043 ptr += streamLength;
1044
1045 ASSERT(ptr - streamLength == binary);
1046 }
1047
1048 if (length)
1049 {
1050 *length = streamLength;
1051 }
1052
He Yunchaoacd18982017-01-04 10:46:42 +08001053 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001054}
1055
Jamie Madillffe00c02017-06-27 16:26:55 -04001056GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001057{
1058 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001059 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001060 if (error.isError())
1061 {
1062 return 0;
1063 }
1064
1065 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001066}
1067
Geoff Langc5629752015-12-07 16:29:04 -05001068void Program::setBinaryRetrievableHint(bool retrievable)
1069{
1070 // TODO(jmadill) : replace with dirty bits
1071 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001072 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001073}
1074
1075bool Program::getBinaryRetrievableHint() const
1076{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001077 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001078}
1079
Yunchao He61afff12017-03-14 15:34:03 +08001080void Program::setSeparable(bool separable)
1081{
1082 // TODO(yunchao) : replace with dirty bits
1083 if (mState.mSeparable != separable)
1084 {
1085 mProgram->setSeparable(separable);
1086 mState.mSeparable = separable;
1087 }
1088}
1089
1090bool Program::isSeparable() const
1091{
1092 return mState.mSeparable;
1093}
1094
Jamie Madill6c1f6712017-02-14 19:08:04 -05001095void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001096{
1097 mRefCount--;
1098
1099 if (mRefCount == 0 && mDeleteStatus)
1100 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001101 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001102 }
1103}
1104
1105void Program::addRef()
1106{
1107 mRefCount++;
1108}
1109
1110unsigned int Program::getRefCount() const
1111{
1112 return mRefCount;
1113}
1114
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001115int Program::getInfoLogLength() const
1116{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001117 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001118}
1119
Geoff Lange1a27752015-10-05 13:16:04 -04001120void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001121{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001122 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001123}
1124
Geoff Lange1a27752015-10-05 13:16:04 -04001125void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001126{
1127 int total = 0;
1128
Martin Radev4c4c8e72016-08-04 12:25:34 +03001129 if (mState.mAttachedComputeShader)
1130 {
1131 if (total < maxCount)
1132 {
1133 shaders[total] = mState.mAttachedComputeShader->getHandle();
1134 total++;
1135 }
1136 }
1137
Jamie Madill48ef11b2016-04-27 15:21:52 -04001138 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001139 {
1140 if (total < maxCount)
1141 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001142 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001143 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001144 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001145 }
1146
Jamie Madill48ef11b2016-04-27 15:21:52 -04001147 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001148 {
1149 if (total < maxCount)
1150 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001151 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001152 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001153 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001154 }
1155
1156 if (count)
1157 {
1158 *count = total;
1159 }
1160}
1161
Geoff Lange1a27752015-10-05 13:16:04 -04001162GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001163{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001164 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001165}
1166
Jamie Madill63805b42015-08-25 13:17:39 -04001167bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001168{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001169 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1170 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001171}
1172
jchen10fd7c3b52017-03-21 15:36:03 +08001173void Program::getActiveAttribute(GLuint index,
1174 GLsizei bufsize,
1175 GLsizei *length,
1176 GLint *size,
1177 GLenum *type,
1178 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001179{
Jamie Madillc349ec02015-08-21 16:53:12 -04001180 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001181 {
1182 if (bufsize > 0)
1183 {
1184 name[0] = '\0';
1185 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001186
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001187 if (length)
1188 {
1189 *length = 0;
1190 }
1191
1192 *type = GL_NONE;
1193 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001194 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001195 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001196
jchen1036e120e2017-03-14 14:53:58 +08001197 ASSERT(index < mState.mAttributes.size());
1198 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001199
1200 if (bufsize > 0)
1201 {
jchen10fd7c3b52017-03-21 15:36:03 +08001202 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001203 }
1204
1205 // Always a single 'type' instance
1206 *size = 1;
1207 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001208}
1209
Geoff Lange1a27752015-10-05 13:16:04 -04001210GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001211{
Jamie Madillc349ec02015-08-21 16:53:12 -04001212 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001213 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001214 return 0;
1215 }
1216
jchen1036e120e2017-03-14 14:53:58 +08001217 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001218}
1219
Geoff Lange1a27752015-10-05 13:16:04 -04001220GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001221{
Jamie Madillc349ec02015-08-21 16:53:12 -04001222 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001223 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001224 return 0;
1225 }
1226
1227 size_t maxLength = 0;
1228
Jamie Madill48ef11b2016-04-27 15:21:52 -04001229 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001230 {
jchen1036e120e2017-03-14 14:53:58 +08001231 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001232 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001233
Jamie Madillc349ec02015-08-21 16:53:12 -04001234 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001235}
1236
jchen1015015f72017-03-16 13:54:21 +08001237GLuint Program::getInputResourceIndex(const GLchar *name) const
1238{
Olli Etuahod2551232017-10-26 20:03:33 +03001239 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001240}
1241
1242GLuint Program::getOutputResourceIndex(const GLchar *name) const
1243{
1244 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1245}
1246
jchen10fd7c3b52017-03-21 15:36:03 +08001247size_t Program::getOutputResourceCount() const
1248{
1249 return (mLinked ? mState.mOutputVariables.size() : 0);
1250}
1251
jchen10baf5d942017-08-28 20:45:48 +08001252template <typename T>
1253void Program::getResourceName(GLuint index,
1254 const std::vector<T> &resources,
1255 GLsizei bufSize,
1256 GLsizei *length,
1257 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001258{
1259 if (length)
1260 {
1261 *length = 0;
1262 }
1263
1264 if (!mLinked)
1265 {
1266 if (bufSize > 0)
1267 {
1268 name[0] = '\0';
1269 }
1270 return;
1271 }
jchen10baf5d942017-08-28 20:45:48 +08001272 ASSERT(index < resources.size());
1273 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001274
1275 if (bufSize > 0)
1276 {
Olli Etuahod2551232017-10-26 20:03:33 +03001277 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001278 }
1279}
1280
jchen10baf5d942017-08-28 20:45:48 +08001281void Program::getInputResourceName(GLuint index,
1282 GLsizei bufSize,
1283 GLsizei *length,
1284 GLchar *name) const
1285{
1286 getResourceName(index, mState.mAttributes, bufSize, length, name);
1287}
1288
1289void Program::getOutputResourceName(GLuint index,
1290 GLsizei bufSize,
1291 GLsizei *length,
1292 GLchar *name) const
1293{
1294 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1295}
1296
1297void Program::getUniformResourceName(GLuint index,
1298 GLsizei bufSize,
1299 GLsizei *length,
1300 GLchar *name) const
1301{
1302 getResourceName(index, mState.mUniforms, bufSize, length, name);
1303}
1304
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001305void Program::getBufferVariableResourceName(GLuint index,
1306 GLsizei bufSize,
1307 GLsizei *length,
1308 GLchar *name) const
1309{
1310 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1311}
1312
jchen10880683b2017-04-12 16:21:55 +08001313const sh::Attribute &Program::getInputResource(GLuint index) const
1314{
1315 ASSERT(index < mState.mAttributes.size());
1316 return mState.mAttributes[index];
1317}
1318
1319const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1320{
1321 ASSERT(index < mState.mOutputVariables.size());
1322 return mState.mOutputVariables[index];
1323}
1324
Geoff Lang7dd2e102014-11-10 15:19:26 -05001325GLint Program::getFragDataLocation(const std::string &name) const
1326{
Olli Etuahod2551232017-10-26 20:03:33 +03001327 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001328}
1329
Geoff Lange1a27752015-10-05 13:16:04 -04001330void Program::getActiveUniform(GLuint index,
1331 GLsizei bufsize,
1332 GLsizei *length,
1333 GLint *size,
1334 GLenum *type,
1335 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001336{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001337 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001338 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001339 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001340 ASSERT(index < mState.mUniforms.size());
1341 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001342
1343 if (bufsize > 0)
1344 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001345 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001346 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001347 }
1348
Jamie Madill62d31cb2015-09-11 13:25:51 -04001349 *size = uniform.elementCount();
1350 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001351 }
1352 else
1353 {
1354 if (bufsize > 0)
1355 {
1356 name[0] = '\0';
1357 }
1358
1359 if (length)
1360 {
1361 *length = 0;
1362 }
1363
1364 *size = 0;
1365 *type = GL_NONE;
1366 }
1367}
1368
Geoff Lange1a27752015-10-05 13:16:04 -04001369GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001370{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001371 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001372 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001373 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001374 }
1375 else
1376 {
1377 return 0;
1378 }
1379}
1380
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001381size_t Program::getActiveBufferVariableCount() const
1382{
1383 return mLinked ? mState.mBufferVariables.size() : 0;
1384}
1385
Geoff Lange1a27752015-10-05 13:16:04 -04001386GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001387{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001388 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001389
1390 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001391 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001392 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001394 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001395 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001396 size_t length = uniform.name.length() + 1u;
1397 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398 {
1399 length += 3; // Counting in "[0]".
1400 }
1401 maxLength = std::max(length, maxLength);
1402 }
1403 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001404 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001405
Jamie Madill62d31cb2015-09-11 13:25:51 -04001406 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001407}
1408
Geoff Lang7dd2e102014-11-10 15:19:26 -05001409bool Program::isValidUniformLocation(GLint location) const
1410{
Jamie Madille2e406c2016-06-02 13:04:10 -04001411 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001412 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001413 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001414}
1415
Jamie Madill62d31cb2015-09-11 13:25:51 -04001416const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001417{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001418 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001419 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001420}
1421
Jamie Madillac4e9c32017-01-13 14:07:12 -05001422const VariableLocation &Program::getUniformLocation(GLint location) const
1423{
1424 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1425 return mState.mUniformLocations[location];
1426}
1427
1428const std::vector<VariableLocation> &Program::getUniformLocations() const
1429{
1430 return mState.mUniformLocations;
1431}
1432
1433const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1434{
1435 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1436 return mState.mUniforms[index];
1437}
1438
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001439const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1440{
1441 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1442 return mState.mBufferVariables[index];
1443}
1444
Jamie Madill62d31cb2015-09-11 13:25:51 -04001445GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446{
Olli Etuahod2551232017-10-26 20:03:33 +03001447 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001448}
1449
Jamie Madill62d31cb2015-09-11 13:25:51 -04001450GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001451{
Jamie Madille7d84322017-01-10 18:21:59 -05001452 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001453}
1454
1455void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1456{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001457 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1458 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001459 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001460}
1461
1462void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1463{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001464 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1465 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001466 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467}
1468
1469void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1470{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001471 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1472 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001473 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001474}
1475
1476void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1477{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001478 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1479 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001480 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481}
1482
Jamie Madill81c2e252017-09-09 23:32:46 -04001483Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001484{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001485 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1486 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1487
Jamie Madill81c2e252017-09-09 23:32:46 -04001488 mProgram->setUniform1iv(location, clampedCount, v);
1489
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001490 if (mState.isSamplerUniformIndex(locationInfo.index))
1491 {
1492 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001493 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001494 }
1495
Jamie Madill81c2e252017-09-09 23:32:46 -04001496 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1500{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001501 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1502 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001503 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504}
1505
1506void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1507{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001508 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1509 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001510 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001511}
1512
1513void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1514{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001515 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1516 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001517 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001518}
1519
1520void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1521{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001522 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1523 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001524 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001525}
1526
1527void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1528{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001529 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1530 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001531 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001532}
1533
1534void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1535{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001536 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1537 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001538 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539}
1540
1541void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1542{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001543 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1544 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001545 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001546}
1547
1548void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1549{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001550 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001551 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001552}
1553
1554void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1555{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001556 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001557 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558}
1559
1560void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1561{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001562 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001563 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564}
1565
1566void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1567{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001568 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001569 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570}
1571
1572void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1573{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001574 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001575 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001576}
1577
1578void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1579{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001580 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001581 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001582}
1583
1584void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1585{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001586 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001587 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001588}
1589
1590void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1591{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001592 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001593 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001594}
1595
1596void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1597{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001598 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001599 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600}
1601
Jamie Madill54164b02017-08-28 15:17:37 -04001602void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001603{
Jamie Madill54164b02017-08-28 15:17:37 -04001604 const auto &uniformLocation = mState.getUniformLocations()[location];
1605 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1606
1607 GLenum nativeType = gl::VariableComponentType(uniform.type);
1608 if (nativeType == GL_FLOAT)
1609 {
1610 mProgram->getUniformfv(context, location, v);
1611 }
1612 else
1613 {
1614 getUniformInternal(context, v, location, nativeType,
1615 gl::VariableComponentCount(uniform.type));
1616 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001617}
1618
Jamie Madill54164b02017-08-28 15:17:37 -04001619void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620{
Jamie Madill54164b02017-08-28 15:17:37 -04001621 const auto &uniformLocation = mState.getUniformLocations()[location];
1622 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1623
1624 GLenum nativeType = gl::VariableComponentType(uniform.type);
1625 if (nativeType == GL_INT || nativeType == GL_BOOL)
1626 {
1627 mProgram->getUniformiv(context, location, v);
1628 }
1629 else
1630 {
1631 getUniformInternal(context, v, location, nativeType,
1632 gl::VariableComponentCount(uniform.type));
1633 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001634}
1635
Jamie Madill54164b02017-08-28 15:17:37 -04001636void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001637{
Jamie Madill54164b02017-08-28 15:17:37 -04001638 const auto &uniformLocation = mState.getUniformLocations()[location];
1639 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1640
1641 GLenum nativeType = gl::VariableComponentType(uniform.type);
1642 if (nativeType == GL_UNSIGNED_INT)
1643 {
1644 mProgram->getUniformuiv(context, location, v);
1645 }
1646 else
1647 {
1648 getUniformInternal(context, v, location, nativeType,
1649 gl::VariableComponentCount(uniform.type));
1650 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001651}
1652
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001653void Program::flagForDeletion()
1654{
1655 mDeleteStatus = true;
1656}
1657
1658bool Program::isFlaggedForDeletion() const
1659{
1660 return mDeleteStatus;
1661}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001662
Brandon Jones43a53e22014-08-28 16:23:22 -07001663void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001664{
1665 mInfoLog.reset();
1666
Geoff Lang7dd2e102014-11-10 15:19:26 -05001667 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001668 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001669 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001670 }
1671 else
1672 {
Jamie Madillf6113162015-05-07 11:49:21 -04001673 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001674 }
1675}
1676
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1678{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001679 // Skip cache if we're using an infolog, so we get the full error.
1680 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1681 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1682 {
1683 return mCachedValidateSamplersResult.value();
1684 }
1685
1686 if (mTextureUnitTypesCache.empty())
1687 {
1688 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1689 }
1690 else
1691 {
1692 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1693 }
1694
1695 // if any two active samplers in a program are of different types, but refer to the same
1696 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1697 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001698 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001699 {
Jamie Madill54164b02017-08-28 15:17:37 -04001700 if (samplerBinding.unreferenced)
1701 continue;
1702
Jamie Madille7d84322017-01-10 18:21:59 -05001703 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001704
Jamie Madille7d84322017-01-10 18:21:59 -05001705 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001706 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001707 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1708 {
1709 if (infoLog)
1710 {
1711 (*infoLog) << "Sampler uniform (" << textureUnit
1712 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1713 << caps.maxCombinedTextureImageUnits << ")";
1714 }
1715
1716 mCachedValidateSamplersResult = false;
1717 return false;
1718 }
1719
1720 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1721 {
1722 if (textureType != mTextureUnitTypesCache[textureUnit])
1723 {
1724 if (infoLog)
1725 {
1726 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1727 "image unit ("
1728 << textureUnit << ").";
1729 }
1730
1731 mCachedValidateSamplersResult = false;
1732 return false;
1733 }
1734 }
1735 else
1736 {
1737 mTextureUnitTypesCache[textureUnit] = textureType;
1738 }
1739 }
1740 }
1741
1742 mCachedValidateSamplersResult = true;
1743 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001744}
1745
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001746bool Program::isValidated() const
1747{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001748 return mValidated;
1749}
1750
Geoff Lange1a27752015-10-05 13:16:04 -04001751GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001752{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001753 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001754}
1755
jchen1058f67be2017-10-27 08:59:27 +08001756GLuint Program::getActiveAtomicCounterBufferCount() const
1757{
1758 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1759}
1760
Jiajia Qin729b2c62017-08-14 09:36:11 +08001761GLuint Program::getActiveShaderStorageBlockCount() const
1762{
1763 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1764}
1765
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001766void Program::getActiveUniformBlockName(const GLuint blockIndex,
1767 GLsizei bufSize,
1768 GLsizei *length,
1769 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001770{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001771 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1772}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001773
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001774void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1775 GLsizei bufSize,
1776 GLsizei *length,
1777 GLchar *blockName) const
1778{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001779
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001780 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001781}
1782
Geoff Lange1a27752015-10-05 13:16:04 -04001783GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001784{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001785 int maxLength = 0;
1786
1787 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001788 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001789 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001790 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1791 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001792 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001793 if (!uniformBlock.name.empty())
1794 {
jchen10af713a22017-04-19 09:10:56 +08001795 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1796 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001797 }
1798 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001799 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001800
1801 return maxLength;
1802}
1803
Geoff Lange1a27752015-10-05 13:16:04 -04001804GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001805{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001806 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1807}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001808
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001809GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1810{
1811 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001812}
1813
Jiajia Qin729b2c62017-08-14 09:36:11 +08001814const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001815{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001816 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1817 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001818}
1819
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001820const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1821{
1822 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1823 return mState.mShaderStorageBlocks[index];
1824}
1825
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001826void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1827{
jchen107a20b972017-06-13 14:25:26 +08001828 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001829 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001830 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001831}
1832
1833GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1834{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001835 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001836}
1837
Jiajia Qin729b2c62017-08-14 09:36:11 +08001838GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1839{
1840 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1841}
1842
Geoff Lang48dcae72014-02-05 16:28:24 -05001843void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1844{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001845 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001846 for (GLsizei i = 0; i < count; i++)
1847 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001848 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001849 }
1850
Jamie Madill48ef11b2016-04-27 15:21:52 -04001851 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001852}
1853
1854void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1855{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001857 {
jchen10a9042d32017-03-17 08:50:45 +08001858 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1859 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1860 std::string varName = var.nameWithArrayIndex();
1861 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001862 if (length)
1863 {
1864 *length = lastNameIdx;
1865 }
1866 if (size)
1867 {
jchen10a9042d32017-03-17 08:50:45 +08001868 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001869 }
1870 if (type)
1871 {
jchen10a9042d32017-03-17 08:50:45 +08001872 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001873 }
1874 if (name)
1875 {
jchen10a9042d32017-03-17 08:50:45 +08001876 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001877 name[lastNameIdx] = '\0';
1878 }
1879 }
1880}
1881
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001882GLsizei Program::getTransformFeedbackVaryingCount() const
1883{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001884 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001885 {
jchen10a9042d32017-03-17 08:50:45 +08001886 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001887 }
1888 else
1889 {
1890 return 0;
1891 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001892}
1893
1894GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1895{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001896 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001897 {
1898 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001899 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001900 {
jchen10a9042d32017-03-17 08:50:45 +08001901 maxSize =
1902 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001903 }
1904
1905 return maxSize;
1906 }
1907 else
1908 {
1909 return 0;
1910 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001911}
1912
1913GLenum Program::getTransformFeedbackBufferMode() const
1914{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001915 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001916}
1917
Jamie Madillbd044ed2017-06-05 12:59:21 -04001918bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001919{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001920 Shader *vertexShader = mState.mAttachedVertexShader;
1921 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001922
Jamie Madillbd044ed2017-06-05 12:59:21 -04001923 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001924
Jiawei Shao3d404882017-10-16 13:30:48 +08001925 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
1926 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001927
Sami Väisänen46eaa942016-06-29 10:26:37 +03001928 std::map<GLuint, std::string> staticFragmentInputLocations;
1929
Jamie Madill4cff2472015-08-21 16:53:18 -04001930 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001932 bool matched = false;
1933
1934 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001935 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001936 {
1937 continue;
1938 }
1939
Jamie Madill4cff2472015-08-21 16:53:18 -04001940 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001941 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001942 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001943 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001944 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001945 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04001946 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001947 {
1948 return false;
1949 }
1950
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951 matched = true;
1952 break;
1953 }
1954 }
1955
1956 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001957 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001958 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001959 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001960 return false;
1961 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001962
1963 // Check for aliased path rendering input bindings (if any).
1964 // If more than one binding refer statically to the same
1965 // location the link must fail.
1966
1967 if (!output.staticUse)
1968 continue;
1969
1970 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1971 if (inputBinding == -1)
1972 continue;
1973
1974 const auto it = staticFragmentInputLocations.find(inputBinding);
1975 if (it == std::end(staticFragmentInputLocations))
1976 {
1977 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1978 }
1979 else
1980 {
1981 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1982 << it->second;
1983 return false;
1984 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001985 }
1986
Jamie Madillbd044ed2017-06-05 12:59:21 -04001987 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05001988 {
1989 return false;
1990 }
1991
Jamie Madillada9ecc2015-08-17 12:53:37 -04001992 // TODO(jmadill): verify no unmatched vertex varyings?
1993
Geoff Lang7dd2e102014-11-10 15:19:26 -05001994 return true;
1995}
1996
Jamie Madillbd044ed2017-06-05 12:59:21 -04001997bool Program::linkUniforms(const Context *context,
1998 InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001999 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002000{
Olli Etuahob78707c2017-03-09 15:03:11 +00002001 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002002 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002003 {
2004 return false;
2005 }
2006
Olli Etuahob78707c2017-03-09 15:03:11 +00002007 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002008
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002009 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002010
jchen10eaef1e52017-06-13 10:44:11 +08002011 if (!linkAtomicCounterBuffers())
2012 {
2013 return false;
2014 }
2015
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002016 return true;
2017}
2018
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002019void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002020{
Jamie Madill982f6e02017-06-07 14:33:04 -04002021 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2022 unsigned int low = high;
2023
jchen10eaef1e52017-06-13 10:44:11 +08002024 for (auto counterIter = mState.mUniforms.rbegin();
2025 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2026 {
2027 --low;
2028 }
2029
2030 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2031
2032 high = low;
2033
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002034 for (auto imageIter = mState.mUniforms.rbegin();
2035 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2036 {
2037 --low;
2038 }
2039
2040 mState.mImageUniformRange = RangeUI(low, high);
2041
2042 // If uniform is a image type, insert it into the mImageBindings array.
2043 for (unsigned int imageIndex : mState.mImageUniformRange)
2044 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002045 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2046 // cannot load values into a uniform defined as an image. if declare without a
2047 // binding qualifier, any uniform image variable (include all elements of
2048 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002049 auto &imageUniform = mState.mUniforms[imageIndex];
2050 if (imageUniform.binding == -1)
2051 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002052 mState.mImageBindings.emplace_back(ImageBinding(imageUniform.elementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002053 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002054 else
2055 {
2056 mState.mImageBindings.emplace_back(
2057 ImageBinding(imageUniform.binding, imageUniform.elementCount()));
2058 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002059 }
2060
2061 high = low;
2062
2063 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002064 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002065 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002066 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002067 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002068
2069 mState.mSamplerUniformRange = RangeUI(low, high);
2070
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002071 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002072 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002073 {
2074 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2075 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2076 mState.mSamplerBindings.emplace_back(
Jamie Madill54164b02017-08-28 15:17:37 -04002077 SamplerBinding(textureType, samplerUniform.elementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002078 }
2079}
2080
jchen10eaef1e52017-06-13 10:44:11 +08002081bool Program::linkAtomicCounterBuffers()
2082{
2083 for (unsigned int index : mState.mAtomicCounterUniformRange)
2084 {
2085 auto &uniform = mState.mUniforms[index];
2086 bool found = false;
2087 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2088 ++bufferIndex)
2089 {
2090 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2091 if (buffer.binding == uniform.binding)
2092 {
2093 buffer.memberIndexes.push_back(index);
2094 uniform.bufferIndex = bufferIndex;
2095 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002096 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002097 break;
2098 }
2099 }
2100 if (!found)
2101 {
2102 AtomicCounterBuffer atomicCounterBuffer;
2103 atomicCounterBuffer.binding = uniform.binding;
2104 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002105 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002106 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2107 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2108 }
2109 }
2110 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2111 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2112
2113 return true;
2114}
2115
Martin Radev4c4c8e72016-08-04 12:25:34 +03002116bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2117 const std::string &uniformName,
2118 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002119 const sh::InterfaceBlockField &fragmentUniform,
2120 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002121{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002122 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2123 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2124 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002125 {
2126 return false;
2127 }
2128
2129 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2130 {
Jamie Madillf6113162015-05-07 11:49:21 -04002131 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002132 return false;
2133 }
2134
2135 return true;
2136}
2137
Jamie Madilleb979bf2016-11-15 12:28:46 -05002138// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002139bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002140{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002141 const ContextState &data = context->getContextState();
2142 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002143
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002145 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002146 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002147
2148 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002149 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002150 {
Jamie Madillf6113162015-05-07 11:49:21 -04002151 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002152 return false;
2153 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002154
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002155 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002156
Jamie Madillc349ec02015-08-21 16:53:12 -04002157 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002158 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002159 {
Olli Etuahod2551232017-10-26 20:03:33 +03002160 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2161 // structures, so we don't need to worry about adjusting their names or generating entries
2162 // for each member/element (unlike uniforms for example).
2163 ASSERT(!attribute.isArray() && !attribute.isStruct());
2164
Jamie Madilleb979bf2016-11-15 12:28:46 -05002165 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002166 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002167 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002168 attribute.location = bindingLocation;
2169 }
2170
2171 if (attribute.location != -1)
2172 {
2173 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002174 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175
Jamie Madill63805b42015-08-25 13:17:39 -04002176 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002177 {
Jamie Madillf6113162015-05-07 11:49:21 -04002178 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002179 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002180
2181 return false;
2182 }
2183
Jamie Madill63805b42015-08-25 13:17:39 -04002184 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185 {
Jamie Madill63805b42015-08-25 13:17:39 -04002186 const int regLocation = attribute.location + reg;
2187 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002188
2189 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002190 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002191 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002192 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002193 // TODO(jmadill): fix aliasing on ES2
2194 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002196 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002197 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002198 return false;
2199 }
2200 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002201 else
2202 {
Jamie Madill63805b42015-08-25 13:17:39 -04002203 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002204 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205
Jamie Madill63805b42015-08-25 13:17:39 -04002206 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002207 }
2208 }
2209 }
2210
2211 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002212 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002213 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002214 // Not set by glBindAttribLocation or by location layout qualifier
2215 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002216 {
Jamie Madill63805b42015-08-25 13:17:39 -04002217 int regs = VariableRegisterCount(attribute.type);
2218 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002219
Jamie Madill63805b42015-08-25 13:17:39 -04002220 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221 {
Jamie Madillf6113162015-05-07 11:49:21 -04002222 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002223 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002224 }
2225
Jamie Madillc349ec02015-08-21 16:53:12 -04002226 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002227 }
2228 }
2229
Jamie Madill48ef11b2016-04-27 15:21:52 -04002230 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002231 {
Jamie Madill63805b42015-08-25 13:17:39 -04002232 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002233 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002234
Jamie Madillbd159f02017-10-09 19:39:06 -04002235 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002236 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002237 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2238 mState.mActiveAttribLocationsMask.set(location);
2239 mState.mMaxActiveAttribLocation =
2240 std::max(mState.mMaxActiveAttribLocation, location + 1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002241 }
2242 }
2243
Geoff Lang7dd2e102014-11-10 15:19:26 -05002244 return true;
2245}
2246
Martin Radev4c4c8e72016-08-04 12:25:34 +03002247bool Program::validateVertexAndFragmentInterfaceBlocks(
2248 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2249 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002250 InfoLog &infoLog,
2251 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002252{
2253 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002254 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2255 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002256
2257 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2258 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002259 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002260 }
2261
Jamie Madille473dee2015-08-18 14:49:01 -04002262 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002263 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002264 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2265 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002266 {
2267 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002268 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2269 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002270 {
2271 return false;
2272 }
2273 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002274 // TODO(jiajia.qin@intel.com): Add
2275 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002276 }
2277 return true;
2278}
Jamie Madille473dee2015-08-18 14:49:01 -04002279
Jiajia Qin729b2c62017-08-14 09:36:11 +08002280bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002281{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002282 const auto &caps = context->getCaps();
2283
Martin Radev4c4c8e72016-08-04 12:25:34 +03002284 if (mState.mAttachedComputeShader)
2285 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002286 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002287 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002288
Jiajia Qin729b2c62017-08-14 09:36:11 +08002289 if (!validateInterfaceBlocksCount(
2290 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002291 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2292 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002293 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002294 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002295 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002296
2297 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2298 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2299 computeShaderStorageBlocks,
2300 "Compute shader shader storage block count exceeds "
2301 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2302 infoLog))
2303 {
2304 return false;
2305 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002306 return true;
2307 }
2308
Jamie Madillbd044ed2017-06-05 12:59:21 -04002309 Shader &vertexShader = *mState.mAttachedVertexShader;
2310 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002311
Jiajia Qin729b2c62017-08-14 09:36:11 +08002312 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2313 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002314
Jiajia Qin729b2c62017-08-14 09:36:11 +08002315 if (!validateInterfaceBlocksCount(
2316 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002317 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2318 {
2319 return false;
2320 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002321 if (!validateInterfaceBlocksCount(
2322 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002323 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2324 infoLog))
2325 {
2326
2327 return false;
2328 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002329
2330 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002331 if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002332 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002333 {
2334 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002335 }
Jamie Madille473dee2015-08-18 14:49:01 -04002336
Jiajia Qin729b2c62017-08-14 09:36:11 +08002337 if (context->getClientVersion() >= Version(3, 1))
2338 {
2339 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2340 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2341
2342 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2343 vertexShaderStorageBlocks,
2344 "Vertex shader shader storage block count exceeds "
2345 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2346 infoLog))
2347 {
2348 return false;
2349 }
2350 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2351 fragmentShaderStorageBlocks,
2352 "Fragment shader shader storage block count exceeds "
2353 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2354 infoLog))
2355 {
2356
2357 return false;
2358 }
2359
2360 if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
2361 fragmentShaderStorageBlocks, infoLog,
2362 webglCompatibility))
2363 {
2364 return false;
2365 }
2366 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002367 return true;
2368}
2369
Jamie Madilla2c74982016-12-12 11:20:42 -05002370bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002371 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002372 const sh::InterfaceBlock &fragmentInterfaceBlock,
2373 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002374{
2375 const char* blockName = vertexInterfaceBlock.name.c_str();
2376 // validate blocks for the same member types
2377 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2378 {
Jamie Madillf6113162015-05-07 11:49:21 -04002379 infoLog << "Types for interface block '" << blockName
2380 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002381 return false;
2382 }
2383 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2384 {
Jamie Madillf6113162015-05-07 11:49:21 -04002385 infoLog << "Array sizes differ for interface block '" << blockName
2386 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002387 return false;
2388 }
jchen10af713a22017-04-19 09:10:56 +08002389 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2390 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2391 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 {
Jamie Madillf6113162015-05-07 11:49:21 -04002393 infoLog << "Layout qualifiers differ for interface block '" << blockName
2394 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002395 return false;
2396 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002397 const unsigned int numBlockMembers =
2398 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002399 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2400 {
2401 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2402 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2403 if (vertexMember.name != fragmentMember.name)
2404 {
Jamie Madillf6113162015-05-07 11:49:21 -04002405 infoLog << "Name mismatch for field " << blockMemberIndex
2406 << " of interface block '" << blockName
2407 << "': (in vertex: '" << vertexMember.name
2408 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002409 return false;
2410 }
2411 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002412 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2413 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002414 {
2415 return false;
2416 }
2417 }
2418 return true;
2419}
2420
2421bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2422 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2423{
2424 if (vertexVariable.type != fragmentVariable.type)
2425 {
Jamie Madillf6113162015-05-07 11:49:21 -04002426 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002427 return false;
2428 }
2429 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2430 {
Jamie Madillf6113162015-05-07 11:49:21 -04002431 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002432 return false;
2433 }
2434 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2435 {
Jamie Madillf6113162015-05-07 11:49:21 -04002436 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002437 return false;
2438 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002439 if (vertexVariable.structName != fragmentVariable.structName)
2440 {
2441 infoLog << "Structure names for " << variableName
2442 << " differ between vertex and fragment shaders";
2443 return false;
2444 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002445
2446 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2447 {
Jamie Madillf6113162015-05-07 11:49:21 -04002448 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002449 return false;
2450 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002451 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002452 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2453 {
2454 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2455 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2456
2457 if (vertexMember.name != fragmentMember.name)
2458 {
Jamie Madillf6113162015-05-07 11:49:21 -04002459 infoLog << "Name mismatch for field '" << memberIndex
2460 << "' of " << variableName
2461 << ": (in vertex: '" << vertexMember.name
2462 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002463 return false;
2464 }
2465
2466 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2467 vertexMember.name + "'";
2468
2469 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2470 {
2471 return false;
2472 }
2473 }
2474
2475 return true;
2476}
2477
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002478bool Program::linkValidateVaryings(InfoLog &infoLog,
2479 const std::string &varyingName,
2480 const sh::Varying &vertexVarying,
2481 const sh::Varying &fragmentVarying,
2482 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002483{
2484 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2485 {
2486 return false;
2487 }
2488
Jamie Madille9cc4692015-02-19 16:00:13 -05002489 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002490 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002491 infoLog << "Interpolation types for " << varyingName
2492 << " differ between vertex and fragment shaders.";
2493 return false;
2494 }
2495
2496 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2497 {
2498 infoLog << "Invariance for " << varyingName
2499 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002500 return false;
2501 }
2502
2503 return true;
2504}
2505
Jamie Madillbd044ed2017-06-05 12:59:21 -04002506bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002507{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002508 Shader *vertexShader = mState.mAttachedVertexShader;
2509 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002510 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2511 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002512 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002513
2514 if (shaderVersion != 100)
2515 {
2516 // Only ESSL 1.0 has restrictions on matching input and output invariance
2517 return true;
2518 }
2519
2520 bool glPositionIsInvariant = false;
2521 bool glPointSizeIsInvariant = false;
2522 bool glFragCoordIsInvariant = false;
2523 bool glPointCoordIsInvariant = false;
2524
2525 for (const sh::Varying &varying : vertexVaryings)
2526 {
2527 if (!varying.isBuiltIn())
2528 {
2529 continue;
2530 }
2531 if (varying.name.compare("gl_Position") == 0)
2532 {
2533 glPositionIsInvariant = varying.isInvariant;
2534 }
2535 else if (varying.name.compare("gl_PointSize") == 0)
2536 {
2537 glPointSizeIsInvariant = varying.isInvariant;
2538 }
2539 }
2540
2541 for (const sh::Varying &varying : fragmentVaryings)
2542 {
2543 if (!varying.isBuiltIn())
2544 {
2545 continue;
2546 }
2547 if (varying.name.compare("gl_FragCoord") == 0)
2548 {
2549 glFragCoordIsInvariant = varying.isInvariant;
2550 }
2551 else if (varying.name.compare("gl_PointCoord") == 0)
2552 {
2553 glPointCoordIsInvariant = varying.isInvariant;
2554 }
2555 }
2556
2557 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2558 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2559 // Not requiring invariance to match is supported by:
2560 // dEQP, WebGL CTS, Nexus 5X GLES
2561 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2562 {
2563 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2564 "declared invariant.";
2565 return false;
2566 }
2567 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2568 {
2569 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2570 "declared invariant.";
2571 return false;
2572 }
2573
2574 return true;
2575}
2576
jchen10a9042d32017-03-17 08:50:45 +08002577bool Program::linkValidateTransformFeedback(const gl::Context *context,
2578 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002579 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002580 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002581{
2582 size_t totalComponents = 0;
2583
Jamie Madillccdf74b2015-08-18 10:46:12 -04002584 std::set<std::string> uniqueNames;
2585
Jamie Madill48ef11b2016-04-27 15:21:52 -04002586 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002587 {
2588 bool found = false;
Olli Etuahoc8538042017-09-27 11:20:15 +03002589 std::vector<unsigned int> subscripts;
2590 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002591
Jamie Madill192745a2016-12-22 15:58:21 -05002592 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002593 {
Jamie Madill192745a2016-12-22 15:58:21 -05002594 const sh::Varying *varying = ref.second.get();
2595
jchen10a9042d32017-03-17 08:50:45 +08002596 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002597 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002598 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002599 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002600 infoLog << "Two transform feedback varyings specify the same output variable ("
2601 << tfVaryingName << ").";
2602 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002603 }
jchen10a9042d32017-03-17 08:50:45 +08002604 if (context->getClientVersion() >= Version(3, 1))
2605 {
2606 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2607 {
2608 infoLog
2609 << "Two transform feedback varyings include the same array element ("
2610 << tfVaryingName << ").";
2611 return false;
2612 }
2613 }
2614 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002615 {
2616 infoLog << "Capture of arrays is undefined and not supported.";
2617 return false;
2618 }
2619
jchen10a9042d32017-03-17 08:50:45 +08002620 uniqueNames.insert(tfVaryingName);
2621
Jamie Madillccdf74b2015-08-18 10:46:12 -04002622 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002623 size_t elementCount =
Olli Etuahoc8538042017-09-27 11:20:15 +03002624 ((varying->isArray() && subscripts.empty()) ? varying->elementCount() : 1);
jchen10a9042d32017-03-17 08:50:45 +08002625 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002626 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002627 componentCount > caps.maxTransformFeedbackSeparateComponents)
2628 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002629 infoLog << "Transform feedback varying's " << varying->name << " components ("
2630 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002631 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002632 return false;
2633 }
2634
2635 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002636 found = true;
2637 break;
2638 }
2639 }
jchen10a9042d32017-03-17 08:50:45 +08002640 if (context->getClientVersion() < Version(3, 1) &&
2641 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002642 {
Geoff Lang1a683462015-09-29 15:09:59 -04002643 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002644 return false;
2645 }
Olli Etuaho39e78122017-08-29 14:34:22 +03002646 // All transform feedback varyings are expected to exist since packUserVaryings checks for
2647 // them.
Geoff Lang7dd2e102014-11-10 15:19:26 -05002648 ASSERT(found);
2649 }
2650
Jamie Madill48ef11b2016-04-27 15:21:52 -04002651 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002652 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002653 {
Jamie Madillf6113162015-05-07 11:49:21 -04002654 infoLog << "Transform feedback varying total components (" << totalComponents
2655 << ") exceed the maximum interleaved components ("
2656 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002657 return false;
2658 }
2659
2660 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002661}
2662
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002663bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
2664{
2665 const std::vector<sh::Uniform> &vertexUniforms =
2666 mState.mAttachedVertexShader->getUniforms(context);
2667 const std::vector<sh::Uniform> &fragmentUniforms =
2668 mState.mAttachedFragmentShader->getUniforms(context);
2669 const std::vector<sh::Attribute> &attributes =
2670 mState.mAttachedVertexShader->getActiveAttributes(context);
2671 for (const auto &attrib : attributes)
2672 {
2673 for (const auto &uniform : vertexUniforms)
2674 {
2675 if (uniform.name == attrib.name)
2676 {
2677 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2678 return false;
2679 }
2680 }
2681 for (const auto &uniform : fragmentUniforms)
2682 {
2683 if (uniform.name == attrib.name)
2684 {
2685 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2686 return false;
2687 }
2688 }
2689 }
2690 return true;
2691}
2692
Jamie Madill192745a2016-12-22 15:58:21 -05002693void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002694{
2695 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002696 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002697 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002698 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002699 std::vector<unsigned int> subscripts;
2700 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002701 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002702 if (!subscripts.empty())
2703 {
2704 subscript = subscripts.back();
2705 }
Jamie Madill192745a2016-12-22 15:58:21 -05002706 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002707 {
Jamie Madill192745a2016-12-22 15:58:21 -05002708 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002709 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002710 {
jchen10a9042d32017-03-17 08:50:45 +08002711 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2712 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002713 break;
2714 }
2715 }
2716 }
2717}
2718
Jamie Madillbd044ed2017-06-05 12:59:21 -04002719Program::MergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002720{
Jamie Madill192745a2016-12-22 15:58:21 -05002721 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002722
Jiawei Shao3d404882017-10-16 13:30:48 +08002723 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002724 {
Jamie Madill192745a2016-12-22 15:58:21 -05002725 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002726 }
2727
Jiawei Shao3d404882017-10-16 13:30:48 +08002728 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002729 {
Jamie Madill192745a2016-12-22 15:58:21 -05002730 merged[varying.name].fragment = &varying;
2731 }
2732
2733 return merged;
2734}
2735
2736std::vector<PackedVarying> Program::getPackedVaryings(
2737 const Program::MergedVaryings &mergedVaryings) const
2738{
2739 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2740 std::vector<PackedVarying> packedVaryings;
jchen10a9042d32017-03-17 08:50:45 +08002741 std::set<std::string> uniqueFullNames;
Jamie Madill192745a2016-12-22 15:58:21 -05002742
2743 for (const auto &ref : mergedVaryings)
2744 {
2745 const sh::Varying *input = ref.second.vertex;
2746 const sh::Varying *output = ref.second.fragment;
2747
2748 // Only pack varyings that have a matched input or output, plus special builtins.
2749 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002750 {
Jamie Madill192745a2016-12-22 15:58:21 -05002751 // Will get the vertex shader interpolation by default.
2752 auto interpolation = ref.second.get()->interpolation;
2753
Olli Etuaho06a06f52017-07-12 12:22:15 +03002754 // Note that we lose the vertex shader static use information here. The data for the
2755 // variable is taken from the fragment shader.
Jamie Madill192745a2016-12-22 15:58:21 -05002756 if (output->isStruct())
2757 {
2758 ASSERT(!output->isArray());
2759 for (const auto &field : output->fields)
2760 {
2761 ASSERT(!field.isStruct() && !field.isArray());
2762 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2763 }
2764 }
2765 else
2766 {
2767 packedVaryings.push_back(PackedVarying(*output, interpolation));
2768 }
2769 continue;
2770 }
2771
2772 // Keep Transform FB varyings in the merged list always.
2773 if (!input)
2774 {
2775 continue;
2776 }
2777
2778 for (const std::string &tfVarying : tfVaryings)
2779 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002780 std::vector<unsigned int> subscripts;
2781 std::string baseName = ParseResourceName(tfVarying, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002782 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002783 if (!subscripts.empty())
2784 {
2785 subscript = subscripts.back();
2786 }
jchen10a9042d32017-03-17 08:50:45 +08002787 if (uniqueFullNames.count(tfVarying) > 0)
2788 {
2789 continue;
2790 }
2791 if (baseName == input->name)
Jamie Madill192745a2016-12-22 15:58:21 -05002792 {
2793 // Transform feedback for varying structs is underspecified.
2794 // See Khronos bug 9856.
2795 // TODO(jmadill): Figure out how to be spec-compliant here.
2796 if (!input->isStruct())
2797 {
2798 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2799 packedVaryings.back().vertexOnly = true;
jchen10a9042d32017-03-17 08:50:45 +08002800 packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
2801 uniqueFullNames.insert(tfVarying);
Jamie Madill192745a2016-12-22 15:58:21 -05002802 }
jchen10a9042d32017-03-17 08:50:45 +08002803 if (subscript == GL_INVALID_INDEX)
2804 {
2805 break;
2806 }
Jamie Madill192745a2016-12-22 15:58:21 -05002807 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002808 }
2809 }
2810
Jamie Madill192745a2016-12-22 15:58:21 -05002811 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2812
2813 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002814}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002815
Jamie Madillbd044ed2017-06-05 12:59:21 -04002816void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002817{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002818 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002819 ASSERT(fragmentShader != nullptr);
2820
Geoff Lange0cff192017-05-30 13:04:56 -04002821 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002822 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002823
2824 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002825 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002826 {
2827 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2828 outputVariable.name != "gl_FragData")
2829 {
2830 continue;
2831 }
2832
2833 unsigned int baseLocation =
2834 (outputVariable.location == -1 ? 0u
2835 : static_cast<unsigned int>(outputVariable.location));
2836 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2837 elementIndex++)
2838 {
2839 const unsigned int location = baseLocation + elementIndex;
2840 if (location >= mState.mOutputVariableTypes.size())
2841 {
2842 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2843 }
Corentin Walleze7557742017-06-01 13:09:57 -04002844 ASSERT(location < mState.mActiveOutputVariables.size());
2845 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002846 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2847 }
2848 }
2849
Jamie Madill80a6fc02015-08-21 16:53:16 -04002850 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002851 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002852 return;
2853
Jamie Madillbd044ed2017-06-05 12:59:21 -04002854 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002855 // TODO(jmadill): any caps validation here?
2856
jchen1015015f72017-03-16 13:54:21 +08002857 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002858 outputVariableIndex++)
2859 {
jchen1015015f72017-03-16 13:54:21 +08002860 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002861
Olli Etuahod2551232017-10-26 20:03:33 +03002862 if (outputVariable.isArray())
2863 {
2864 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2865 // Resources and including [0] at the end of array variable names.
2866 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2867 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2868 }
2869
Jamie Madill80a6fc02015-08-21 16:53:16 -04002870 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2871 if (outputVariable.isBuiltIn())
2872 continue;
2873
2874 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002875 unsigned int baseLocation =
2876 (outputVariable.location == -1 ? 0u
2877 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002878
Jamie Madill80a6fc02015-08-21 16:53:16 -04002879 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2880 elementIndex++)
2881 {
Olli Etuahod2551232017-10-26 20:03:33 +03002882 const unsigned int location = baseLocation + elementIndex;
2883 if (location >= mState.mOutputLocations.size())
2884 {
2885 mState.mOutputLocations.resize(location + 1);
2886 }
2887 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03002888 if (outputVariable.isArray())
2889 {
2890 mState.mOutputLocations[location] =
2891 VariableLocation(elementIndex, outputVariableIndex);
2892 }
2893 else
2894 {
2895 VariableLocation locationInfo;
2896 locationInfo.index = outputVariableIndex;
2897 mState.mOutputLocations[location] = locationInfo;
2898 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04002899 }
2900 }
2901}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002902
Olli Etuaho48fed632017-03-16 12:05:30 +00002903void Program::setUniformValuesFromBindingQualifiers()
2904{
Jamie Madill982f6e02017-06-07 14:33:04 -04002905 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002906 {
2907 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2908 if (samplerUniform.binding != -1)
2909 {
Olli Etuahod2551232017-10-26 20:03:33 +03002910 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00002911 ASSERT(location != -1);
2912 std::vector<GLint> boundTextureUnits;
2913 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2914 ++elementIndex)
2915 {
2916 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2917 }
2918 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2919 boundTextureUnits.data());
2920 }
2921 }
2922}
2923
jchen10eaef1e52017-06-13 10:44:11 +08002924void Program::gatherAtomicCounterBuffers()
2925{
jchen10baf5d942017-08-28 20:45:48 +08002926 for (unsigned int index : mState.mAtomicCounterUniformRange)
2927 {
2928 auto &uniform = mState.mUniforms[index];
2929 uniform.blockInfo.offset = uniform.offset;
2930 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2931 uniform.blockInfo.matrixStride = 0;
2932 uniform.blockInfo.isRowMajorMatrix = false;
2933 }
2934
jchen10eaef1e52017-06-13 10:44:11 +08002935 // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
2936}
2937
Jamie Madill6db1c2e2017-11-08 09:17:40 -05002938void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04002939{
jchen10af713a22017-04-19 09:10:56 +08002940 // Set initial bindings from shader.
2941 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2942 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002943 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08002944 bindUniformBlock(blockIndex, uniformBlock.binding);
2945 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002946}
2947
Jamie Madille7d84322017-01-10 18:21:59 -05002948void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05002949 GLsizei clampedCount,
2950 const GLint *v)
2951{
Jamie Madill81c2e252017-09-09 23:32:46 -04002952 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
2953 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2954 std::vector<GLuint> *boundTextureUnits =
2955 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05002956
Olli Etuaho1734e172017-10-27 15:30:27 +03002957 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04002958
2959 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04002960 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05002961}
2962
2963template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002964GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
2965 GLsizei count,
2966 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05002967 const T *v)
2968{
Jamie Madill134f93d2017-08-31 17:11:00 -04002969 if (count == 1)
2970 return 1;
2971
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002972 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002973
Corentin Wallez15ac5342016-11-03 17:06:39 -04002974 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2975 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03002976 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002977 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002978 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002979
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002980 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002981 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002982 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002983 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002984
2985 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002986}
2987
2988template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002989GLsizei Program::clampMatrixUniformCount(GLint location,
2990 GLsizei count,
2991 GLboolean transpose,
2992 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002993{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002994 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2995
Jamie Madill62d31cb2015-09-11 13:25:51 -04002996 if (!transpose)
2997 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002998 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002999 }
3000
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003001 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003002
3003 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3004 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03003005 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
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