blob: 8296d504d00efee8735edd17e02fb863a40c1888 [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{
Geoff Lang92019432017-11-20 13:09:34 -050074 return (ConvertToBool(value) ? 1.0f : 0.0f);
Jamie Madill62d31cb2015-09-11 13:25:51 -040075}
76
77template <>
78GLint UniformStateQueryCast(GLboolean value)
79{
Geoff Lang92019432017-11-20 13:09:34 -050080 return (ConvertToBool(value) ? 1 : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -040081}
82
83template <>
84GLuint UniformStateQueryCast(GLboolean value)
85{
Geoff Lang92019432017-11-20 13:09:34 -050086 return (ConvertToBool(value) ? 1u : 0u);
Jamie Madill62d31cb2015-09-11 13:25:51 -040087}
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
jchen1015015f72017-03-16 13:54:21 +0800110template <typename VarT>
111GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
112{
Olli Etuahod2551232017-10-26 20:03:33 +0300113 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800114 for (size_t index = 0; index < list.size(); index++)
115 {
116 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300117 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800118 {
Olli Etuahod2551232017-10-26 20:03:33 +0300119 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800120 }
121 }
122
123 return GL_INVALID_INDEX;
124}
125
Olli Etuahod2551232017-10-26 20:03:33 +0300126template <typename VarT>
127GLint GetVariableLocation(const std::vector<VarT> &list,
128 const std::vector<VariableLocation> &locationList,
129 const std::string &name)
130{
131 size_t nameLengthWithoutArrayIndex;
132 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
133
134 for (size_t location = 0u; location < locationList.size(); ++location)
135 {
136 const VariableLocation &variableLocation = locationList[location];
137 if (!variableLocation.used())
138 {
139 continue;
140 }
141
142 const VarT &variable = list[variableLocation.index];
143
144 if (angle::BeginsWith(variable.name, name))
145 {
146 if (name.length() == variable.name.length())
147 {
148 ASSERT(name == variable.name);
149 // GLES 3.1 November 2016 page 87.
150 // The string exactly matches the name of the active variable.
151 return static_cast<GLint>(location);
152 }
153 if (name.length() + 3u == variable.name.length() && variable.isArray())
154 {
155 ASSERT(name + "[0]" == variable.name);
156 // The string identifies the base name of an active array, where the string would
157 // exactly match the name of the variable if the suffix "[0]" were appended to the
158 // string.
159 return static_cast<GLint>(location);
160 }
161 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300162 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300163 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
164 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
165 {
166 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
167 // The string identifies an active element of the array, where the string ends with the
168 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
169 // zeroes, or whitespace) identifying an array element, and the "]" character, the
170 // integer is less than the number of active elements of the array variable, and where
171 // the string would exactly match the enumerated name of the array if the decimal
172 // integer were replaced with zero.
173 return static_cast<GLint>(location);
174 }
175 }
176
177 return -1;
178}
179
jchen10fd7c3b52017-03-21 15:36:03 +0800180void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
181{
182 ASSERT(bufSize > 0);
183 strncpy(buffer, string.c_str(), bufSize);
184 buffer[bufSize - 1] = '\0';
185
186 if (length)
187 {
188 *length = static_cast<GLsizei>(strlen(buffer));
189 }
190}
191
jchen10a9042d32017-03-17 08:50:45 +0800192bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
193{
Olli Etuahoc8538042017-09-27 11:20:15 +0300194 std::vector<unsigned int> subscripts;
195 std::string baseName = ParseResourceName(name, &subscripts);
196 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800197 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300198 std::vector<unsigned int> arrayIndices;
199 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
200 if (baseName == arrayName &&
201 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800202 {
203 return true;
204 }
205 }
206 return false;
207}
208
Jiajia Qin729b2c62017-08-14 09:36:11 +0800209bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
210 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
211 const std::string &errorMessage,
212 InfoLog &infoLog)
213{
214 GLuint blockCount = 0;
215 for (const sh::InterfaceBlock &block : interfaceBlocks)
216 {
217 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
218 {
219 blockCount += (block.arraySize ? block.arraySize : 1);
220 if (blockCount > maxInterfaceBlocks)
221 {
222 infoLog << errorMessage << maxInterfaceBlocks << ")";
223 return false;
224 }
225 }
226 }
227 return true;
228}
229
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800230GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
231{
232 std::vector<unsigned int> subscripts;
233 std::string baseName = ParseResourceName(name, &subscripts);
234
235 unsigned int numBlocks = static_cast<unsigned int>(list.size());
236 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
237 {
238 const auto &block = list[blockIndex];
239 if (block.name == baseName)
240 {
241 const bool arrayElementZero =
242 (subscripts.empty() && (!block.isArray || block.arrayElement == 0));
243 const bool arrayElementMatches =
244 (subscripts.size() == 1 && subscripts[0] == block.arrayElement);
245 if (arrayElementMatches || arrayElementZero)
246 {
247 return blockIndex;
248 }
249 }
250 }
251
252 return GL_INVALID_INDEX;
253}
254
255void GetInterfaceBlockName(const GLuint index,
256 const std::vector<InterfaceBlock> &list,
257 GLsizei bufSize,
258 GLsizei *length,
259 GLchar *name)
260{
261 ASSERT(index < list.size());
262
263 const auto &block = list[index];
264
265 if (bufSize > 0)
266 {
267 std::string blockName = block.name;
268
269 if (block.isArray)
270 {
271 blockName += ArrayString(block.arrayElement);
272 }
273 CopyStringToBuffer(name, blockName, bufSize, length);
274 }
275}
276
Jamie Madillc9727f32017-11-07 12:37:07 -0500277void InitUniformBlockLinker(const gl::Context *context,
278 const ProgramState &state,
279 UniformBlockLinker *blockLinker)
280{
281 if (state.getAttachedVertexShader())
282 {
283 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
284 &state.getAttachedVertexShader()->getUniformBlocks(context));
285 }
286
287 if (state.getAttachedFragmentShader())
288 {
289 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
290 &state.getAttachedFragmentShader()->getUniformBlocks(context));
291 }
292
293 if (state.getAttachedComputeShader())
294 {
295 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
296 &state.getAttachedComputeShader()->getUniformBlocks(context));
297 }
298}
299
300void InitShaderStorageBlockLinker(const gl::Context *context,
301 const ProgramState &state,
302 ShaderStorageBlockLinker *blockLinker)
303{
304 if (state.getAttachedVertexShader())
305 {
306 blockLinker->addShaderBlocks(
307 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
308 }
309
310 if (state.getAttachedFragmentShader())
311 {
312 blockLinker->addShaderBlocks(
313 GL_FRAGMENT_SHADER,
314 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
315 }
316
317 if (state.getAttachedComputeShader())
318 {
319 blockLinker->addShaderBlocks(
320 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
321 }
322}
323
Jamie Madill62d31cb2015-09-11 13:25:51 -0400324} // anonymous namespace
325
Jamie Madill4a3c2342015-10-08 12:58:45 -0400326const char *const g_fakepath = "C:\\fakepath";
327
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400328InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000329{
330}
331
332InfoLog::~InfoLog()
333{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000334}
335
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400336size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000337{
Jamie Madill23176ce2017-07-31 14:14:33 -0400338 if (!mLazyStream)
339 {
340 return 0;
341 }
342
343 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400344 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000345}
346
Geoff Lange1a27752015-10-05 13:16:04 -0400347void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000348{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400349 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000350
351 if (bufSize > 0)
352 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400353 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400354
Jamie Madill23176ce2017-07-31 14:14:33 -0400355 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400357 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
358 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000359 }
360
361 infoLog[index] = '\0';
362 }
363
364 if (length)
365 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400366 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000367 }
368}
369
370// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300371// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000372// messages, so lets remove all occurrences of this fake file path from the log.
373void InfoLog::appendSanitized(const char *message)
374{
Jamie Madill23176ce2017-07-31 14:14:33 -0400375 ensureInitialized();
376
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000377 std::string msg(message);
378
379 size_t found;
380 do
381 {
382 found = msg.find(g_fakepath);
383 if (found != std::string::npos)
384 {
385 msg.erase(found, strlen(g_fakepath));
386 }
387 }
388 while (found != std::string::npos);
389
Jamie Madill23176ce2017-07-31 14:14:33 -0400390 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000391}
392
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000393void InfoLog::reset()
394{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000395}
396
Olli Etuaho1734e172017-10-27 15:30:27 +0300397VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000398{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500399}
400
Olli Etuahoc8538042017-09-27 11:20:15 +0300401VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300402 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500403{
Olli Etuahoc8538042017-09-27 11:20:15 +0300404 ASSERT(arrayIndex != GL_INVALID_INDEX);
405}
406
Geoff Langd8605522016-04-13 10:19:12 -0400407void Program::Bindings::bindLocation(GLuint index, const std::string &name)
408{
409 mBindings[name] = index;
410}
411
412int Program::Bindings::getBinding(const std::string &name) const
413{
414 auto iter = mBindings.find(name);
415 return (iter != mBindings.end()) ? iter->second : -1;
416}
417
418Program::Bindings::const_iterator Program::Bindings::begin() const
419{
420 return mBindings.begin();
421}
422
423Program::Bindings::const_iterator Program::Bindings::end() const
424{
425 return mBindings.end();
426}
427
Jamie Madill48ef11b2016-04-27 15:21:52 -0400428ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500429 : mLabel(),
430 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400431 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300432 mAttachedComputeShader(nullptr),
Jiawei Shao89be29a2017-11-06 14:36:45 +0800433 mAttachedGeometryShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500434 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400435 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500436 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800437 mImageUniformRange(0, 0),
438 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300439 mBinaryRetrieveableHint(false),
440 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400441{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300442 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400443}
444
Jamie Madill48ef11b2016-04-27 15:21:52 -0400445ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400446{
Jiawei Shao89be29a2017-11-06 14:36:45 +0800447 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader &&
448 !mAttachedGeometryShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400449}
450
Jamie Madill48ef11b2016-04-27 15:21:52 -0400451const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500452{
453 return mLabel;
454}
455
Jamie Madille7d84322017-01-10 18:21:59 -0500456GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400457{
jchen1015015f72017-03-16 13:54:21 +0800458 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400459}
460
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800461GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
462{
463 return GetResourceIndexFromName(mBufferVariables, name);
464}
465
Jamie Madille7d84322017-01-10 18:21:59 -0500466GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
467{
468 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
469 return mUniformLocations[location].index;
470}
471
472Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
473{
474 GLuint index = getUniformIndexFromLocation(location);
475 if (!isSamplerUniformIndex(index))
476 {
477 return Optional<GLuint>::Invalid();
478 }
479
480 return getSamplerIndexFromUniformIndex(index);
481}
482
483bool ProgramState::isSamplerUniformIndex(GLuint index) const
484{
Jamie Madill982f6e02017-06-07 14:33:04 -0400485 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500486}
487
488GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
489{
490 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400491 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500492}
493
Jamie Madill34ca4f52017-06-13 11:49:39 -0400494GLuint ProgramState::getAttributeLocation(const std::string &name) const
495{
496 for (const sh::Attribute &attribute : mAttributes)
497 {
498 if (attribute.name == name)
499 {
500 return attribute.location;
501 }
502 }
503
504 return static_cast<GLuint>(-1);
505}
506
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500507Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400508 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400509 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500510 mLinked(false),
511 mDeleteStatus(false),
512 mRefCount(0),
513 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500514 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500515{
516 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000517
Geoff Lang7dd2e102014-11-10 15:19:26 -0500518 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519}
520
521Program::~Program()
522{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400523 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524}
525
Jamie Madill4928b7c2017-06-20 12:57:39 -0400526void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500527{
528 if (mState.mAttachedVertexShader != nullptr)
529 {
530 mState.mAttachedVertexShader->release(context);
531 mState.mAttachedVertexShader = nullptr;
532 }
533
534 if (mState.mAttachedFragmentShader != nullptr)
535 {
536 mState.mAttachedFragmentShader->release(context);
537 mState.mAttachedFragmentShader = nullptr;
538 }
539
540 if (mState.mAttachedComputeShader != nullptr)
541 {
542 mState.mAttachedComputeShader->release(context);
543 mState.mAttachedComputeShader = nullptr;
544 }
545
Jiawei Shao89be29a2017-11-06 14:36:45 +0800546 if (mState.mAttachedGeometryShader != nullptr)
547 {
548 mState.mAttachedGeometryShader->release(context);
549 mState.mAttachedGeometryShader = nullptr;
550 }
551
Jamie Madillc564c072017-06-01 12:45:42 -0400552 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400553
554 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800555 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400556 SafeDelete(mProgram);
557
558 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500559}
560
Geoff Lang70d0f492015-12-10 17:45:46 -0500561void Program::setLabel(const std::string &label)
562{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400563 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500564}
565
566const std::string &Program::getLabel() const
567{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400568 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500569}
570
Jamie Madillef300b12016-10-07 15:12:09 -0400571void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300573 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000574 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300575 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576 {
Jamie Madillef300b12016-10-07 15:12:09 -0400577 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300578 mState.mAttachedVertexShader = shader;
579 mState.mAttachedVertexShader->addRef();
580 break;
581 }
582 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583 {
Jamie Madillef300b12016-10-07 15:12:09 -0400584 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300585 mState.mAttachedFragmentShader = shader;
586 mState.mAttachedFragmentShader->addRef();
587 break;
588 }
589 case GL_COMPUTE_SHADER:
590 {
Jamie Madillef300b12016-10-07 15:12:09 -0400591 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300592 mState.mAttachedComputeShader = shader;
593 mState.mAttachedComputeShader->addRef();
594 break;
595 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800596 case GL_GEOMETRY_SHADER_EXT:
597 {
598 ASSERT(!mState.mAttachedGeometryShader);
599 mState.mAttachedGeometryShader = shader;
600 mState.mAttachedGeometryShader->addRef();
601 break;
602 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300603 default:
604 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606}
607
Jamie Madillc1d770e2017-04-13 17:31:24 -0400608void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000609{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300610 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300612 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000613 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400614 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500615 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300616 mState.mAttachedVertexShader = nullptr;
617 break;
618 }
619 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400621 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500622 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300623 mState.mAttachedFragmentShader = nullptr;
624 break;
625 }
626 case GL_COMPUTE_SHADER:
627 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400628 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500629 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300630 mState.mAttachedComputeShader = nullptr;
631 break;
632 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800633 case GL_GEOMETRY_SHADER_EXT:
634 {
635 ASSERT(mState.mAttachedGeometryShader == shader);
636 shader->release(context);
637 mState.mAttachedGeometryShader = nullptr;
638 break;
639 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300640 default:
641 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643}
644
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000645int Program::getAttachedShadersCount() const
646{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300647 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800648 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000649}
650
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651void Program::bindAttributeLocation(GLuint index, const char *name)
652{
Geoff Langd8605522016-04-13 10:19:12 -0400653 mAttributeBindings.bindLocation(index, name);
654}
655
656void Program::bindUniformLocation(GLuint index, const char *name)
657{
Olli Etuahod2551232017-10-26 20:03:33 +0300658 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659}
660
Sami Väisänen46eaa942016-06-29 10:26:37 +0300661void Program::bindFragmentInputLocation(GLint index, const char *name)
662{
663 mFragmentInputBindings.bindLocation(index, name);
664}
665
Jamie Madillbd044ed2017-06-05 12:59:21 -0400666BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300667{
668 BindingInfo ret;
669 ret.type = GL_NONE;
670 ret.valid = false;
671
Jamie Madillbd044ed2017-06-05 12:59:21 -0400672 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300673 ASSERT(fragmentShader);
674
675 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800676 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300677
678 for (const auto &binding : mFragmentInputBindings)
679 {
680 if (binding.second != static_cast<GLuint>(index))
681 continue;
682
683 ret.valid = true;
684
Olli Etuahod2551232017-10-26 20:03:33 +0300685 size_t nameLengthWithoutArrayIndex;
686 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300687
688 for (const auto &in : inputs)
689 {
Olli Etuahod2551232017-10-26 20:03:33 +0300690 if (in.name.length() == nameLengthWithoutArrayIndex &&
691 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300692 {
693 if (in.isArray())
694 {
695 // The client wants to bind either "name" or "name[0]".
696 // GL ES 3.1 spec refers to active array names with language such as:
697 // "if the string identifies the base name of an active array, where the
698 // string would exactly match the name of the variable if the suffix "[0]"
699 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400700 if (arrayIndex == GL_INVALID_INDEX)
701 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300702
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400703 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300704 }
705 else
706 {
707 ret.name = in.mappedName;
708 }
709 ret.type = in.type;
710 return ret;
711 }
712 }
713 }
714
715 return ret;
716}
717
Jamie Madillbd044ed2017-06-05 12:59:21 -0400718void Program::pathFragmentInputGen(const Context *context,
719 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300720 GLenum genMode,
721 GLint components,
722 const GLfloat *coeffs)
723{
724 // If the location is -1 then the command is silently ignored
725 if (index == -1)
726 return;
727
Jamie Madillbd044ed2017-06-05 12:59:21 -0400728 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300729
730 // If the input doesn't exist then then the command is silently ignored
731 // This could happen through optimization for example, the shader translator
732 // decides that a variable is not actually being used and optimizes it away.
733 if (binding.name.empty())
734 return;
735
736 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
737}
738
Martin Radev4c4c8e72016-08-04 12:25:34 +0300739// The attached shaders are checked for linking errors by matching up their variables.
740// Uniform, input and output variables get collected.
741// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500742Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000743{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500744 const auto &data = context->getContextState();
745
Jamie Madill6c58b062017-08-01 13:44:25 -0400746 auto *platform = ANGLEPlatformCurrent();
747 double startTime = platform->currentTime(platform);
748
Jamie Madill6c1f6712017-02-14 19:08:04 -0500749 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000750
Jamie Madill32447362017-06-28 14:53:52 -0400751 ProgramHash programHash;
752 auto *cache = context->getMemoryProgramCache();
753 if (cache)
754 {
755 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400756 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400757 }
758
759 if (mLinked)
760 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400761 double delta = platform->currentTime(platform) - startTime;
762 int us = static_cast<int>(delta * 1000000.0);
763 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400764 return NoError();
765 }
766
767 // Cache load failed, fall through to normal linking.
768 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000769 mInfoLog.reset();
770
Martin Radev4c4c8e72016-08-04 12:25:34 +0300771 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500772
Jamie Madill192745a2016-12-22 15:58:21 -0500773 auto vertexShader = mState.mAttachedVertexShader;
774 auto fragmentShader = mState.mAttachedFragmentShader;
775 auto computeShader = mState.mAttachedComputeShader;
776
777 bool isComputeShaderAttached = (computeShader != nullptr);
778 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300779 // Check whether we both have a compute and non-compute shaders attached.
780 // If there are of both types attached, then linking should fail.
781 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
782 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500783 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300784 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
785 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400786 }
787
Jamie Madill192745a2016-12-22 15:58:21 -0500788 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500789 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400790 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300791 {
792 mInfoLog << "Attached compute shader is not compiled.";
793 return NoError();
794 }
Jamie Madill192745a2016-12-22 15:58:21 -0500795 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300796
Jamie Madillbd044ed2017-06-05 12:59:21 -0400797 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300798
799 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
800 // If the work group size is not specified, a link time error should occur.
801 if (!mState.mComputeShaderLocalSize.isDeclared())
802 {
803 mInfoLog << "Work group size is not specified.";
804 return NoError();
805 }
806
Jamie Madillbd044ed2017-06-05 12:59:21 -0400807 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300808 {
809 return NoError();
810 }
811
Jiajia Qin729b2c62017-08-14 09:36:11 +0800812 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300813 {
814 return NoError();
815 }
816
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800817 ProgramLinkedResources resources = {
818 {0, PackMode::ANGLE_RELAXED},
819 {&mState.mUniformBlocks, &mState.mUniforms},
820 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500821
822 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
823 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
824
825 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500826 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300827 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500828 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300829 }
830 }
831 else
832 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400833 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300834 {
835 return NoError();
836 }
Jamie Madill192745a2016-12-22 15:58:21 -0500837 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300838
Jamie Madillbd044ed2017-06-05 12:59:21 -0400839 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300840 {
841 return NoError();
842 }
Jamie Madill192745a2016-12-22 15:58:21 -0500843 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300844
Jamie Madillbd044ed2017-06-05 12:59:21 -0400845 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300846 {
847 mInfoLog << "Fragment shader version does not match vertex shader version.";
848 return NoError();
849 }
850
Jamie Madillbd044ed2017-06-05 12:59:21 -0400851 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300852 {
853 return NoError();
854 }
855
Jamie Madillbd044ed2017-06-05 12:59:21 -0400856 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300857 {
858 return NoError();
859 }
860
Jamie Madillbd044ed2017-06-05 12:59:21 -0400861 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300862 {
863 return NoError();
864 }
865
Jiajia Qin729b2c62017-08-14 09:36:11 +0800866 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300867 {
868 return NoError();
869 }
870
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400871 if (!linkValidateGlobalNames(context, mInfoLog))
872 {
873 return NoError();
874 }
875
Jamie Madillbd044ed2017-06-05 12:59:21 -0400876 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300877
Martin Radev7cf61662017-07-26 17:10:53 +0300878 mState.mNumViews = vertexShader->getNumViews(context);
879
Jamie Madillbd044ed2017-06-05 12:59:21 -0400880 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300881
Jamie Madill192745a2016-12-22 15:58:21 -0500882 // Map the varyings to the register file
883 // In WebGL, we use a slightly different handling for packing variables.
884 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
885 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500886
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800887 ProgramLinkedResources resources = {
888 {data.getCaps().maxVaryingVectors, packMode},
889 {&mState.mUniformBlocks, &mState.mUniforms},
890 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500891
892 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
893 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
894
jchen1085c93c42017-11-12 15:36:47 +0800895 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
Jamie Madill192745a2016-12-22 15:58:21 -0500896 {
897 return NoError();
898 }
899
jchen1085c93c42017-11-12 15:36:47 +0800900 if (!resources.varyingPacking.collectAndPackUserVaryings(
901 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +0300902 {
903 return NoError();
904 }
905
Jamie Madillc9727f32017-11-07 12:37:07 -0500906 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500907 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300908 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500909 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300910 }
911
912 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500913 }
914
jchen10eaef1e52017-06-13 10:44:11 +0800915 gatherAtomicCounterBuffers();
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500916 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400917
jchen10eaef1e52017-06-13 10:44:11 +0800918 setUniformValuesFromBindingQualifiers();
919
Jamie Madill54164b02017-08-28 15:17:37 -0400920 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400921 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400922
Jamie Madill32447362017-06-28 14:53:52 -0400923 // Save to the program cache.
924 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
925 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
926 {
927 cache->putProgram(programHash, context, this);
928 }
929
Jamie Madill6c58b062017-08-01 13:44:25 -0400930 double delta = platform->currentTime(platform) - startTime;
931 int us = static_cast<int>(delta * 1000000.0);
932 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
933
Martin Radev4c4c8e72016-08-04 12:25:34 +0300934 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000935}
936
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000937// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500938void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000939{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400940 mState.mAttributes.clear();
941 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -0400942 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +0800943 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400944 mState.mUniforms.clear();
945 mState.mUniformLocations.clear();
946 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +0800947 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +0800948 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400949 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800950 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -0400951 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -0400952 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300953 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500954 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +0800955 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +0300956 mState.mNumViews = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500957
Geoff Lang7dd2e102014-11-10 15:19:26 -0500958 mValidated = false;
959
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000960 mLinked = false;
961}
962
Geoff Lange1a27752015-10-05 13:16:04 -0400963bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000964{
965 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966}
967
Jamie Madilla2c74982016-12-12 11:20:42 -0500968Error Program::loadBinary(const Context *context,
969 GLenum binaryFormat,
970 const void *binary,
971 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000972{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500973 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000974
Geoff Lang7dd2e102014-11-10 15:19:26 -0500975#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800976 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500977#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400978 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
979 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000980 {
Jamie Madillf6113162015-05-07 11:49:21 -0400981 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800982 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500983 }
984
Jamie Madill4f86d052017-06-05 12:59:26 -0400985 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
986 ANGLE_TRY_RESULT(
987 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400988
989 // Currently we require the full shader text to compute the program hash.
990 // TODO(jmadill): Store the binary in the internal program cache.
991
Jamie Madillb0a838b2016-11-13 20:02:12 -0500992 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500993#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500994}
995
Jamie Madilla2c74982016-12-12 11:20:42 -0500996Error Program::saveBinary(const Context *context,
997 GLenum *binaryFormat,
998 void *binary,
999 GLsizei bufSize,
1000 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001{
1002 if (binaryFormat)
1003 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001004 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001005 }
1006
Jamie Madill4f86d052017-06-05 12:59:26 -04001007 angle::MemoryBuffer memoryBuf;
1008 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001009
Jamie Madill4f86d052017-06-05 12:59:26 -04001010 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1011 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001012
1013 if (streamLength > bufSize)
1014 {
1015 if (length)
1016 {
1017 *length = 0;
1018 }
1019
1020 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1021 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1022 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001023 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001024 }
1025
1026 if (binary)
1027 {
1028 char *ptr = reinterpret_cast<char*>(binary);
1029
Jamie Madill48ef11b2016-04-27 15:21:52 -04001030 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001031 ptr += streamLength;
1032
1033 ASSERT(ptr - streamLength == binary);
1034 }
1035
1036 if (length)
1037 {
1038 *length = streamLength;
1039 }
1040
He Yunchaoacd18982017-01-04 10:46:42 +08001041 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042}
1043
Jamie Madillffe00c02017-06-27 16:26:55 -04001044GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001045{
1046 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001047 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001048 if (error.isError())
1049 {
1050 return 0;
1051 }
1052
1053 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001054}
1055
Geoff Langc5629752015-12-07 16:29:04 -05001056void Program::setBinaryRetrievableHint(bool retrievable)
1057{
1058 // TODO(jmadill) : replace with dirty bits
1059 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001060 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001061}
1062
1063bool Program::getBinaryRetrievableHint() const
1064{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001065 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001066}
1067
Yunchao He61afff12017-03-14 15:34:03 +08001068void Program::setSeparable(bool separable)
1069{
1070 // TODO(yunchao) : replace with dirty bits
1071 if (mState.mSeparable != separable)
1072 {
1073 mProgram->setSeparable(separable);
1074 mState.mSeparable = separable;
1075 }
1076}
1077
1078bool Program::isSeparable() const
1079{
1080 return mState.mSeparable;
1081}
1082
Jamie Madill6c1f6712017-02-14 19:08:04 -05001083void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001084{
1085 mRefCount--;
1086
1087 if (mRefCount == 0 && mDeleteStatus)
1088 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001089 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001090 }
1091}
1092
1093void Program::addRef()
1094{
1095 mRefCount++;
1096}
1097
1098unsigned int Program::getRefCount() const
1099{
1100 return mRefCount;
1101}
1102
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001103int Program::getInfoLogLength() const
1104{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001105 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001106}
1107
Geoff Lange1a27752015-10-05 13:16:04 -04001108void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001109{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001110 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001111}
1112
Geoff Lange1a27752015-10-05 13:16:04 -04001113void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001114{
1115 int total = 0;
1116
Martin Radev4c4c8e72016-08-04 12:25:34 +03001117 if (mState.mAttachedComputeShader)
1118 {
1119 if (total < maxCount)
1120 {
1121 shaders[total] = mState.mAttachedComputeShader->getHandle();
1122 total++;
1123 }
1124 }
1125
Jamie Madill48ef11b2016-04-27 15:21:52 -04001126 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001127 {
1128 if (total < maxCount)
1129 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001130 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001131 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001132 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001133 }
1134
Jamie Madill48ef11b2016-04-27 15:21:52 -04001135 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001136 {
1137 if (total < maxCount)
1138 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001139 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001140 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001141 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001142 }
1143
Jiawei Shao89be29a2017-11-06 14:36:45 +08001144 if (mState.mAttachedGeometryShader)
1145 {
1146 if (total < maxCount)
1147 {
1148 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1149 total++;
1150 }
1151 }
1152
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001153 if (count)
1154 {
1155 *count = total;
1156 }
1157}
1158
Geoff Lange1a27752015-10-05 13:16:04 -04001159GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001161 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001162}
1163
Jamie Madill63805b42015-08-25 13:17:39 -04001164bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001165{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001166 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1167 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001168}
1169
jchen10fd7c3b52017-03-21 15:36:03 +08001170void Program::getActiveAttribute(GLuint index,
1171 GLsizei bufsize,
1172 GLsizei *length,
1173 GLint *size,
1174 GLenum *type,
1175 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001176{
Jamie Madillc349ec02015-08-21 16:53:12 -04001177 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001178 {
1179 if (bufsize > 0)
1180 {
1181 name[0] = '\0';
1182 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001183
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001184 if (length)
1185 {
1186 *length = 0;
1187 }
1188
1189 *type = GL_NONE;
1190 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001191 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001192 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001193
jchen1036e120e2017-03-14 14:53:58 +08001194 ASSERT(index < mState.mAttributes.size());
1195 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001196
1197 if (bufsize > 0)
1198 {
jchen10fd7c3b52017-03-21 15:36:03 +08001199 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001200 }
1201
1202 // Always a single 'type' instance
1203 *size = 1;
1204 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001205}
1206
Geoff Lange1a27752015-10-05 13:16:04 -04001207GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001208{
Jamie Madillc349ec02015-08-21 16:53:12 -04001209 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001210 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001211 return 0;
1212 }
1213
jchen1036e120e2017-03-14 14:53:58 +08001214 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001215}
1216
Geoff Lange1a27752015-10-05 13:16:04 -04001217GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001218{
Jamie Madillc349ec02015-08-21 16:53:12 -04001219 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001220 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001221 return 0;
1222 }
1223
1224 size_t maxLength = 0;
1225
Jamie Madill48ef11b2016-04-27 15:21:52 -04001226 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001227 {
jchen1036e120e2017-03-14 14:53:58 +08001228 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001229 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001230
Jamie Madillc349ec02015-08-21 16:53:12 -04001231 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001232}
1233
jchen1015015f72017-03-16 13:54:21 +08001234GLuint Program::getInputResourceIndex(const GLchar *name) const
1235{
Olli Etuahod2551232017-10-26 20:03:33 +03001236 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001237}
1238
1239GLuint Program::getOutputResourceIndex(const GLchar *name) const
1240{
1241 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1242}
1243
jchen10fd7c3b52017-03-21 15:36:03 +08001244size_t Program::getOutputResourceCount() const
1245{
1246 return (mLinked ? mState.mOutputVariables.size() : 0);
1247}
1248
jchen10baf5d942017-08-28 20:45:48 +08001249template <typename T>
1250void Program::getResourceName(GLuint index,
1251 const std::vector<T> &resources,
1252 GLsizei bufSize,
1253 GLsizei *length,
1254 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001255{
1256 if (length)
1257 {
1258 *length = 0;
1259 }
1260
1261 if (!mLinked)
1262 {
1263 if (bufSize > 0)
1264 {
1265 name[0] = '\0';
1266 }
1267 return;
1268 }
jchen10baf5d942017-08-28 20:45:48 +08001269 ASSERT(index < resources.size());
1270 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001271
1272 if (bufSize > 0)
1273 {
Olli Etuahod2551232017-10-26 20:03:33 +03001274 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001275 }
1276}
1277
jchen10baf5d942017-08-28 20:45:48 +08001278void Program::getInputResourceName(GLuint index,
1279 GLsizei bufSize,
1280 GLsizei *length,
1281 GLchar *name) const
1282{
1283 getResourceName(index, mState.mAttributes, bufSize, length, name);
1284}
1285
1286void Program::getOutputResourceName(GLuint index,
1287 GLsizei bufSize,
1288 GLsizei *length,
1289 GLchar *name) const
1290{
1291 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1292}
1293
1294void Program::getUniformResourceName(GLuint index,
1295 GLsizei bufSize,
1296 GLsizei *length,
1297 GLchar *name) const
1298{
1299 getResourceName(index, mState.mUniforms, bufSize, length, name);
1300}
1301
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001302void Program::getBufferVariableResourceName(GLuint index,
1303 GLsizei bufSize,
1304 GLsizei *length,
1305 GLchar *name) const
1306{
1307 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1308}
1309
jchen10880683b2017-04-12 16:21:55 +08001310const sh::Attribute &Program::getInputResource(GLuint index) const
1311{
1312 ASSERT(index < mState.mAttributes.size());
1313 return mState.mAttributes[index];
1314}
1315
1316const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1317{
1318 ASSERT(index < mState.mOutputVariables.size());
1319 return mState.mOutputVariables[index];
1320}
1321
Geoff Lang7dd2e102014-11-10 15:19:26 -05001322GLint Program::getFragDataLocation(const std::string &name) const
1323{
Olli Etuahod2551232017-10-26 20:03:33 +03001324 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001325}
1326
Geoff Lange1a27752015-10-05 13:16:04 -04001327void Program::getActiveUniform(GLuint index,
1328 GLsizei bufsize,
1329 GLsizei *length,
1330 GLint *size,
1331 GLenum *type,
1332 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001333{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001334 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001335 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001336 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001337 ASSERT(index < mState.mUniforms.size());
1338 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001339
1340 if (bufsize > 0)
1341 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001342 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001343 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001344 }
1345
Jamie Madill62d31cb2015-09-11 13:25:51 -04001346 *size = uniform.elementCount();
1347 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001348 }
1349 else
1350 {
1351 if (bufsize > 0)
1352 {
1353 name[0] = '\0';
1354 }
1355
1356 if (length)
1357 {
1358 *length = 0;
1359 }
1360
1361 *size = 0;
1362 *type = GL_NONE;
1363 }
1364}
1365
Geoff Lange1a27752015-10-05 13:16:04 -04001366GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001367{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001368 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001369 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001370 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001371 }
1372 else
1373 {
1374 return 0;
1375 }
1376}
1377
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001378size_t Program::getActiveBufferVariableCount() const
1379{
1380 return mLinked ? mState.mBufferVariables.size() : 0;
1381}
1382
Geoff Lange1a27752015-10-05 13:16:04 -04001383GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001384{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001385 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386
1387 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001388 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001389 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001391 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001393 size_t length = uniform.name.length() + 1u;
1394 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001395 {
1396 length += 3; // Counting in "[0]".
1397 }
1398 maxLength = std::max(length, maxLength);
1399 }
1400 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001401 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001402
Jamie Madill62d31cb2015-09-11 13:25:51 -04001403 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001404}
1405
Geoff Lang7dd2e102014-11-10 15:19:26 -05001406bool Program::isValidUniformLocation(GLint location) const
1407{
Jamie Madille2e406c2016-06-02 13:04:10 -04001408 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001409 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001410 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001411}
1412
Jamie Madill62d31cb2015-09-11 13:25:51 -04001413const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001414{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001415 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001416 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001417}
1418
Jamie Madillac4e9c32017-01-13 14:07:12 -05001419const VariableLocation &Program::getUniformLocation(GLint location) const
1420{
1421 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1422 return mState.mUniformLocations[location];
1423}
1424
1425const std::vector<VariableLocation> &Program::getUniformLocations() const
1426{
1427 return mState.mUniformLocations;
1428}
1429
1430const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1431{
1432 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1433 return mState.mUniforms[index];
1434}
1435
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001436const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1437{
1438 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1439 return mState.mBufferVariables[index];
1440}
1441
Jamie Madill62d31cb2015-09-11 13:25:51 -04001442GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443{
Olli Etuahod2551232017-10-26 20:03:33 +03001444 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001445}
1446
Jamie Madill62d31cb2015-09-11 13:25:51 -04001447GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001448{
Jamie Madille7d84322017-01-10 18:21:59 -05001449 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001450}
1451
1452void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1453{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001454 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1455 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001456 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001457}
1458
1459void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1460{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001461 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1462 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001463 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001464}
1465
1466void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1467{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001468 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1469 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001470 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471}
1472
1473void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1474{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001475 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1476 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001477 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478}
1479
Jamie Madill81c2e252017-09-09 23:32:46 -04001480Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001481{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001482 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1483 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1484
Jamie Madill81c2e252017-09-09 23:32:46 -04001485 mProgram->setUniform1iv(location, clampedCount, v);
1486
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001487 if (mState.isSamplerUniformIndex(locationInfo.index))
1488 {
1489 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001490 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001491 }
1492
Jamie Madill81c2e252017-09-09 23:32:46 -04001493 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494}
1495
1496void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1497{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001498 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1499 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001500 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001501}
1502
1503void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1504{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001505 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1506 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001507 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001508}
1509
1510void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1511{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001512 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1513 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001514 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1518{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001519 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1520 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001521 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001522}
1523
1524void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1525{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001526 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1527 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001528 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001529}
1530
1531void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1532{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001533 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1534 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001535 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001536}
1537
1538void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1539{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001540 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1541 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001542 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001543}
1544
1545void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1546{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001547 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001548 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001549}
1550
1551void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1552{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001553 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001554 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001555}
1556
1557void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1558{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001559 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001560 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561}
1562
1563void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1564{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001565 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001566 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001567}
1568
1569void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1570{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001571 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001572 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001573}
1574
1575void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1576{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001577 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001578 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001579}
1580
1581void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1582{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001583 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001584 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001585}
1586
1587void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1588{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001589 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001590 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001591}
1592
1593void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1594{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001595 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001596 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001597}
1598
Jamie Madill54164b02017-08-28 15:17:37 -04001599void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600{
Jamie Madill54164b02017-08-28 15:17:37 -04001601 const auto &uniformLocation = mState.getUniformLocations()[location];
1602 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1603
1604 GLenum nativeType = gl::VariableComponentType(uniform.type);
1605 if (nativeType == GL_FLOAT)
1606 {
1607 mProgram->getUniformfv(context, location, v);
1608 }
1609 else
1610 {
1611 getUniformInternal(context, v, location, nativeType,
1612 gl::VariableComponentCount(uniform.type));
1613 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001614}
1615
Jamie Madill54164b02017-08-28 15:17:37 -04001616void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001617{
Jamie Madill54164b02017-08-28 15:17:37 -04001618 const auto &uniformLocation = mState.getUniformLocations()[location];
1619 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1620
1621 GLenum nativeType = gl::VariableComponentType(uniform.type);
1622 if (nativeType == GL_INT || nativeType == GL_BOOL)
1623 {
1624 mProgram->getUniformiv(context, location, v);
1625 }
1626 else
1627 {
1628 getUniformInternal(context, v, location, nativeType,
1629 gl::VariableComponentCount(uniform.type));
1630 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001631}
1632
Jamie Madill54164b02017-08-28 15:17:37 -04001633void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001634{
Jamie Madill54164b02017-08-28 15:17:37 -04001635 const auto &uniformLocation = mState.getUniformLocations()[location];
1636 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1637
1638 GLenum nativeType = gl::VariableComponentType(uniform.type);
1639 if (nativeType == GL_UNSIGNED_INT)
1640 {
1641 mProgram->getUniformuiv(context, location, v);
1642 }
1643 else
1644 {
1645 getUniformInternal(context, v, location, nativeType,
1646 gl::VariableComponentCount(uniform.type));
1647 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001648}
1649
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001650void Program::flagForDeletion()
1651{
1652 mDeleteStatus = true;
1653}
1654
1655bool Program::isFlaggedForDeletion() const
1656{
1657 return mDeleteStatus;
1658}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001659
Brandon Jones43a53e22014-08-28 16:23:22 -07001660void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001661{
1662 mInfoLog.reset();
1663
Geoff Lang7dd2e102014-11-10 15:19:26 -05001664 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001665 {
Geoff Lang92019432017-11-20 13:09:34 -05001666 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001667 }
1668 else
1669 {
Jamie Madillf6113162015-05-07 11:49:21 -04001670 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001671 }
1672}
1673
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1675{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001676 // Skip cache if we're using an infolog, so we get the full error.
1677 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1678 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1679 {
1680 return mCachedValidateSamplersResult.value();
1681 }
1682
1683 if (mTextureUnitTypesCache.empty())
1684 {
1685 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1686 }
1687 else
1688 {
1689 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1690 }
1691
1692 // if any two active samplers in a program are of different types, but refer to the same
1693 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1694 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001695 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001696 {
Jamie Madill54164b02017-08-28 15:17:37 -04001697 if (samplerBinding.unreferenced)
1698 continue;
1699
Jamie Madille7d84322017-01-10 18:21:59 -05001700 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001701
Jamie Madille7d84322017-01-10 18:21:59 -05001702 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001703 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001704 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1705 {
1706 if (infoLog)
1707 {
1708 (*infoLog) << "Sampler uniform (" << textureUnit
1709 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1710 << caps.maxCombinedTextureImageUnits << ")";
1711 }
1712
1713 mCachedValidateSamplersResult = false;
1714 return false;
1715 }
1716
1717 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1718 {
1719 if (textureType != mTextureUnitTypesCache[textureUnit])
1720 {
1721 if (infoLog)
1722 {
1723 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1724 "image unit ("
1725 << textureUnit << ").";
1726 }
1727
1728 mCachedValidateSamplersResult = false;
1729 return false;
1730 }
1731 }
1732 else
1733 {
1734 mTextureUnitTypesCache[textureUnit] = textureType;
1735 }
1736 }
1737 }
1738
1739 mCachedValidateSamplersResult = true;
1740 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001741}
1742
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001743bool Program::isValidated() const
1744{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001745 return mValidated;
1746}
1747
Geoff Lange1a27752015-10-05 13:16:04 -04001748GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001749{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001750 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001751}
1752
jchen1058f67be2017-10-27 08:59:27 +08001753GLuint Program::getActiveAtomicCounterBufferCount() const
1754{
1755 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1756}
1757
Jiajia Qin729b2c62017-08-14 09:36:11 +08001758GLuint Program::getActiveShaderStorageBlockCount() const
1759{
1760 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1761}
1762
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001763void Program::getActiveUniformBlockName(const GLuint blockIndex,
1764 GLsizei bufSize,
1765 GLsizei *length,
1766 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001767{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001768 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1769}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001770
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001771void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1772 GLsizei bufSize,
1773 GLsizei *length,
1774 GLchar *blockName) const
1775{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001776
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001777 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001778}
1779
Geoff Lange1a27752015-10-05 13:16:04 -04001780GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001781{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001782 int maxLength = 0;
1783
1784 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001785 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001787 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1788 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001789 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001790 if (!uniformBlock.name.empty())
1791 {
jchen10af713a22017-04-19 09:10:56 +08001792 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1793 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001794 }
1795 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001796 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001797
1798 return maxLength;
1799}
1800
Geoff Lange1a27752015-10-05 13:16:04 -04001801GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001803 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1804}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001805
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001806GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1807{
1808 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001809}
1810
Jiajia Qin729b2c62017-08-14 09:36:11 +08001811const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001812{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001813 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1814 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001815}
1816
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001817const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1818{
1819 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1820 return mState.mShaderStorageBlocks[index];
1821}
1822
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001823void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1824{
jchen107a20b972017-06-13 14:25:26 +08001825 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001826 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001827 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001828}
1829
1830GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1831{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001832 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001833}
1834
Jiajia Qin729b2c62017-08-14 09:36:11 +08001835GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1836{
1837 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1838}
1839
Geoff Lang48dcae72014-02-05 16:28:24 -05001840void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1841{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001842 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001843 for (GLsizei i = 0; i < count; i++)
1844 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001845 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001846 }
1847
Jamie Madill48ef11b2016-04-27 15:21:52 -04001848 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001849}
1850
1851void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1852{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001853 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001854 {
jchen10a9042d32017-03-17 08:50:45 +08001855 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1856 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1857 std::string varName = var.nameWithArrayIndex();
1858 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001859 if (length)
1860 {
1861 *length = lastNameIdx;
1862 }
1863 if (size)
1864 {
jchen10a9042d32017-03-17 08:50:45 +08001865 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001866 }
1867 if (type)
1868 {
jchen10a9042d32017-03-17 08:50:45 +08001869 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001870 }
1871 if (name)
1872 {
jchen10a9042d32017-03-17 08:50:45 +08001873 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001874 name[lastNameIdx] = '\0';
1875 }
1876 }
1877}
1878
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001879GLsizei Program::getTransformFeedbackVaryingCount() const
1880{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001881 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001882 {
jchen10a9042d32017-03-17 08:50:45 +08001883 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001884 }
1885 else
1886 {
1887 return 0;
1888 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001889}
1890
1891GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1892{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001893 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001894 {
1895 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001896 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001897 {
jchen10a9042d32017-03-17 08:50:45 +08001898 maxSize =
1899 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001900 }
1901
1902 return maxSize;
1903 }
1904 else
1905 {
1906 return 0;
1907 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001908}
1909
1910GLenum Program::getTransformFeedbackBufferMode() const
1911{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001912 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001913}
1914
Jamie Madillbd044ed2017-06-05 12:59:21 -04001915bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001916{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001917 Shader *vertexShader = mState.mAttachedVertexShader;
1918 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001919
Jamie Madillbd044ed2017-06-05 12:59:21 -04001920 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001921
Jiawei Shao3d404882017-10-16 13:30:48 +08001922 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
1923 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924
Sami Väisänen46eaa942016-06-29 10:26:37 +03001925 std::map<GLuint, std::string> staticFragmentInputLocations;
1926
Jamie Madill4cff2472015-08-21 16:53:18 -04001927 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001928 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001929 bool matched = false;
1930
1931 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001932 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001933 {
1934 continue;
1935 }
1936
Jamie Madill4cff2472015-08-21 16:53:18 -04001937 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001939 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001940 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001941 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001942 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04001943 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001944 {
1945 return false;
1946 }
1947
Geoff Lang7dd2e102014-11-10 15:19:26 -05001948 matched = true;
1949 break;
1950 }
1951 }
1952
1953 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001954 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001955 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001956 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001957 return false;
1958 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001959
1960 // Check for aliased path rendering input bindings (if any).
1961 // If more than one binding refer statically to the same
1962 // location the link must fail.
1963
1964 if (!output.staticUse)
1965 continue;
1966
1967 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1968 if (inputBinding == -1)
1969 continue;
1970
1971 const auto it = staticFragmentInputLocations.find(inputBinding);
1972 if (it == std::end(staticFragmentInputLocations))
1973 {
1974 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1975 }
1976 else
1977 {
1978 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1979 << it->second;
1980 return false;
1981 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001982 }
1983
Jamie Madillbd044ed2017-06-05 12:59:21 -04001984 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05001985 {
1986 return false;
1987 }
1988
Jamie Madillada9ecc2015-08-17 12:53:37 -04001989 // TODO(jmadill): verify no unmatched vertex varyings?
1990
Geoff Lang7dd2e102014-11-10 15:19:26 -05001991 return true;
1992}
1993
Jamie Madillbd044ed2017-06-05 12:59:21 -04001994bool Program::linkUniforms(const Context *context,
1995 InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001996 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001997{
Olli Etuahob78707c2017-03-09 15:03:11 +00001998 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04001999 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002000 {
2001 return false;
2002 }
2003
Olli Etuahob78707c2017-03-09 15:03:11 +00002004 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002005
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002006 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002007
jchen10eaef1e52017-06-13 10:44:11 +08002008 if (!linkAtomicCounterBuffers())
2009 {
2010 return false;
2011 }
2012
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002013 return true;
2014}
2015
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002016void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002017{
Jamie Madill982f6e02017-06-07 14:33:04 -04002018 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2019 unsigned int low = high;
2020
jchen10eaef1e52017-06-13 10:44:11 +08002021 for (auto counterIter = mState.mUniforms.rbegin();
2022 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2023 {
2024 --low;
2025 }
2026
2027 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2028
2029 high = low;
2030
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002031 for (auto imageIter = mState.mUniforms.rbegin();
2032 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2033 {
2034 --low;
2035 }
2036
2037 mState.mImageUniformRange = RangeUI(low, high);
2038
2039 // If uniform is a image type, insert it into the mImageBindings array.
2040 for (unsigned int imageIndex : mState.mImageUniformRange)
2041 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002042 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2043 // cannot load values into a uniform defined as an image. if declare without a
2044 // binding qualifier, any uniform image variable (include all elements of
2045 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002046 auto &imageUniform = mState.mUniforms[imageIndex];
2047 if (imageUniform.binding == -1)
2048 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002049 mState.mImageBindings.emplace_back(ImageBinding(imageUniform.elementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002050 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002051 else
2052 {
2053 mState.mImageBindings.emplace_back(
2054 ImageBinding(imageUniform.binding, imageUniform.elementCount()));
2055 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002056 }
2057
2058 high = low;
2059
2060 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002061 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002062 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002063 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002064 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002065
2066 mState.mSamplerUniformRange = RangeUI(low, high);
2067
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002068 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002069 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002070 {
2071 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2072 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2073 mState.mSamplerBindings.emplace_back(
Jamie Madill54164b02017-08-28 15:17:37 -04002074 SamplerBinding(textureType, samplerUniform.elementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002075 }
2076}
2077
jchen10eaef1e52017-06-13 10:44:11 +08002078bool Program::linkAtomicCounterBuffers()
2079{
2080 for (unsigned int index : mState.mAtomicCounterUniformRange)
2081 {
2082 auto &uniform = mState.mUniforms[index];
2083 bool found = false;
2084 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2085 ++bufferIndex)
2086 {
2087 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2088 if (buffer.binding == uniform.binding)
2089 {
2090 buffer.memberIndexes.push_back(index);
2091 uniform.bufferIndex = bufferIndex;
2092 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002093 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002094 break;
2095 }
2096 }
2097 if (!found)
2098 {
2099 AtomicCounterBuffer atomicCounterBuffer;
2100 atomicCounterBuffer.binding = uniform.binding;
2101 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002102 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002103 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2104 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2105 }
2106 }
2107 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2108 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2109
2110 return true;
2111}
2112
Martin Radev4c4c8e72016-08-04 12:25:34 +03002113bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2114 const std::string &uniformName,
2115 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002116 const sh::InterfaceBlockField &fragmentUniform,
2117 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002118{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002119 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2120 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2121 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002122 {
2123 return false;
2124 }
2125
2126 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2127 {
Jamie Madillf6113162015-05-07 11:49:21 -04002128 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002129 return false;
2130 }
2131
2132 return true;
2133}
2134
Jamie Madilleb979bf2016-11-15 12:28:46 -05002135// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002136bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002137{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002138 const ContextState &data = context->getContextState();
2139 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002140
Geoff Lang7dd2e102014-11-10 15:19:26 -05002141 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002142 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002143 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002144
2145 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002146 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002147 {
Jamie Madillf6113162015-05-07 11:49:21 -04002148 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002149 return false;
2150 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002151
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002152 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002153
Jamie Madillc349ec02015-08-21 16:53:12 -04002154 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002155 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002156 {
Olli Etuahod2551232017-10-26 20:03:33 +03002157 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2158 // structures, so we don't need to worry about adjusting their names or generating entries
2159 // for each member/element (unlike uniforms for example).
2160 ASSERT(!attribute.isArray() && !attribute.isStruct());
2161
Jamie Madilleb979bf2016-11-15 12:28:46 -05002162 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002163 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002164 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002165 attribute.location = bindingLocation;
2166 }
2167
2168 if (attribute.location != -1)
2169 {
2170 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002171 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002172
Jamie Madill63805b42015-08-25 13:17:39 -04002173 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 {
Jamie Madillf6113162015-05-07 11:49:21 -04002175 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002176 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002177
2178 return false;
2179 }
2180
Jamie Madill63805b42015-08-25 13:17:39 -04002181 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002182 {
Jamie Madill63805b42015-08-25 13:17:39 -04002183 const int regLocation = attribute.location + reg;
2184 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185
2186 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002187 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002188 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002190 // TODO(jmadill): fix aliasing on ES2
2191 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002192 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002193 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002194 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195 return false;
2196 }
2197 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002198 else
2199 {
Jamie Madill63805b42015-08-25 13:17:39 -04002200 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002201 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002202
Jamie Madill63805b42015-08-25 13:17:39 -04002203 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002204 }
2205 }
2206 }
2207
2208 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002209 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002210 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002211 // Not set by glBindAttribLocation or by location layout qualifier
2212 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002213 {
Jamie Madill63805b42015-08-25 13:17:39 -04002214 int regs = VariableRegisterCount(attribute.type);
2215 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002216
Jamie Madill63805b42015-08-25 13:17:39 -04002217 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002218 {
Jamie Madillf6113162015-05-07 11:49:21 -04002219 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002220 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221 }
2222
Jamie Madillc349ec02015-08-21 16:53:12 -04002223 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002224 }
2225 }
2226
Jamie Madill48ef11b2016-04-27 15:21:52 -04002227 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002228 {
Jamie Madill63805b42015-08-25 13:17:39 -04002229 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002230 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002231
Jamie Madillbd159f02017-10-09 19:39:06 -04002232 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002233 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002234 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2235 mState.mActiveAttribLocationsMask.set(location);
2236 mState.mMaxActiveAttribLocation =
2237 std::max(mState.mMaxActiveAttribLocation, location + 1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002238 }
2239 }
2240
Geoff Lang7dd2e102014-11-10 15:19:26 -05002241 return true;
2242}
2243
Martin Radev4c4c8e72016-08-04 12:25:34 +03002244bool Program::validateVertexAndFragmentInterfaceBlocks(
2245 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2246 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002247 InfoLog &infoLog,
2248 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002249{
2250 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002251 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2252 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002253
2254 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2255 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002256 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002257 }
2258
Jamie Madille473dee2015-08-18 14:49:01 -04002259 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002260 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002261 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2262 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002263 {
2264 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002265 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2266 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002267 {
2268 return false;
2269 }
2270 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002271 // TODO(jiajia.qin@intel.com): Add
2272 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002273 }
2274 return true;
2275}
Jamie Madille473dee2015-08-18 14:49:01 -04002276
Jiajia Qin729b2c62017-08-14 09:36:11 +08002277bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002278{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002279 const auto &caps = context->getCaps();
2280
Martin Radev4c4c8e72016-08-04 12:25:34 +03002281 if (mState.mAttachedComputeShader)
2282 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002283 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002284 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002285
Jiajia Qin729b2c62017-08-14 09:36:11 +08002286 if (!validateInterfaceBlocksCount(
2287 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002288 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2289 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002290 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002291 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002292 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002293
2294 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2295 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2296 computeShaderStorageBlocks,
2297 "Compute shader shader storage block count exceeds "
2298 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2299 infoLog))
2300 {
2301 return false;
2302 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002303 return true;
2304 }
2305
Jamie Madillbd044ed2017-06-05 12:59:21 -04002306 Shader &vertexShader = *mState.mAttachedVertexShader;
2307 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002308
Jiajia Qin729b2c62017-08-14 09:36:11 +08002309 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2310 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002311
Jiajia Qin729b2c62017-08-14 09:36:11 +08002312 if (!validateInterfaceBlocksCount(
2313 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002314 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2315 {
2316 return false;
2317 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002318 if (!validateInterfaceBlocksCount(
2319 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002320 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2321 infoLog))
2322 {
2323
2324 return false;
2325 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002326
2327 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002328 if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002329 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002330 {
2331 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002332 }
Jamie Madille473dee2015-08-18 14:49:01 -04002333
Jiajia Qin729b2c62017-08-14 09:36:11 +08002334 if (context->getClientVersion() >= Version(3, 1))
2335 {
2336 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2337 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2338
2339 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2340 vertexShaderStorageBlocks,
2341 "Vertex shader shader storage block count exceeds "
2342 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2343 infoLog))
2344 {
2345 return false;
2346 }
2347 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2348 fragmentShaderStorageBlocks,
2349 "Fragment shader shader storage block count exceeds "
2350 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2351 infoLog))
2352 {
2353
2354 return false;
2355 }
2356
2357 if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
2358 fragmentShaderStorageBlocks, infoLog,
2359 webglCompatibility))
2360 {
2361 return false;
2362 }
2363 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002364 return true;
2365}
2366
Jamie Madilla2c74982016-12-12 11:20:42 -05002367bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002368 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002369 const sh::InterfaceBlock &fragmentInterfaceBlock,
2370 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002371{
2372 const char* blockName = vertexInterfaceBlock.name.c_str();
2373 // validate blocks for the same member types
2374 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2375 {
Jamie Madillf6113162015-05-07 11:49:21 -04002376 infoLog << "Types for interface block '" << blockName
2377 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002378 return false;
2379 }
2380 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2381 {
Jamie Madillf6113162015-05-07 11:49:21 -04002382 infoLog << "Array sizes differ for interface block '" << blockName
2383 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002384 return false;
2385 }
jchen10af713a22017-04-19 09:10:56 +08002386 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2387 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2388 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002389 {
Jamie Madillf6113162015-05-07 11:49:21 -04002390 infoLog << "Layout qualifiers differ for interface block '" << blockName
2391 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 return false;
2393 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002394 const unsigned int numBlockMembers =
2395 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002396 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2397 {
2398 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2399 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2400 if (vertexMember.name != fragmentMember.name)
2401 {
Jamie Madillf6113162015-05-07 11:49:21 -04002402 infoLog << "Name mismatch for field " << blockMemberIndex
2403 << " of interface block '" << blockName
2404 << "': (in vertex: '" << vertexMember.name
2405 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002406 return false;
2407 }
2408 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002409 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2410 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002411 {
2412 return false;
2413 }
2414 }
2415 return true;
2416}
2417
2418bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2419 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2420{
2421 if (vertexVariable.type != fragmentVariable.type)
2422 {
Jamie Madillf6113162015-05-07 11:49:21 -04002423 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002424 return false;
2425 }
2426 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2427 {
Jamie Madillf6113162015-05-07 11:49:21 -04002428 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002429 return false;
2430 }
2431 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2432 {
Jamie Madillf6113162015-05-07 11:49:21 -04002433 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002434 return false;
2435 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002436 if (vertexVariable.structName != fragmentVariable.structName)
2437 {
2438 infoLog << "Structure names for " << variableName
2439 << " differ between vertex and fragment shaders";
2440 return false;
2441 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002442
2443 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2444 {
Jamie Madillf6113162015-05-07 11:49:21 -04002445 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002446 return false;
2447 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002448 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002449 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2450 {
2451 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2452 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2453
2454 if (vertexMember.name != fragmentMember.name)
2455 {
Jamie Madillf6113162015-05-07 11:49:21 -04002456 infoLog << "Name mismatch for field '" << memberIndex
2457 << "' of " << variableName
2458 << ": (in vertex: '" << vertexMember.name
2459 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002460 return false;
2461 }
2462
2463 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2464 vertexMember.name + "'";
2465
2466 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2467 {
2468 return false;
2469 }
2470 }
2471
2472 return true;
2473}
2474
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002475bool Program::linkValidateVaryings(InfoLog &infoLog,
2476 const std::string &varyingName,
2477 const sh::Varying &vertexVarying,
2478 const sh::Varying &fragmentVarying,
2479 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002480{
2481 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2482 {
2483 return false;
2484 }
2485
Jamie Madille9cc4692015-02-19 16:00:13 -05002486 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002487 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002488 infoLog << "Interpolation types for " << varyingName
2489 << " differ between vertex and fragment shaders.";
2490 return false;
2491 }
2492
2493 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2494 {
2495 infoLog << "Invariance for " << varyingName
2496 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002497 return false;
2498 }
2499
2500 return true;
2501}
2502
Jamie Madillbd044ed2017-06-05 12:59:21 -04002503bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002504{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002505 Shader *vertexShader = mState.mAttachedVertexShader;
2506 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002507 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2508 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002509 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002510
2511 if (shaderVersion != 100)
2512 {
2513 // Only ESSL 1.0 has restrictions on matching input and output invariance
2514 return true;
2515 }
2516
2517 bool glPositionIsInvariant = false;
2518 bool glPointSizeIsInvariant = false;
2519 bool glFragCoordIsInvariant = false;
2520 bool glPointCoordIsInvariant = false;
2521
2522 for (const sh::Varying &varying : vertexVaryings)
2523 {
2524 if (!varying.isBuiltIn())
2525 {
2526 continue;
2527 }
2528 if (varying.name.compare("gl_Position") == 0)
2529 {
2530 glPositionIsInvariant = varying.isInvariant;
2531 }
2532 else if (varying.name.compare("gl_PointSize") == 0)
2533 {
2534 glPointSizeIsInvariant = varying.isInvariant;
2535 }
2536 }
2537
2538 for (const sh::Varying &varying : fragmentVaryings)
2539 {
2540 if (!varying.isBuiltIn())
2541 {
2542 continue;
2543 }
2544 if (varying.name.compare("gl_FragCoord") == 0)
2545 {
2546 glFragCoordIsInvariant = varying.isInvariant;
2547 }
2548 else if (varying.name.compare("gl_PointCoord") == 0)
2549 {
2550 glPointCoordIsInvariant = varying.isInvariant;
2551 }
2552 }
2553
2554 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2555 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2556 // Not requiring invariance to match is supported by:
2557 // dEQP, WebGL CTS, Nexus 5X GLES
2558 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2559 {
2560 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2561 "declared invariant.";
2562 return false;
2563 }
2564 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2565 {
2566 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2567 "declared invariant.";
2568 return false;
2569 }
2570
2571 return true;
2572}
2573
jchen10a9042d32017-03-17 08:50:45 +08002574bool Program::linkValidateTransformFeedback(const gl::Context *context,
2575 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002576 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002577 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002578{
2579 size_t totalComponents = 0;
2580
Jamie Madillccdf74b2015-08-18 10:46:12 -04002581 std::set<std::string> uniqueNames;
2582
Jamie Madill48ef11b2016-04-27 15:21:52 -04002583 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002584 {
2585 bool found = false;
Olli Etuahoc8538042017-09-27 11:20:15 +03002586 std::vector<unsigned int> subscripts;
2587 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002588
Jamie Madill192745a2016-12-22 15:58:21 -05002589 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002590 {
Jamie Madill192745a2016-12-22 15:58:21 -05002591 const sh::Varying *varying = ref.second.get();
2592
jchen10a9042d32017-03-17 08:50:45 +08002593 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002594 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002595 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002596 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002597 infoLog << "Two transform feedback varyings specify the same output variable ("
2598 << tfVaryingName << ").";
2599 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002600 }
jchen10a9042d32017-03-17 08:50:45 +08002601 if (context->getClientVersion() >= Version(3, 1))
2602 {
2603 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2604 {
2605 infoLog
2606 << "Two transform feedback varyings include the same array element ("
2607 << tfVaryingName << ").";
2608 return false;
2609 }
2610 }
2611 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002612 {
2613 infoLog << "Capture of arrays is undefined and not supported.";
2614 return false;
2615 }
2616
jchen10a9042d32017-03-17 08:50:45 +08002617 uniqueNames.insert(tfVaryingName);
2618
Jamie Madillccdf74b2015-08-18 10:46:12 -04002619 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002620 size_t elementCount =
Olli Etuahoc8538042017-09-27 11:20:15 +03002621 ((varying->isArray() && subscripts.empty()) ? varying->elementCount() : 1);
jchen10a9042d32017-03-17 08:50:45 +08002622 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002623 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002624 componentCount > caps.maxTransformFeedbackSeparateComponents)
2625 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002626 infoLog << "Transform feedback varying's " << varying->name << " components ("
2627 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002628 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002629 return false;
2630 }
2631
2632 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002633 found = true;
2634 break;
2635 }
2636 }
jchen10a9042d32017-03-17 08:50:45 +08002637 if (context->getClientVersion() < Version(3, 1) &&
2638 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002639 {
Geoff Lang1a683462015-09-29 15:09:59 -04002640 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002641 return false;
2642 }
jchen1085c93c42017-11-12 15:36:47 +08002643 if (!found)
2644 {
2645 infoLog << "Transform feedback varying " << tfVaryingName
2646 << " does not exist in the vertex shader.";
2647 return false;
2648 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002649 }
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
Jamie Madill80a6fc02015-08-21 16:53:16 -04002736
Jamie Madillbd044ed2017-06-05 12:59:21 -04002737void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002738{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002739 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002740 ASSERT(fragmentShader != nullptr);
2741
Geoff Lange0cff192017-05-30 13:04:56 -04002742 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002743 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002744
2745 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002746 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002747 {
2748 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2749 outputVariable.name != "gl_FragData")
2750 {
2751 continue;
2752 }
2753
2754 unsigned int baseLocation =
2755 (outputVariable.location == -1 ? 0u
2756 : static_cast<unsigned int>(outputVariable.location));
2757 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2758 elementIndex++)
2759 {
2760 const unsigned int location = baseLocation + elementIndex;
2761 if (location >= mState.mOutputVariableTypes.size())
2762 {
2763 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2764 }
Corentin Walleze7557742017-06-01 13:09:57 -04002765 ASSERT(location < mState.mActiveOutputVariables.size());
2766 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002767 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2768 }
2769 }
2770
Jamie Madill80a6fc02015-08-21 16:53:16 -04002771 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002772 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002773 return;
2774
Jamie Madillbd044ed2017-06-05 12:59:21 -04002775 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002776 // TODO(jmadill): any caps validation here?
2777
jchen1015015f72017-03-16 13:54:21 +08002778 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002779 outputVariableIndex++)
2780 {
jchen1015015f72017-03-16 13:54:21 +08002781 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002782
Olli Etuahod2551232017-10-26 20:03:33 +03002783 if (outputVariable.isArray())
2784 {
2785 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2786 // Resources and including [0] at the end of array variable names.
2787 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2788 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2789 }
2790
Jamie Madill80a6fc02015-08-21 16:53:16 -04002791 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2792 if (outputVariable.isBuiltIn())
2793 continue;
2794
2795 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002796 unsigned int baseLocation =
2797 (outputVariable.location == -1 ? 0u
2798 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002799
Jamie Madill80a6fc02015-08-21 16:53:16 -04002800 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2801 elementIndex++)
2802 {
Olli Etuahod2551232017-10-26 20:03:33 +03002803 const unsigned int location = baseLocation + elementIndex;
2804 if (location >= mState.mOutputLocations.size())
2805 {
2806 mState.mOutputLocations.resize(location + 1);
2807 }
2808 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03002809 if (outputVariable.isArray())
2810 {
2811 mState.mOutputLocations[location] =
2812 VariableLocation(elementIndex, outputVariableIndex);
2813 }
2814 else
2815 {
2816 VariableLocation locationInfo;
2817 locationInfo.index = outputVariableIndex;
2818 mState.mOutputLocations[location] = locationInfo;
2819 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04002820 }
2821 }
2822}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002823
Olli Etuaho48fed632017-03-16 12:05:30 +00002824void Program::setUniformValuesFromBindingQualifiers()
2825{
Jamie Madill982f6e02017-06-07 14:33:04 -04002826 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002827 {
2828 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2829 if (samplerUniform.binding != -1)
2830 {
Olli Etuahod2551232017-10-26 20:03:33 +03002831 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00002832 ASSERT(location != -1);
2833 std::vector<GLint> boundTextureUnits;
2834 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2835 ++elementIndex)
2836 {
2837 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2838 }
2839 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2840 boundTextureUnits.data());
2841 }
2842 }
2843}
2844
jchen10eaef1e52017-06-13 10:44:11 +08002845void Program::gatherAtomicCounterBuffers()
2846{
jchen10baf5d942017-08-28 20:45:48 +08002847 for (unsigned int index : mState.mAtomicCounterUniformRange)
2848 {
2849 auto &uniform = mState.mUniforms[index];
2850 uniform.blockInfo.offset = uniform.offset;
2851 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2852 uniform.blockInfo.matrixStride = 0;
2853 uniform.blockInfo.isRowMajorMatrix = false;
2854 }
2855
jchen10eaef1e52017-06-13 10:44:11 +08002856 // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
2857}
2858
Jamie Madill6db1c2e2017-11-08 09:17:40 -05002859void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04002860{
jchen10af713a22017-04-19 09:10:56 +08002861 // Set initial bindings from shader.
2862 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2863 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002864 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08002865 bindUniformBlock(blockIndex, uniformBlock.binding);
2866 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002867}
2868
Jamie Madille7d84322017-01-10 18:21:59 -05002869void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05002870 GLsizei clampedCount,
2871 const GLint *v)
2872{
Jamie Madill81c2e252017-09-09 23:32:46 -04002873 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
2874 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2875 std::vector<GLuint> *boundTextureUnits =
2876 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05002877
Olli Etuaho1734e172017-10-27 15:30:27 +03002878 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04002879
2880 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04002881 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05002882}
2883
2884template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002885GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
2886 GLsizei count,
2887 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05002888 const T *v)
2889{
Jamie Madill134f93d2017-08-31 17:11:00 -04002890 if (count == 1)
2891 return 1;
2892
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002893 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002894
Corentin Wallez15ac5342016-11-03 17:06:39 -04002895 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2896 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03002897 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002898 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002899 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002900
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002901 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002902 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002903 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002904 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002905
2906 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002907}
2908
2909template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002910GLsizei Program::clampMatrixUniformCount(GLint location,
2911 GLsizei count,
2912 GLboolean transpose,
2913 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002914{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002915 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2916
Jamie Madill62d31cb2015-09-11 13:25:51 -04002917 if (!transpose)
2918 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002919 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002920 }
2921
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002922 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04002923
2924 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2925 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03002926 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002927 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04002928}
2929
Jamie Madill54164b02017-08-28 15:17:37 -04002930// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
2931// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002932template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04002933void Program::getUniformInternal(const Context *context,
2934 DestT *dataOut,
2935 GLint location,
2936 GLenum nativeType,
2937 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04002938{
Jamie Madill54164b02017-08-28 15:17:37 -04002939 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002940 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002941 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04002942 {
2943 GLint tempValue[16] = {0};
2944 mProgram->getUniformiv(context, location, tempValue);
2945 UniformStateQueryCastLoop<GLboolean>(
2946 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002947 break;
Jamie Madill54164b02017-08-28 15:17:37 -04002948 }
2949 case GL_INT:
2950 {
2951 GLint tempValue[16] = {0};
2952 mProgram->getUniformiv(context, location, tempValue);
2953 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
2954 components);
2955 break;
2956 }
2957 case GL_UNSIGNED_INT:
2958 {
2959 GLuint tempValue[16] = {0};
2960 mProgram->getUniformuiv(context, location, tempValue);
2961 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
2962 components);
2963 break;
2964 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002965 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04002966 {
2967 GLfloat tempValue[16] = {0};
2968 mProgram->getUniformfv(context, location, tempValue);
2969 UniformStateQueryCastLoop<GLfloat>(
2970 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002971 break;
Jamie Madill54164b02017-08-28 15:17:37 -04002972 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002973 default:
2974 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04002975 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002976 }
2977}
Jamie Madilla4595b82017-01-11 17:36:34 -05002978
2979bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
2980{
2981 // Must be called after samplers are validated.
2982 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
2983
2984 for (const auto &binding : mState.mSamplerBindings)
2985 {
2986 GLenum textureType = binding.textureType;
2987 for (const auto &unit : binding.boundTextureUnits)
2988 {
2989 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
2990 if (programTextureID == textureID)
2991 {
2992 // TODO(jmadill): Check for appropriate overlap.
2993 return true;
2994 }
2995 }
2996 }
2997
2998 return false;
2999}
3000
Jamie Madilla2c74982016-12-12 11:20:42 -05003001} // namespace gl