blob: c484668c6a4ccaa47cda53de473766e1fe69578e [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill20e005b2017-04-07 14:19:22 -040014#include "common/bitset_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
Olli Etuahod2551232017-10-26 20:03:33 +030017#include "common/string_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "common/utilities.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021#include "libANGLE/MemoryProgramCache.h"
Jamie Madill7af0de52017-11-06 17:09:33 -050022#include "libANGLE/ProgramLinkedResources.h"
Jamie Madill437d2662014-12-05 14:23:35 -050023#include "libANGLE/ResourceManager.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040024#include "libANGLE/Uniform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040025#include "libANGLE/VaryingPacking.h"
26#include "libANGLE/features.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040027#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040028#include "libANGLE/queryconversions.h"
29#include "libANGLE/renderer/GLImplFactory.h"
30#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040031#include "platform/Platform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050032
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033namespace gl
34{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000035
Geoff Lang7dd2e102014-11-10 15:19:26 -050036namespace
37{
38
Jamie Madill62d31cb2015-09-11 13:25:51 -040039// This simplified cast function doesn't need to worry about advanced concepts like
40// depth range values, or casting to bool.
41template <typename DestT, typename SrcT>
42DestT UniformStateQueryCast(SrcT value);
43
44// From-Float-To-Integer Casts
45template <>
46GLint UniformStateQueryCast(GLfloat value)
47{
48 return clampCast<GLint>(roundf(value));
49}
50
51template <>
52GLuint UniformStateQueryCast(GLfloat value)
53{
54 return clampCast<GLuint>(roundf(value));
55}
56
57// From-Integer-to-Integer Casts
58template <>
59GLint UniformStateQueryCast(GLuint value)
60{
61 return clampCast<GLint>(value);
62}
63
64template <>
65GLuint UniformStateQueryCast(GLint value)
66{
67 return clampCast<GLuint>(value);
68}
69
70// From-Boolean-to-Anything Casts
71template <>
72GLfloat UniformStateQueryCast(GLboolean value)
73{
74 return (value == GL_TRUE ? 1.0f : 0.0f);
75}
76
77template <>
78GLint UniformStateQueryCast(GLboolean value)
79{
80 return (value == GL_TRUE ? 1 : 0);
81}
82
83template <>
84GLuint UniformStateQueryCast(GLboolean value)
85{
86 return (value == GL_TRUE ? 1u : 0u);
87}
88
89// Default to static_cast
90template <typename DestT, typename SrcT>
91DestT UniformStateQueryCast(SrcT value)
92{
93 return static_cast<DestT>(value);
94}
95
96template <typename SrcT, typename DestT>
97void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
98{
99 for (int comp = 0; comp < components; ++comp)
100 {
101 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
102 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
103 size_t offset = comp * 4;
104 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
105 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
106 }
107}
108
Jamie Madill192745a2016-12-22 15:58:21 -0500109// true if varying x has a higher priority in packing than y
110bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
111{
jchen10a9042d32017-03-17 08:50:45 +0800112 // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent
113 // non-array shader variable 'vx' or 'vy' for actual comparison instead.
114 sh::ShaderVariable vx, vy;
115 const sh::ShaderVariable *px, *py;
116 if (x.isArrayElement())
117 {
118 vx = *x.varying;
119 vx.arraySize = 0;
120 px = &vx;
121 }
122 else
123 {
124 px = x.varying;
125 }
126
127 if (y.isArrayElement())
128 {
129 vy = *y.varying;
130 vy.arraySize = 0;
131 py = &vy;
132 }
133 else
134 {
135 py = y.varying;
136 }
137
138 return gl::CompareShaderVar(*px, *py);
Jamie Madill192745a2016-12-22 15:58:21 -0500139}
140
jchen1015015f72017-03-16 13:54:21 +0800141template <typename VarT>
142GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
143{
Olli Etuahod2551232017-10-26 20:03:33 +0300144 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800145 for (size_t index = 0; index < list.size(); index++)
146 {
147 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300148 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800149 {
Olli Etuahod2551232017-10-26 20:03:33 +0300150 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800151 }
152 }
153
154 return GL_INVALID_INDEX;
155}
156
Olli Etuahod2551232017-10-26 20:03:33 +0300157template <typename VarT>
158GLint GetVariableLocation(const std::vector<VarT> &list,
159 const std::vector<VariableLocation> &locationList,
160 const std::string &name)
161{
162 size_t nameLengthWithoutArrayIndex;
163 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
164
165 for (size_t location = 0u; location < locationList.size(); ++location)
166 {
167 const VariableLocation &variableLocation = locationList[location];
168 if (!variableLocation.used())
169 {
170 continue;
171 }
172
173 const VarT &variable = list[variableLocation.index];
174
175 if (angle::BeginsWith(variable.name, name))
176 {
177 if (name.length() == variable.name.length())
178 {
179 ASSERT(name == variable.name);
180 // GLES 3.1 November 2016 page 87.
181 // The string exactly matches the name of the active variable.
182 return static_cast<GLint>(location);
183 }
184 if (name.length() + 3u == variable.name.length() && variable.isArray())
185 {
186 ASSERT(name + "[0]" == variable.name);
187 // The string identifies the base name of an active array, where the string would
188 // exactly match the name of the variable if the suffix "[0]" were appended to the
189 // string.
190 return static_cast<GLint>(location);
191 }
192 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300193 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300194 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
195 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
196 {
197 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
198 // The string identifies an active element of the array, where the string ends with the
199 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
200 // zeroes, or whitespace) identifying an array element, and the "]" character, the
201 // integer is less than the number of active elements of the array variable, and where
202 // the string would exactly match the enumerated name of the array if the decimal
203 // integer were replaced with zero.
204 return static_cast<GLint>(location);
205 }
206 }
207
208 return -1;
209}
210
jchen10fd7c3b52017-03-21 15:36:03 +0800211void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
212{
213 ASSERT(bufSize > 0);
214 strncpy(buffer, string.c_str(), bufSize);
215 buffer[bufSize - 1] = '\0';
216
217 if (length)
218 {
219 *length = static_cast<GLsizei>(strlen(buffer));
220 }
221}
222
jchen10a9042d32017-03-17 08:50:45 +0800223bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
224{
Olli Etuahoc8538042017-09-27 11:20:15 +0300225 std::vector<unsigned int> subscripts;
226 std::string baseName = ParseResourceName(name, &subscripts);
227 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800228 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300229 std::vector<unsigned int> arrayIndices;
230 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
231 if (baseName == arrayName &&
232 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800233 {
234 return true;
235 }
236 }
237 return false;
238}
239
Jiajia Qin729b2c62017-08-14 09:36:11 +0800240bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
241 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
242 const std::string &errorMessage,
243 InfoLog &infoLog)
244{
245 GLuint blockCount = 0;
246 for (const sh::InterfaceBlock &block : interfaceBlocks)
247 {
248 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
249 {
250 blockCount += (block.arraySize ? block.arraySize : 1);
251 if (blockCount > maxInterfaceBlocks)
252 {
253 infoLog << errorMessage << maxInterfaceBlocks << ")";
254 return false;
255 }
256 }
257 }
258 return true;
259}
260
Jamie Madillc9727f32017-11-07 12:37:07 -0500261void InitUniformBlockLinker(const gl::Context *context,
262 const ProgramState &state,
263 UniformBlockLinker *blockLinker)
264{
265 if (state.getAttachedVertexShader())
266 {
267 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
268 &state.getAttachedVertexShader()->getUniformBlocks(context));
269 }
270
271 if (state.getAttachedFragmentShader())
272 {
273 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
274 &state.getAttachedFragmentShader()->getUniformBlocks(context));
275 }
276
277 if (state.getAttachedComputeShader())
278 {
279 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
280 &state.getAttachedComputeShader()->getUniformBlocks(context));
281 }
282}
283
284void InitShaderStorageBlockLinker(const gl::Context *context,
285 const ProgramState &state,
286 ShaderStorageBlockLinker *blockLinker)
287{
288 if (state.getAttachedVertexShader())
289 {
290 blockLinker->addShaderBlocks(
291 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
292 }
293
294 if (state.getAttachedFragmentShader())
295 {
296 blockLinker->addShaderBlocks(
297 GL_FRAGMENT_SHADER,
298 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
299 }
300
301 if (state.getAttachedComputeShader())
302 {
303 blockLinker->addShaderBlocks(
304 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
305 }
306}
307
Jamie Madill62d31cb2015-09-11 13:25:51 -0400308} // anonymous namespace
309
Jamie Madill4a3c2342015-10-08 12:58:45 -0400310const char *const g_fakepath = "C:\\fakepath";
311
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400312InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000313{
314}
315
316InfoLog::~InfoLog()
317{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000318}
319
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400320size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000321{
Jamie Madill23176ce2017-07-31 14:14:33 -0400322 if (!mLazyStream)
323 {
324 return 0;
325 }
326
327 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400328 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000329}
330
Geoff Lange1a27752015-10-05 13:16:04 -0400331void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000332{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400333 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000334
335 if (bufSize > 0)
336 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400337 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400338
Jamie Madill23176ce2017-07-31 14:14:33 -0400339 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000340 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400341 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
342 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000343 }
344
345 infoLog[index] = '\0';
346 }
347
348 if (length)
349 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400350 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000351 }
352}
353
354// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300355// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356// messages, so lets remove all occurrences of this fake file path from the log.
357void InfoLog::appendSanitized(const char *message)
358{
Jamie Madill23176ce2017-07-31 14:14:33 -0400359 ensureInitialized();
360
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000361 std::string msg(message);
362
363 size_t found;
364 do
365 {
366 found = msg.find(g_fakepath);
367 if (found != std::string::npos)
368 {
369 msg.erase(found, strlen(g_fakepath));
370 }
371 }
372 while (found != std::string::npos);
373
Jamie Madill23176ce2017-07-31 14:14:33 -0400374 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000375}
376
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000377void InfoLog::reset()
378{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000379}
380
Olli Etuaho1734e172017-10-27 15:30:27 +0300381VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000382{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500383}
384
Olli Etuahoc8538042017-09-27 11:20:15 +0300385VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300386 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500387{
Olli Etuahoc8538042017-09-27 11:20:15 +0300388 ASSERT(arrayIndex != GL_INVALID_INDEX);
389}
390
Geoff Langd8605522016-04-13 10:19:12 -0400391void Program::Bindings::bindLocation(GLuint index, const std::string &name)
392{
393 mBindings[name] = index;
394}
395
396int Program::Bindings::getBinding(const std::string &name) const
397{
398 auto iter = mBindings.find(name);
399 return (iter != mBindings.end()) ? iter->second : -1;
400}
401
402Program::Bindings::const_iterator Program::Bindings::begin() const
403{
404 return mBindings.begin();
405}
406
407Program::Bindings::const_iterator Program::Bindings::end() const
408{
409 return mBindings.end();
410}
411
Jamie Madill48ef11b2016-04-27 15:21:52 -0400412ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500413 : mLabel(),
414 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400415 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300416 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500417 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400418 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500419 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800420 mImageUniformRange(0, 0),
421 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300422 mBinaryRetrieveableHint(false),
423 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400424{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300425 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400426}
427
Jamie Madill48ef11b2016-04-27 15:21:52 -0400428ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400429{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500430 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400431}
432
Jamie Madill48ef11b2016-04-27 15:21:52 -0400433const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500434{
435 return mLabel;
436}
437
Jamie Madille7d84322017-01-10 18:21:59 -0500438GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400439{
jchen1015015f72017-03-16 13:54:21 +0800440 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400441}
442
Jamie Madille7d84322017-01-10 18:21:59 -0500443GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
444{
445 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
446 return mUniformLocations[location].index;
447}
448
449Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
450{
451 GLuint index = getUniformIndexFromLocation(location);
452 if (!isSamplerUniformIndex(index))
453 {
454 return Optional<GLuint>::Invalid();
455 }
456
457 return getSamplerIndexFromUniformIndex(index);
458}
459
460bool ProgramState::isSamplerUniformIndex(GLuint index) const
461{
Jamie Madill982f6e02017-06-07 14:33:04 -0400462 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500463}
464
465GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
466{
467 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400468 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500469}
470
Jamie Madill34ca4f52017-06-13 11:49:39 -0400471GLuint ProgramState::getAttributeLocation(const std::string &name) const
472{
473 for (const sh::Attribute &attribute : mAttributes)
474 {
475 if (attribute.name == name)
476 {
477 return attribute.location;
478 }
479 }
480
481 return static_cast<GLuint>(-1);
482}
483
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500484Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400485 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400486 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500487 mLinked(false),
488 mDeleteStatus(false),
489 mRefCount(0),
490 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500491 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500492{
493 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000494
Geoff Lang7dd2e102014-11-10 15:19:26 -0500495 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496}
497
498Program::~Program()
499{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400500 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501}
502
Jamie Madill4928b7c2017-06-20 12:57:39 -0400503void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500504{
505 if (mState.mAttachedVertexShader != nullptr)
506 {
507 mState.mAttachedVertexShader->release(context);
508 mState.mAttachedVertexShader = nullptr;
509 }
510
511 if (mState.mAttachedFragmentShader != nullptr)
512 {
513 mState.mAttachedFragmentShader->release(context);
514 mState.mAttachedFragmentShader = nullptr;
515 }
516
517 if (mState.mAttachedComputeShader != nullptr)
518 {
519 mState.mAttachedComputeShader->release(context);
520 mState.mAttachedComputeShader = nullptr;
521 }
522
Jamie Madillc564c072017-06-01 12:45:42 -0400523 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400524
525 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
526 !mState.mAttachedComputeShader);
527 SafeDelete(mProgram);
528
529 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500530}
531
Geoff Lang70d0f492015-12-10 17:45:46 -0500532void Program::setLabel(const std::string &label)
533{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400534 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500535}
536
537const std::string &Program::getLabel() const
538{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400539 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500540}
541
Jamie Madillef300b12016-10-07 15:12:09 -0400542void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300544 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300546 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000547 {
Jamie Madillef300b12016-10-07 15:12:09 -0400548 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300549 mState.mAttachedVertexShader = shader;
550 mState.mAttachedVertexShader->addRef();
551 break;
552 }
553 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000554 {
Jamie Madillef300b12016-10-07 15:12:09 -0400555 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300556 mState.mAttachedFragmentShader = shader;
557 mState.mAttachedFragmentShader->addRef();
558 break;
559 }
560 case GL_COMPUTE_SHADER:
561 {
Jamie Madillef300b12016-10-07 15:12:09 -0400562 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300563 mState.mAttachedComputeShader = shader;
564 mState.mAttachedComputeShader->addRef();
565 break;
566 }
567 default:
568 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570}
571
Jamie Madillc1d770e2017-04-13 17:31:24 -0400572void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000573{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300574 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000575 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300576 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000577 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400578 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500579 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300580 mState.mAttachedVertexShader = nullptr;
581 break;
582 }
583 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400585 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500586 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300587 mState.mAttachedFragmentShader = nullptr;
588 break;
589 }
590 case GL_COMPUTE_SHADER:
591 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400592 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500593 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300594 mState.mAttachedComputeShader = nullptr;
595 break;
596 }
597 default:
598 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600}
601
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000602int Program::getAttachedShadersCount() const
603{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300604 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
605 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000606}
607
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608void Program::bindAttributeLocation(GLuint index, const char *name)
609{
Geoff Langd8605522016-04-13 10:19:12 -0400610 mAttributeBindings.bindLocation(index, name);
611}
612
613void Program::bindUniformLocation(GLuint index, const char *name)
614{
Olli Etuahod2551232017-10-26 20:03:33 +0300615 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616}
617
Sami Väisänen46eaa942016-06-29 10:26:37 +0300618void Program::bindFragmentInputLocation(GLint index, const char *name)
619{
620 mFragmentInputBindings.bindLocation(index, name);
621}
622
Jamie Madillbd044ed2017-06-05 12:59:21 -0400623BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300624{
625 BindingInfo ret;
626 ret.type = GL_NONE;
627 ret.valid = false;
628
Jamie Madillbd044ed2017-06-05 12:59:21 -0400629 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300630 ASSERT(fragmentShader);
631
632 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800633 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300634
635 for (const auto &binding : mFragmentInputBindings)
636 {
637 if (binding.second != static_cast<GLuint>(index))
638 continue;
639
640 ret.valid = true;
641
Olli Etuahod2551232017-10-26 20:03:33 +0300642 size_t nameLengthWithoutArrayIndex;
643 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300644
645 for (const auto &in : inputs)
646 {
Olli Etuahod2551232017-10-26 20:03:33 +0300647 if (in.name.length() == nameLengthWithoutArrayIndex &&
648 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300649 {
650 if (in.isArray())
651 {
652 // The client wants to bind either "name" or "name[0]".
653 // GL ES 3.1 spec refers to active array names with language such as:
654 // "if the string identifies the base name of an active array, where the
655 // string would exactly match the name of the variable if the suffix "[0]"
656 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400657 if (arrayIndex == GL_INVALID_INDEX)
658 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300659
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400660 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300661 }
662 else
663 {
664 ret.name = in.mappedName;
665 }
666 ret.type = in.type;
667 return ret;
668 }
669 }
670 }
671
672 return ret;
673}
674
Jamie Madillbd044ed2017-06-05 12:59:21 -0400675void Program::pathFragmentInputGen(const Context *context,
676 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300677 GLenum genMode,
678 GLint components,
679 const GLfloat *coeffs)
680{
681 // If the location is -1 then the command is silently ignored
682 if (index == -1)
683 return;
684
Jamie Madillbd044ed2017-06-05 12:59:21 -0400685 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300686
687 // If the input doesn't exist then then the command is silently ignored
688 // This could happen through optimization for example, the shader translator
689 // decides that a variable is not actually being used and optimizes it away.
690 if (binding.name.empty())
691 return;
692
693 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
694}
695
Martin Radev4c4c8e72016-08-04 12:25:34 +0300696// The attached shaders are checked for linking errors by matching up their variables.
697// Uniform, input and output variables get collected.
698// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500699Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000700{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500701 const auto &data = context->getContextState();
702
Jamie Madill6c58b062017-08-01 13:44:25 -0400703 auto *platform = ANGLEPlatformCurrent();
704 double startTime = platform->currentTime(platform);
705
Jamie Madill6c1f6712017-02-14 19:08:04 -0500706 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000707
Jamie Madill32447362017-06-28 14:53:52 -0400708 ProgramHash programHash;
709 auto *cache = context->getMemoryProgramCache();
710 if (cache)
711 {
712 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400713 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400714 }
715
716 if (mLinked)
717 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400718 double delta = platform->currentTime(platform) - startTime;
719 int us = static_cast<int>(delta * 1000000.0);
720 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400721 return NoError();
722 }
723
724 // Cache load failed, fall through to normal linking.
725 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000726 mInfoLog.reset();
727
Martin Radev4c4c8e72016-08-04 12:25:34 +0300728 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500729
Jamie Madill192745a2016-12-22 15:58:21 -0500730 auto vertexShader = mState.mAttachedVertexShader;
731 auto fragmentShader = mState.mAttachedFragmentShader;
732 auto computeShader = mState.mAttachedComputeShader;
733
734 bool isComputeShaderAttached = (computeShader != nullptr);
735 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300736 // Check whether we both have a compute and non-compute shaders attached.
737 // If there are of both types attached, then linking should fail.
738 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
739 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500740 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300741 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
742 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400743 }
744
Jamie Madill192745a2016-12-22 15:58:21 -0500745 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500746 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400747 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300748 {
749 mInfoLog << "Attached compute shader is not compiled.";
750 return NoError();
751 }
Jamie Madill192745a2016-12-22 15:58:21 -0500752 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300753
Jamie Madillbd044ed2017-06-05 12:59:21 -0400754 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300755
756 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
757 // If the work group size is not specified, a link time error should occur.
758 if (!mState.mComputeShaderLocalSize.isDeclared())
759 {
760 mInfoLog << "Work group size is not specified.";
761 return NoError();
762 }
763
Jamie Madillbd044ed2017-06-05 12:59:21 -0400764 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300765 {
766 return NoError();
767 }
768
Jiajia Qin729b2c62017-08-14 09:36:11 +0800769 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300770 {
771 return NoError();
772 }
773
Jamie Madillc9727f32017-11-07 12:37:07 -0500774 ProgramLinkedResources resources = {{0, PackMode::ANGLE_RELAXED},
775 {&mState.mUniformBlocks, &mState.mUniforms},
776 {&mState.mShaderStorageBlocks}};
777
778 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
779 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
780
781 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500782 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300783 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500784 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300785 }
786 }
787 else
788 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400789 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300790 {
791 return NoError();
792 }
Jamie Madill192745a2016-12-22 15:58:21 -0500793 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300794
Jamie Madillbd044ed2017-06-05 12:59:21 -0400795 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300796 {
797 return NoError();
798 }
Jamie Madill192745a2016-12-22 15:58:21 -0500799 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300800
Jamie Madillbd044ed2017-06-05 12:59:21 -0400801 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300802 {
803 mInfoLog << "Fragment shader version does not match vertex shader version.";
804 return NoError();
805 }
806
Jamie Madillbd044ed2017-06-05 12:59:21 -0400807 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300808 {
809 return NoError();
810 }
811
Jamie Madillbd044ed2017-06-05 12:59:21 -0400812 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300813 {
814 return NoError();
815 }
816
Jamie Madillbd044ed2017-06-05 12:59:21 -0400817 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300818 {
819 return NoError();
820 }
821
Jiajia Qin729b2c62017-08-14 09:36:11 +0800822 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300823 {
824 return NoError();
825 }
826
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400827 if (!linkValidateGlobalNames(context, mInfoLog))
828 {
829 return NoError();
830 }
831
Jamie Madillbd044ed2017-06-05 12:59:21 -0400832 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300833
Martin Radev7cf61662017-07-26 17:10:53 +0300834 mState.mNumViews = vertexShader->getNumViews(context);
835
Jamie Madillbd044ed2017-06-05 12:59:21 -0400836 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300837
Jamie Madill192745a2016-12-22 15:58:21 -0500838 // Validate we can pack the varyings.
839 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
840
841 // Map the varyings to the register file
842 // In WebGL, we use a slightly different handling for packing variables.
843 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
844 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500845
846 ProgramLinkedResources resources = {{data.getCaps().maxVaryingVectors, packMode},
847 {&mState.mUniformBlocks, &mState.mUniforms},
848 {&mState.mShaderStorageBlocks}};
849
850 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
851 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
852
853 if (!resources.varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
854 mState.getTransformFeedbackVaryingNames()))
Jamie Madill192745a2016-12-22 15:58:21 -0500855 {
856 return NoError();
857 }
858
Olli Etuaho39e78122017-08-29 14:34:22 +0300859 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
860 {
861 return NoError();
862 }
863
Jamie Madillc9727f32017-11-07 12:37:07 -0500864 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500865 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300866 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500867 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300868 }
869
870 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500871 }
872
jchen10eaef1e52017-06-13 10:44:11 +0800873 gatherAtomicCounterBuffers();
Jamie Madillbd044ed2017-06-05 12:59:21 -0400874 gatherInterfaceBlockInfo(context);
Jamie Madillccdf74b2015-08-18 10:46:12 -0400875
jchen10eaef1e52017-06-13 10:44:11 +0800876 setUniformValuesFromBindingQualifiers();
877
Jamie Madill54164b02017-08-28 15:17:37 -0400878 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400879 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400880
Jamie Madill32447362017-06-28 14:53:52 -0400881 // Save to the program cache.
882 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
883 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
884 {
885 cache->putProgram(programHash, context, this);
886 }
887
Jamie Madill6c58b062017-08-01 13:44:25 -0400888 double delta = platform->currentTime(platform) - startTime;
889 int us = static_cast<int>(delta * 1000000.0);
890 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
891
Martin Radev4c4c8e72016-08-04 12:25:34 +0300892 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000893}
894
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000895// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500896void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000897{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400898 mState.mAttributes.clear();
899 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -0400900 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +0800901 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400902 mState.mUniforms.clear();
903 mState.mUniformLocations.clear();
904 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +0800905 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +0800906 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400907 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800908 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -0400909 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -0400910 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300911 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500912 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +0800913 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +0300914 mState.mNumViews = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500915
Geoff Lang7dd2e102014-11-10 15:19:26 -0500916 mValidated = false;
917
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000918 mLinked = false;
919}
920
Geoff Lange1a27752015-10-05 13:16:04 -0400921bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000922{
923 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924}
925
Jamie Madilla2c74982016-12-12 11:20:42 -0500926Error Program::loadBinary(const Context *context,
927 GLenum binaryFormat,
928 const void *binary,
929 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000930{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500931 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000932
Geoff Lang7dd2e102014-11-10 15:19:26 -0500933#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800934 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500935#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400936 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
937 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000938 {
Jamie Madillf6113162015-05-07 11:49:21 -0400939 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800940 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500941 }
942
Jamie Madill4f86d052017-06-05 12:59:26 -0400943 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
944 ANGLE_TRY_RESULT(
945 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400946
947 // Currently we require the full shader text to compute the program hash.
948 // TODO(jmadill): Store the binary in the internal program cache.
949
Jamie Madillb0a838b2016-11-13 20:02:12 -0500950 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500951#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500952}
953
Jamie Madilla2c74982016-12-12 11:20:42 -0500954Error Program::saveBinary(const Context *context,
955 GLenum *binaryFormat,
956 void *binary,
957 GLsizei bufSize,
958 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500959{
960 if (binaryFormat)
961 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400962 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500963 }
964
Jamie Madill4f86d052017-06-05 12:59:26 -0400965 angle::MemoryBuffer memoryBuf;
966 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500967
Jamie Madill4f86d052017-06-05 12:59:26 -0400968 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
969 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500970
971 if (streamLength > bufSize)
972 {
973 if (length)
974 {
975 *length = 0;
976 }
977
978 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
979 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
980 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500981 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500982 }
983
984 if (binary)
985 {
986 char *ptr = reinterpret_cast<char*>(binary);
987
Jamie Madill48ef11b2016-04-27 15:21:52 -0400988 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500989 ptr += streamLength;
990
991 ASSERT(ptr - streamLength == binary);
992 }
993
994 if (length)
995 {
996 *length = streamLength;
997 }
998
He Yunchaoacd18982017-01-04 10:46:42 +0800999 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001000}
1001
Jamie Madillffe00c02017-06-27 16:26:55 -04001002GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001003{
1004 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001005 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001006 if (error.isError())
1007 {
1008 return 0;
1009 }
1010
1011 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001012}
1013
Geoff Langc5629752015-12-07 16:29:04 -05001014void Program::setBinaryRetrievableHint(bool retrievable)
1015{
1016 // TODO(jmadill) : replace with dirty bits
1017 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001018 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001019}
1020
1021bool Program::getBinaryRetrievableHint() const
1022{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001023 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001024}
1025
Yunchao He61afff12017-03-14 15:34:03 +08001026void Program::setSeparable(bool separable)
1027{
1028 // TODO(yunchao) : replace with dirty bits
1029 if (mState.mSeparable != separable)
1030 {
1031 mProgram->setSeparable(separable);
1032 mState.mSeparable = separable;
1033 }
1034}
1035
1036bool Program::isSeparable() const
1037{
1038 return mState.mSeparable;
1039}
1040
Jamie Madill6c1f6712017-02-14 19:08:04 -05001041void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001042{
1043 mRefCount--;
1044
1045 if (mRefCount == 0 && mDeleteStatus)
1046 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001047 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001048 }
1049}
1050
1051void Program::addRef()
1052{
1053 mRefCount++;
1054}
1055
1056unsigned int Program::getRefCount() const
1057{
1058 return mRefCount;
1059}
1060
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001061int Program::getInfoLogLength() const
1062{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001063 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001064}
1065
Geoff Lange1a27752015-10-05 13:16:04 -04001066void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001067{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001068 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001069}
1070
Geoff Lange1a27752015-10-05 13:16:04 -04001071void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001072{
1073 int total = 0;
1074
Martin Radev4c4c8e72016-08-04 12:25:34 +03001075 if (mState.mAttachedComputeShader)
1076 {
1077 if (total < maxCount)
1078 {
1079 shaders[total] = mState.mAttachedComputeShader->getHandle();
1080 total++;
1081 }
1082 }
1083
Jamie Madill48ef11b2016-04-27 15:21:52 -04001084 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001085 {
1086 if (total < maxCount)
1087 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001088 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001089 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001090 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001091 }
1092
Jamie Madill48ef11b2016-04-27 15:21:52 -04001093 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001094 {
1095 if (total < maxCount)
1096 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001097 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001098 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001099 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001100 }
1101
1102 if (count)
1103 {
1104 *count = total;
1105 }
1106}
1107
Geoff Lange1a27752015-10-05 13:16:04 -04001108GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001109{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001110 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001111}
1112
Jamie Madill63805b42015-08-25 13:17:39 -04001113bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001114{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001115 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1116 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001117}
1118
jchen10fd7c3b52017-03-21 15:36:03 +08001119void Program::getActiveAttribute(GLuint index,
1120 GLsizei bufsize,
1121 GLsizei *length,
1122 GLint *size,
1123 GLenum *type,
1124 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001125{
Jamie Madillc349ec02015-08-21 16:53:12 -04001126 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001127 {
1128 if (bufsize > 0)
1129 {
1130 name[0] = '\0';
1131 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001132
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001133 if (length)
1134 {
1135 *length = 0;
1136 }
1137
1138 *type = GL_NONE;
1139 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001140 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001141 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001142
jchen1036e120e2017-03-14 14:53:58 +08001143 ASSERT(index < mState.mAttributes.size());
1144 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001145
1146 if (bufsize > 0)
1147 {
jchen10fd7c3b52017-03-21 15:36:03 +08001148 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001149 }
1150
1151 // Always a single 'type' instance
1152 *size = 1;
1153 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001154}
1155
Geoff Lange1a27752015-10-05 13:16:04 -04001156GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001157{
Jamie Madillc349ec02015-08-21 16:53:12 -04001158 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001159 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001160 return 0;
1161 }
1162
jchen1036e120e2017-03-14 14:53:58 +08001163 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001164}
1165
Geoff Lange1a27752015-10-05 13:16:04 -04001166GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001167{
Jamie Madillc349ec02015-08-21 16:53:12 -04001168 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001169 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001170 return 0;
1171 }
1172
1173 size_t maxLength = 0;
1174
Jamie Madill48ef11b2016-04-27 15:21:52 -04001175 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001176 {
jchen1036e120e2017-03-14 14:53:58 +08001177 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001178 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001179
Jamie Madillc349ec02015-08-21 16:53:12 -04001180 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001181}
1182
jchen1015015f72017-03-16 13:54:21 +08001183GLuint Program::getInputResourceIndex(const GLchar *name) const
1184{
Olli Etuahod2551232017-10-26 20:03:33 +03001185 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001186}
1187
1188GLuint Program::getOutputResourceIndex(const GLchar *name) const
1189{
1190 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1191}
1192
jchen10fd7c3b52017-03-21 15:36:03 +08001193size_t Program::getOutputResourceCount() const
1194{
1195 return (mLinked ? mState.mOutputVariables.size() : 0);
1196}
1197
jchen10baf5d942017-08-28 20:45:48 +08001198template <typename T>
1199void Program::getResourceName(GLuint index,
1200 const std::vector<T> &resources,
1201 GLsizei bufSize,
1202 GLsizei *length,
1203 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001204{
1205 if (length)
1206 {
1207 *length = 0;
1208 }
1209
1210 if (!mLinked)
1211 {
1212 if (bufSize > 0)
1213 {
1214 name[0] = '\0';
1215 }
1216 return;
1217 }
jchen10baf5d942017-08-28 20:45:48 +08001218 ASSERT(index < resources.size());
1219 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001220
1221 if (bufSize > 0)
1222 {
Olli Etuahod2551232017-10-26 20:03:33 +03001223 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001224 }
1225}
1226
jchen10baf5d942017-08-28 20:45:48 +08001227void Program::getInputResourceName(GLuint index,
1228 GLsizei bufSize,
1229 GLsizei *length,
1230 GLchar *name) const
1231{
1232 getResourceName(index, mState.mAttributes, bufSize, length, name);
1233}
1234
1235void Program::getOutputResourceName(GLuint index,
1236 GLsizei bufSize,
1237 GLsizei *length,
1238 GLchar *name) const
1239{
1240 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1241}
1242
1243void Program::getUniformResourceName(GLuint index,
1244 GLsizei bufSize,
1245 GLsizei *length,
1246 GLchar *name) const
1247{
1248 getResourceName(index, mState.mUniforms, bufSize, length, name);
1249}
1250
jchen10880683b2017-04-12 16:21:55 +08001251const sh::Attribute &Program::getInputResource(GLuint index) const
1252{
1253 ASSERT(index < mState.mAttributes.size());
1254 return mState.mAttributes[index];
1255}
1256
1257const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1258{
1259 ASSERT(index < mState.mOutputVariables.size());
1260 return mState.mOutputVariables[index];
1261}
1262
Geoff Lang7dd2e102014-11-10 15:19:26 -05001263GLint Program::getFragDataLocation(const std::string &name) const
1264{
Olli Etuahod2551232017-10-26 20:03:33 +03001265 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001266}
1267
Geoff Lange1a27752015-10-05 13:16:04 -04001268void Program::getActiveUniform(GLuint index,
1269 GLsizei bufsize,
1270 GLsizei *length,
1271 GLint *size,
1272 GLenum *type,
1273 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001274{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001275 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001276 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001277 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001278 ASSERT(index < mState.mUniforms.size());
1279 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001280
1281 if (bufsize > 0)
1282 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001283 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001284 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001285 }
1286
Jamie Madill62d31cb2015-09-11 13:25:51 -04001287 *size = uniform.elementCount();
1288 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001289 }
1290 else
1291 {
1292 if (bufsize > 0)
1293 {
1294 name[0] = '\0';
1295 }
1296
1297 if (length)
1298 {
1299 *length = 0;
1300 }
1301
1302 *size = 0;
1303 *type = GL_NONE;
1304 }
1305}
1306
Geoff Lange1a27752015-10-05 13:16:04 -04001307GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001308{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001309 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001310 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001311 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001312 }
1313 else
1314 {
1315 return 0;
1316 }
1317}
1318
Geoff Lange1a27752015-10-05 13:16:04 -04001319GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001320{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001321 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001322
1323 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001324 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001325 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001326 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001327 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001328 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001329 size_t length = uniform.name.length() + 1u;
1330 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001331 {
1332 length += 3; // Counting in "[0]".
1333 }
1334 maxLength = std::max(length, maxLength);
1335 }
1336 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001337 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001338
Jamie Madill62d31cb2015-09-11 13:25:51 -04001339 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001340}
1341
Geoff Lang7dd2e102014-11-10 15:19:26 -05001342bool Program::isValidUniformLocation(GLint location) const
1343{
Jamie Madille2e406c2016-06-02 13:04:10 -04001344 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001345 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001346 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001347}
1348
Jamie Madill62d31cb2015-09-11 13:25:51 -04001349const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001350{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001351 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001352 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001353}
1354
Jamie Madillac4e9c32017-01-13 14:07:12 -05001355const VariableLocation &Program::getUniformLocation(GLint location) const
1356{
1357 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1358 return mState.mUniformLocations[location];
1359}
1360
1361const std::vector<VariableLocation> &Program::getUniformLocations() const
1362{
1363 return mState.mUniformLocations;
1364}
1365
1366const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1367{
1368 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1369 return mState.mUniforms[index];
1370}
1371
Jamie Madill62d31cb2015-09-11 13:25:51 -04001372GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373{
Olli Etuahod2551232017-10-26 20:03:33 +03001374 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001375}
1376
Jamie Madill62d31cb2015-09-11 13:25:51 -04001377GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001378{
Jamie Madille7d84322017-01-10 18:21:59 -05001379 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380}
1381
1382void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1383{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001384 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1385 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001386 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387}
1388
1389void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1390{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001391 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1392 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001393 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394}
1395
1396void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1397{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001398 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1399 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001400 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001401}
1402
1403void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1404{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001405 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1406 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001407 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001408}
1409
Jamie Madill81c2e252017-09-09 23:32:46 -04001410Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001412 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1413 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1414
Jamie Madill81c2e252017-09-09 23:32:46 -04001415 mProgram->setUniform1iv(location, clampedCount, v);
1416
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001417 if (mState.isSamplerUniformIndex(locationInfo.index))
1418 {
1419 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001420 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001421 }
1422
Jamie Madill81c2e252017-09-09 23:32:46 -04001423 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001424}
1425
1426void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1427{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001428 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1429 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001430 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001431}
1432
1433void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1434{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001435 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1436 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001437 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438}
1439
1440void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1441{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001442 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1443 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001444 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001445}
1446
1447void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1448{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001449 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1450 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001451 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001452}
1453
1454void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1455{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001456 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1457 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001458 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001459}
1460
1461void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1462{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001463 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1464 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001465 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001466}
1467
1468void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1469{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001470 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1471 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001472 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473}
1474
1475void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1476{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001477 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001478 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479}
1480
1481void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1482{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001483 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001484 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1488{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001489 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001490 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
1493void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1494{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001495 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001496 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1500{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001501 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001502 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503}
1504
1505void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1506{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001507 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001508 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1512{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001513 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001514 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1518{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001519 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001520 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521}
1522
1523void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1524{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001525 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001526 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
Jamie Madill54164b02017-08-28 15:17:37 -04001529void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001530{
Jamie Madill54164b02017-08-28 15:17:37 -04001531 const auto &uniformLocation = mState.getUniformLocations()[location];
1532 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1533
1534 GLenum nativeType = gl::VariableComponentType(uniform.type);
1535 if (nativeType == GL_FLOAT)
1536 {
1537 mProgram->getUniformfv(context, location, v);
1538 }
1539 else
1540 {
1541 getUniformInternal(context, v, location, nativeType,
1542 gl::VariableComponentCount(uniform.type));
1543 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001544}
1545
Jamie Madill54164b02017-08-28 15:17:37 -04001546void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001547{
Jamie Madill54164b02017-08-28 15:17:37 -04001548 const auto &uniformLocation = mState.getUniformLocations()[location];
1549 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1550
1551 GLenum nativeType = gl::VariableComponentType(uniform.type);
1552 if (nativeType == GL_INT || nativeType == GL_BOOL)
1553 {
1554 mProgram->getUniformiv(context, location, v);
1555 }
1556 else
1557 {
1558 getUniformInternal(context, v, location, nativeType,
1559 gl::VariableComponentCount(uniform.type));
1560 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561}
1562
Jamie Madill54164b02017-08-28 15:17:37 -04001563void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564{
Jamie Madill54164b02017-08-28 15:17:37 -04001565 const auto &uniformLocation = mState.getUniformLocations()[location];
1566 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1567
1568 GLenum nativeType = gl::VariableComponentType(uniform.type);
1569 if (nativeType == GL_UNSIGNED_INT)
1570 {
1571 mProgram->getUniformuiv(context, location, v);
1572 }
1573 else
1574 {
1575 getUniformInternal(context, v, location, nativeType,
1576 gl::VariableComponentCount(uniform.type));
1577 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001578}
1579
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001580void Program::flagForDeletion()
1581{
1582 mDeleteStatus = true;
1583}
1584
1585bool Program::isFlaggedForDeletion() const
1586{
1587 return mDeleteStatus;
1588}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001589
Brandon Jones43a53e22014-08-28 16:23:22 -07001590void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001591{
1592 mInfoLog.reset();
1593
Geoff Lang7dd2e102014-11-10 15:19:26 -05001594 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001595 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001596 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001597 }
1598 else
1599 {
Jamie Madillf6113162015-05-07 11:49:21 -04001600 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001601 }
1602}
1603
Geoff Lang7dd2e102014-11-10 15:19:26 -05001604bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1605{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001606 // Skip cache if we're using an infolog, so we get the full error.
1607 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1608 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1609 {
1610 return mCachedValidateSamplersResult.value();
1611 }
1612
1613 if (mTextureUnitTypesCache.empty())
1614 {
1615 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1616 }
1617 else
1618 {
1619 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1620 }
1621
1622 // if any two active samplers in a program are of different types, but refer to the same
1623 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1624 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001625 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001626 {
Jamie Madill54164b02017-08-28 15:17:37 -04001627 if (samplerBinding.unreferenced)
1628 continue;
1629
Jamie Madille7d84322017-01-10 18:21:59 -05001630 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001631
Jamie Madille7d84322017-01-10 18:21:59 -05001632 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001633 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001634 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1635 {
1636 if (infoLog)
1637 {
1638 (*infoLog) << "Sampler uniform (" << textureUnit
1639 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1640 << caps.maxCombinedTextureImageUnits << ")";
1641 }
1642
1643 mCachedValidateSamplersResult = false;
1644 return false;
1645 }
1646
1647 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1648 {
1649 if (textureType != mTextureUnitTypesCache[textureUnit])
1650 {
1651 if (infoLog)
1652 {
1653 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1654 "image unit ("
1655 << textureUnit << ").";
1656 }
1657
1658 mCachedValidateSamplersResult = false;
1659 return false;
1660 }
1661 }
1662 else
1663 {
1664 mTextureUnitTypesCache[textureUnit] = textureType;
1665 }
1666 }
1667 }
1668
1669 mCachedValidateSamplersResult = true;
1670 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001671}
1672
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001673bool Program::isValidated() const
1674{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001675 return mValidated;
1676}
1677
Geoff Lange1a27752015-10-05 13:16:04 -04001678GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001679{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001680 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001681}
1682
jchen1058f67be2017-10-27 08:59:27 +08001683GLuint Program::getActiveAtomicCounterBufferCount() const
1684{
1685 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1686}
1687
Jiajia Qin729b2c62017-08-14 09:36:11 +08001688GLuint Program::getActiveShaderStorageBlockCount() const
1689{
1690 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1691}
1692
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1694{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001695 ASSERT(
1696 uniformBlockIndex <
1697 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001698
Jiajia Qin729b2c62017-08-14 09:36:11 +08001699 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001700
1701 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001702 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001703 std::string string = uniformBlock.name;
1704
Jamie Madill62d31cb2015-09-11 13:25:51 -04001705 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001706 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001707 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001708 }
jchen10fd7c3b52017-03-21 15:36:03 +08001709 CopyStringToBuffer(uniformBlockName, string, bufSize, length);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001710 }
1711}
1712
Geoff Lange1a27752015-10-05 13:16:04 -04001713GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001714{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715 int maxLength = 0;
1716
1717 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001718 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001719 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001720 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1721 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001722 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001723 if (!uniformBlock.name.empty())
1724 {
jchen10af713a22017-04-19 09:10:56 +08001725 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1726 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001727 }
1728 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001729 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001730
1731 return maxLength;
1732}
1733
Geoff Lange1a27752015-10-05 13:16:04 -04001734GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001735{
Olli Etuahoc8538042017-09-27 11:20:15 +03001736 std::vector<unsigned int> subscripts;
1737 std::string baseName = ParseResourceName(name, &subscripts);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001738
Jamie Madill48ef11b2016-04-27 15:21:52 -04001739 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001740 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1741 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001742 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001743 if (uniformBlock.name == baseName)
1744 {
1745 const bool arrayElementZero =
Olli Etuahoc8538042017-09-27 11:20:15 +03001746 (subscripts.empty() && (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1747 const bool arrayElementMatches =
1748 (subscripts.size() == 1 && subscripts[0] == uniformBlock.arrayElement);
1749 if (arrayElementMatches || arrayElementZero)
Jamie Madill62d31cb2015-09-11 13:25:51 -04001750 {
1751 return blockIndex;
1752 }
1753 }
1754 }
1755
1756 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001757}
1758
Jiajia Qin729b2c62017-08-14 09:36:11 +08001759const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001760{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001761 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1762 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001763}
1764
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001765void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1766{
jchen107a20b972017-06-13 14:25:26 +08001767 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001768 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001769 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001770}
1771
1772GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1773{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001774 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001775}
1776
Jiajia Qin729b2c62017-08-14 09:36:11 +08001777GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1778{
1779 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1780}
1781
Geoff Lang48dcae72014-02-05 16:28:24 -05001782void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1783{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001784 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001785 for (GLsizei i = 0; i < count; i++)
1786 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001787 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001788 }
1789
Jamie Madill48ef11b2016-04-27 15:21:52 -04001790 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001791}
1792
1793void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1794{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001795 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001796 {
jchen10a9042d32017-03-17 08:50:45 +08001797 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1798 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1799 std::string varName = var.nameWithArrayIndex();
1800 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001801 if (length)
1802 {
1803 *length = lastNameIdx;
1804 }
1805 if (size)
1806 {
jchen10a9042d32017-03-17 08:50:45 +08001807 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001808 }
1809 if (type)
1810 {
jchen10a9042d32017-03-17 08:50:45 +08001811 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001812 }
1813 if (name)
1814 {
jchen10a9042d32017-03-17 08:50:45 +08001815 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001816 name[lastNameIdx] = '\0';
1817 }
1818 }
1819}
1820
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001821GLsizei Program::getTransformFeedbackVaryingCount() const
1822{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001823 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001824 {
jchen10a9042d32017-03-17 08:50:45 +08001825 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001826 }
1827 else
1828 {
1829 return 0;
1830 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001831}
1832
1833GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1834{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001835 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001836 {
1837 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001838 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001839 {
jchen10a9042d32017-03-17 08:50:45 +08001840 maxSize =
1841 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001842 }
1843
1844 return maxSize;
1845 }
1846 else
1847 {
1848 return 0;
1849 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001850}
1851
1852GLenum Program::getTransformFeedbackBufferMode() const
1853{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001854 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001855}
1856
Jamie Madillbd044ed2017-06-05 12:59:21 -04001857bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001858{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001859 Shader *vertexShader = mState.mAttachedVertexShader;
1860 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001861
Jamie Madillbd044ed2017-06-05 12:59:21 -04001862 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001863
Jiawei Shao3d404882017-10-16 13:30:48 +08001864 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
1865 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001866
Sami Väisänen46eaa942016-06-29 10:26:37 +03001867 std::map<GLuint, std::string> staticFragmentInputLocations;
1868
Jamie Madill4cff2472015-08-21 16:53:18 -04001869 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001870 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871 bool matched = false;
1872
1873 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001874 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 {
1876 continue;
1877 }
1878
Jamie Madill4cff2472015-08-21 16:53:18 -04001879 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001880 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001881 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001883 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001884 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04001885 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001886 {
1887 return false;
1888 }
1889
Geoff Lang7dd2e102014-11-10 15:19:26 -05001890 matched = true;
1891 break;
1892 }
1893 }
1894
1895 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001896 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001897 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001898 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001899 return false;
1900 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001901
1902 // Check for aliased path rendering input bindings (if any).
1903 // If more than one binding refer statically to the same
1904 // location the link must fail.
1905
1906 if (!output.staticUse)
1907 continue;
1908
1909 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1910 if (inputBinding == -1)
1911 continue;
1912
1913 const auto it = staticFragmentInputLocations.find(inputBinding);
1914 if (it == std::end(staticFragmentInputLocations))
1915 {
1916 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1917 }
1918 else
1919 {
1920 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1921 << it->second;
1922 return false;
1923 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924 }
1925
Jamie Madillbd044ed2017-06-05 12:59:21 -04001926 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05001927 {
1928 return false;
1929 }
1930
Jamie Madillada9ecc2015-08-17 12:53:37 -04001931 // TODO(jmadill): verify no unmatched vertex varyings?
1932
Geoff Lang7dd2e102014-11-10 15:19:26 -05001933 return true;
1934}
1935
Jamie Madillbd044ed2017-06-05 12:59:21 -04001936bool Program::linkUniforms(const Context *context,
1937 InfoLog &infoLog,
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001938 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001939{
Olli Etuahob78707c2017-03-09 15:03:11 +00001940 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04001941 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04001942 {
1943 return false;
1944 }
1945
Olli Etuahob78707c2017-03-09 15:03:11 +00001946 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001947
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001948 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001949
jchen10eaef1e52017-06-13 10:44:11 +08001950 if (!linkAtomicCounterBuffers())
1951 {
1952 return false;
1953 }
1954
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001955 return true;
1956}
1957
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001958void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001959{
Jamie Madill982f6e02017-06-07 14:33:04 -04001960 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
1961 unsigned int low = high;
1962
jchen10eaef1e52017-06-13 10:44:11 +08001963 for (auto counterIter = mState.mUniforms.rbegin();
1964 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
1965 {
1966 --low;
1967 }
1968
1969 mState.mAtomicCounterUniformRange = RangeUI(low, high);
1970
1971 high = low;
1972
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001973 for (auto imageIter = mState.mUniforms.rbegin();
1974 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
1975 {
1976 --low;
1977 }
1978
1979 mState.mImageUniformRange = RangeUI(low, high);
1980
1981 // If uniform is a image type, insert it into the mImageBindings array.
1982 for (unsigned int imageIndex : mState.mImageUniformRange)
1983 {
Xinghua Cao0328b572017-06-26 15:51:36 +08001984 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
1985 // cannot load values into a uniform defined as an image. if declare without a
1986 // binding qualifier, any uniform image variable (include all elements of
1987 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001988 auto &imageUniform = mState.mUniforms[imageIndex];
1989 if (imageUniform.binding == -1)
1990 {
Xinghua Cao0328b572017-06-26 15:51:36 +08001991 mState.mImageBindings.emplace_back(ImageBinding(imageUniform.elementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001992 }
Xinghua Cao0328b572017-06-26 15:51:36 +08001993 else
1994 {
1995 mState.mImageBindings.emplace_back(
1996 ImageBinding(imageUniform.binding, imageUniform.elementCount()));
1997 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001998 }
1999
2000 high = low;
2001
2002 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002003 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002004 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002005 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002006 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002007
2008 mState.mSamplerUniformRange = RangeUI(low, high);
2009
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002010 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002011 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002012 {
2013 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2014 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2015 mState.mSamplerBindings.emplace_back(
Jamie Madill54164b02017-08-28 15:17:37 -04002016 SamplerBinding(textureType, samplerUniform.elementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002017 }
2018}
2019
jchen10eaef1e52017-06-13 10:44:11 +08002020bool Program::linkAtomicCounterBuffers()
2021{
2022 for (unsigned int index : mState.mAtomicCounterUniformRange)
2023 {
2024 auto &uniform = mState.mUniforms[index];
2025 bool found = false;
2026 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2027 ++bufferIndex)
2028 {
2029 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2030 if (buffer.binding == uniform.binding)
2031 {
2032 buffer.memberIndexes.push_back(index);
2033 uniform.bufferIndex = bufferIndex;
2034 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002035 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002036 break;
2037 }
2038 }
2039 if (!found)
2040 {
2041 AtomicCounterBuffer atomicCounterBuffer;
2042 atomicCounterBuffer.binding = uniform.binding;
2043 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002044 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002045 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2046 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2047 }
2048 }
2049 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2050 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2051
2052 return true;
2053}
2054
Martin Radev4c4c8e72016-08-04 12:25:34 +03002055bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2056 const std::string &uniformName,
2057 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002058 const sh::InterfaceBlockField &fragmentUniform,
2059 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002060{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002061 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2062 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2063 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064 {
2065 return false;
2066 }
2067
2068 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2069 {
Jamie Madillf6113162015-05-07 11:49:21 -04002070 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071 return false;
2072 }
2073
2074 return true;
2075}
2076
Jamie Madilleb979bf2016-11-15 12:28:46 -05002077// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002078bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002079{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002080 const ContextState &data = context->getContextState();
2081 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002082
Geoff Lang7dd2e102014-11-10 15:19:26 -05002083 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002084 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002085 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002086
2087 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002088 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002089 {
Jamie Madillf6113162015-05-07 11:49:21 -04002090 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002091 return false;
2092 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002093
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002094 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002095
Jamie Madillc349ec02015-08-21 16:53:12 -04002096 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002097 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002098 {
Olli Etuahod2551232017-10-26 20:03:33 +03002099 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2100 // structures, so we don't need to worry about adjusting their names or generating entries
2101 // for each member/element (unlike uniforms for example).
2102 ASSERT(!attribute.isArray() && !attribute.isStruct());
2103
Jamie Madilleb979bf2016-11-15 12:28:46 -05002104 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002105 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002106 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002107 attribute.location = bindingLocation;
2108 }
2109
2110 if (attribute.location != -1)
2111 {
2112 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002113 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002114
Jamie Madill63805b42015-08-25 13:17:39 -04002115 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002116 {
Jamie Madillf6113162015-05-07 11:49:21 -04002117 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002118 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002119
2120 return false;
2121 }
2122
Jamie Madill63805b42015-08-25 13:17:39 -04002123 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002124 {
Jamie Madill63805b42015-08-25 13:17:39 -04002125 const int regLocation = attribute.location + reg;
2126 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002127
2128 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002129 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002130 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002132 // TODO(jmadill): fix aliasing on ES2
2133 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002134 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002135 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002136 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002137 return false;
2138 }
2139 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002140 else
2141 {
Jamie Madill63805b42015-08-25 13:17:39 -04002142 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002143 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144
Jamie Madill63805b42015-08-25 13:17:39 -04002145 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 }
2147 }
2148 }
2149
2150 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002151 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002152 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002153 // Not set by glBindAttribLocation or by location layout qualifier
2154 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002155 {
Jamie Madill63805b42015-08-25 13:17:39 -04002156 int regs = VariableRegisterCount(attribute.type);
2157 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002158
Jamie Madill63805b42015-08-25 13:17:39 -04002159 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002160 {
Jamie Madillf6113162015-05-07 11:49:21 -04002161 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002162 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002163 }
2164
Jamie Madillc349ec02015-08-21 16:53:12 -04002165 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002166 }
2167 }
2168
Jamie Madill48ef11b2016-04-27 15:21:52 -04002169 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002170 {
Jamie Madill63805b42015-08-25 13:17:39 -04002171 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002172 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002173
Jamie Madillbd159f02017-10-09 19:39:06 -04002174 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002176 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2177 mState.mActiveAttribLocationsMask.set(location);
2178 mState.mMaxActiveAttribLocation =
2179 std::max(mState.mMaxActiveAttribLocation, location + 1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002180 }
2181 }
2182
Geoff Lang7dd2e102014-11-10 15:19:26 -05002183 return true;
2184}
2185
Martin Radev4c4c8e72016-08-04 12:25:34 +03002186bool Program::validateVertexAndFragmentInterfaceBlocks(
2187 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2188 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002189 InfoLog &infoLog,
2190 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002191{
2192 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002193 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2194 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002195
2196 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2197 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002198 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002199 }
2200
Jamie Madille473dee2015-08-18 14:49:01 -04002201 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002202 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002203 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2204 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205 {
2206 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002207 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2208 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002209 {
2210 return false;
2211 }
2212 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002213 // TODO(jiajia.qin@intel.com): Add
2214 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002215 }
2216 return true;
2217}
Jamie Madille473dee2015-08-18 14:49:01 -04002218
Jiajia Qin729b2c62017-08-14 09:36:11 +08002219bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002220{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002221 const auto &caps = context->getCaps();
2222
Martin Radev4c4c8e72016-08-04 12:25:34 +03002223 if (mState.mAttachedComputeShader)
2224 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002225 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002226 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002227
Jiajia Qin729b2c62017-08-14 09:36:11 +08002228 if (!validateInterfaceBlocksCount(
2229 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002230 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2231 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002232 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002233 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002234 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002235
2236 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2237 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2238 computeShaderStorageBlocks,
2239 "Compute shader shader storage block count exceeds "
2240 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2241 infoLog))
2242 {
2243 return false;
2244 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002245 return true;
2246 }
2247
Jamie Madillbd044ed2017-06-05 12:59:21 -04002248 Shader &vertexShader = *mState.mAttachedVertexShader;
2249 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002250
Jiajia Qin729b2c62017-08-14 09:36:11 +08002251 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2252 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002253
Jiajia Qin729b2c62017-08-14 09:36:11 +08002254 if (!validateInterfaceBlocksCount(
2255 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002256 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2257 {
2258 return false;
2259 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002260 if (!validateInterfaceBlocksCount(
2261 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002262 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2263 infoLog))
2264 {
2265
2266 return false;
2267 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002268
2269 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002270 if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002271 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002272 {
2273 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002274 }
Jamie Madille473dee2015-08-18 14:49:01 -04002275
Jiajia Qin729b2c62017-08-14 09:36:11 +08002276 if (context->getClientVersion() >= Version(3, 1))
2277 {
2278 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2279 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2280
2281 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2282 vertexShaderStorageBlocks,
2283 "Vertex shader shader storage block count exceeds "
2284 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2285 infoLog))
2286 {
2287 return false;
2288 }
2289 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2290 fragmentShaderStorageBlocks,
2291 "Fragment shader shader storage block count exceeds "
2292 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2293 infoLog))
2294 {
2295
2296 return false;
2297 }
2298
2299 if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
2300 fragmentShaderStorageBlocks, infoLog,
2301 webglCompatibility))
2302 {
2303 return false;
2304 }
2305 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002306 return true;
2307}
2308
Jamie Madilla2c74982016-12-12 11:20:42 -05002309bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002310 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002311 const sh::InterfaceBlock &fragmentInterfaceBlock,
2312 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002313{
2314 const char* blockName = vertexInterfaceBlock.name.c_str();
2315 // validate blocks for the same member types
2316 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2317 {
Jamie Madillf6113162015-05-07 11:49:21 -04002318 infoLog << "Types for interface block '" << blockName
2319 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002320 return false;
2321 }
2322 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2323 {
Jamie Madillf6113162015-05-07 11:49:21 -04002324 infoLog << "Array sizes differ for interface block '" << blockName
2325 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002326 return false;
2327 }
jchen10af713a22017-04-19 09:10:56 +08002328 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2329 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2330 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002331 {
Jamie Madillf6113162015-05-07 11:49:21 -04002332 infoLog << "Layout qualifiers differ for interface block '" << blockName
2333 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002334 return false;
2335 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002336 const unsigned int numBlockMembers =
2337 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002338 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2339 {
2340 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2341 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2342 if (vertexMember.name != fragmentMember.name)
2343 {
Jamie Madillf6113162015-05-07 11:49:21 -04002344 infoLog << "Name mismatch for field " << blockMemberIndex
2345 << " of interface block '" << blockName
2346 << "': (in vertex: '" << vertexMember.name
2347 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002348 return false;
2349 }
2350 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002351 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2352 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002353 {
2354 return false;
2355 }
2356 }
2357 return true;
2358}
2359
2360bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2361 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2362{
2363 if (vertexVariable.type != fragmentVariable.type)
2364 {
Jamie Madillf6113162015-05-07 11:49:21 -04002365 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002366 return false;
2367 }
2368 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2369 {
Jamie Madillf6113162015-05-07 11:49:21 -04002370 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002371 return false;
2372 }
2373 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2374 {
Jamie Madillf6113162015-05-07 11:49:21 -04002375 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002376 return false;
2377 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002378 if (vertexVariable.structName != fragmentVariable.structName)
2379 {
2380 infoLog << "Structure names for " << variableName
2381 << " differ between vertex and fragment shaders";
2382 return false;
2383 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002384
2385 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2386 {
Jamie Madillf6113162015-05-07 11:49:21 -04002387 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002388 return false;
2389 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002390 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002391 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2392 {
2393 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2394 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2395
2396 if (vertexMember.name != fragmentMember.name)
2397 {
Jamie Madillf6113162015-05-07 11:49:21 -04002398 infoLog << "Name mismatch for field '" << memberIndex
2399 << "' of " << variableName
2400 << ": (in vertex: '" << vertexMember.name
2401 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002402 return false;
2403 }
2404
2405 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2406 vertexMember.name + "'";
2407
2408 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2409 {
2410 return false;
2411 }
2412 }
2413
2414 return true;
2415}
2416
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002417bool Program::linkValidateVaryings(InfoLog &infoLog,
2418 const std::string &varyingName,
2419 const sh::Varying &vertexVarying,
2420 const sh::Varying &fragmentVarying,
2421 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002422{
2423 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2424 {
2425 return false;
2426 }
2427
Jamie Madille9cc4692015-02-19 16:00:13 -05002428 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002429 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002430 infoLog << "Interpolation types for " << varyingName
2431 << " differ between vertex and fragment shaders.";
2432 return false;
2433 }
2434
2435 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2436 {
2437 infoLog << "Invariance for " << varyingName
2438 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002439 return false;
2440 }
2441
2442 return true;
2443}
2444
Jamie Madillbd044ed2017-06-05 12:59:21 -04002445bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002446{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002447 Shader *vertexShader = mState.mAttachedVertexShader;
2448 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002449 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2450 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002451 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002452
2453 if (shaderVersion != 100)
2454 {
2455 // Only ESSL 1.0 has restrictions on matching input and output invariance
2456 return true;
2457 }
2458
2459 bool glPositionIsInvariant = false;
2460 bool glPointSizeIsInvariant = false;
2461 bool glFragCoordIsInvariant = false;
2462 bool glPointCoordIsInvariant = false;
2463
2464 for (const sh::Varying &varying : vertexVaryings)
2465 {
2466 if (!varying.isBuiltIn())
2467 {
2468 continue;
2469 }
2470 if (varying.name.compare("gl_Position") == 0)
2471 {
2472 glPositionIsInvariant = varying.isInvariant;
2473 }
2474 else if (varying.name.compare("gl_PointSize") == 0)
2475 {
2476 glPointSizeIsInvariant = varying.isInvariant;
2477 }
2478 }
2479
2480 for (const sh::Varying &varying : fragmentVaryings)
2481 {
2482 if (!varying.isBuiltIn())
2483 {
2484 continue;
2485 }
2486 if (varying.name.compare("gl_FragCoord") == 0)
2487 {
2488 glFragCoordIsInvariant = varying.isInvariant;
2489 }
2490 else if (varying.name.compare("gl_PointCoord") == 0)
2491 {
2492 glPointCoordIsInvariant = varying.isInvariant;
2493 }
2494 }
2495
2496 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2497 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2498 // Not requiring invariance to match is supported by:
2499 // dEQP, WebGL CTS, Nexus 5X GLES
2500 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2501 {
2502 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2503 "declared invariant.";
2504 return false;
2505 }
2506 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2507 {
2508 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2509 "declared invariant.";
2510 return false;
2511 }
2512
2513 return true;
2514}
2515
jchen10a9042d32017-03-17 08:50:45 +08002516bool Program::linkValidateTransformFeedback(const gl::Context *context,
2517 InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002518 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002519 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002520{
2521 size_t totalComponents = 0;
2522
Jamie Madillccdf74b2015-08-18 10:46:12 -04002523 std::set<std::string> uniqueNames;
2524
Jamie Madill48ef11b2016-04-27 15:21:52 -04002525 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002526 {
2527 bool found = false;
Olli Etuahoc8538042017-09-27 11:20:15 +03002528 std::vector<unsigned int> subscripts;
2529 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002530
Jamie Madill192745a2016-12-22 15:58:21 -05002531 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002532 {
Jamie Madill192745a2016-12-22 15:58:21 -05002533 const sh::Varying *varying = ref.second.get();
2534
jchen10a9042d32017-03-17 08:50:45 +08002535 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002536 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002537 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002538 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002539 infoLog << "Two transform feedback varyings specify the same output variable ("
2540 << tfVaryingName << ").";
2541 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002542 }
jchen10a9042d32017-03-17 08:50:45 +08002543 if (context->getClientVersion() >= Version(3, 1))
2544 {
2545 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2546 {
2547 infoLog
2548 << "Two transform feedback varyings include the same array element ("
2549 << tfVaryingName << ").";
2550 return false;
2551 }
2552 }
2553 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002554 {
2555 infoLog << "Capture of arrays is undefined and not supported.";
2556 return false;
2557 }
2558
jchen10a9042d32017-03-17 08:50:45 +08002559 uniqueNames.insert(tfVaryingName);
2560
Jamie Madillccdf74b2015-08-18 10:46:12 -04002561 // TODO(jmadill): Investigate implementation limits on D3D11
jchen10a9042d32017-03-17 08:50:45 +08002562 size_t elementCount =
Olli Etuahoc8538042017-09-27 11:20:15 +03002563 ((varying->isArray() && subscripts.empty()) ? varying->elementCount() : 1);
jchen10a9042d32017-03-17 08:50:45 +08002564 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002565 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002566 componentCount > caps.maxTransformFeedbackSeparateComponents)
2567 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002568 infoLog << "Transform feedback varying's " << varying->name << " components ("
2569 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002570 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002571 return false;
2572 }
2573
2574 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002575 found = true;
2576 break;
2577 }
2578 }
jchen10a9042d32017-03-17 08:50:45 +08002579 if (context->getClientVersion() < Version(3, 1) &&
2580 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002581 {
Geoff Lang1a683462015-09-29 15:09:59 -04002582 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002583 return false;
2584 }
Olli Etuaho39e78122017-08-29 14:34:22 +03002585 // All transform feedback varyings are expected to exist since packUserVaryings checks for
2586 // them.
Geoff Lang7dd2e102014-11-10 15:19:26 -05002587 ASSERT(found);
2588 }
2589
Jamie Madill48ef11b2016-04-27 15:21:52 -04002590 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002591 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002592 {
Jamie Madillf6113162015-05-07 11:49:21 -04002593 infoLog << "Transform feedback varying total components (" << totalComponents
2594 << ") exceed the maximum interleaved components ("
2595 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002596 return false;
2597 }
2598
2599 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002600}
2601
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002602bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
2603{
2604 const std::vector<sh::Uniform> &vertexUniforms =
2605 mState.mAttachedVertexShader->getUniforms(context);
2606 const std::vector<sh::Uniform> &fragmentUniforms =
2607 mState.mAttachedFragmentShader->getUniforms(context);
2608 const std::vector<sh::Attribute> &attributes =
2609 mState.mAttachedVertexShader->getActiveAttributes(context);
2610 for (const auto &attrib : attributes)
2611 {
2612 for (const auto &uniform : vertexUniforms)
2613 {
2614 if (uniform.name == attrib.name)
2615 {
2616 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2617 return false;
2618 }
2619 }
2620 for (const auto &uniform : fragmentUniforms)
2621 {
2622 if (uniform.name == attrib.name)
2623 {
2624 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2625 return false;
2626 }
2627 }
2628 }
2629 return true;
2630}
2631
Jamie Madill192745a2016-12-22 15:58:21 -05002632void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002633{
2634 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002635 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002636 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002637 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002638 std::vector<unsigned int> subscripts;
2639 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002640 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002641 if (!subscripts.empty())
2642 {
2643 subscript = subscripts.back();
2644 }
Jamie Madill192745a2016-12-22 15:58:21 -05002645 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002646 {
Jamie Madill192745a2016-12-22 15:58:21 -05002647 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002648 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002649 {
jchen10a9042d32017-03-17 08:50:45 +08002650 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2651 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002652 break;
2653 }
2654 }
2655 }
2656}
2657
Jamie Madillbd044ed2017-06-05 12:59:21 -04002658Program::MergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002659{
Jamie Madill192745a2016-12-22 15:58:21 -05002660 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002661
Jiawei Shao3d404882017-10-16 13:30:48 +08002662 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002663 {
Jamie Madill192745a2016-12-22 15:58:21 -05002664 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002665 }
2666
Jiawei Shao3d404882017-10-16 13:30:48 +08002667 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002668 {
Jamie Madill192745a2016-12-22 15:58:21 -05002669 merged[varying.name].fragment = &varying;
2670 }
2671
2672 return merged;
2673}
2674
2675std::vector<PackedVarying> Program::getPackedVaryings(
2676 const Program::MergedVaryings &mergedVaryings) const
2677{
2678 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2679 std::vector<PackedVarying> packedVaryings;
jchen10a9042d32017-03-17 08:50:45 +08002680 std::set<std::string> uniqueFullNames;
Jamie Madill192745a2016-12-22 15:58:21 -05002681
2682 for (const auto &ref : mergedVaryings)
2683 {
2684 const sh::Varying *input = ref.second.vertex;
2685 const sh::Varying *output = ref.second.fragment;
2686
2687 // Only pack varyings that have a matched input or output, plus special builtins.
2688 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002689 {
Jamie Madill192745a2016-12-22 15:58:21 -05002690 // Will get the vertex shader interpolation by default.
2691 auto interpolation = ref.second.get()->interpolation;
2692
Olli Etuaho06a06f52017-07-12 12:22:15 +03002693 // Note that we lose the vertex shader static use information here. The data for the
2694 // variable is taken from the fragment shader.
Jamie Madill192745a2016-12-22 15:58:21 -05002695 if (output->isStruct())
2696 {
2697 ASSERT(!output->isArray());
2698 for (const auto &field : output->fields)
2699 {
2700 ASSERT(!field.isStruct() && !field.isArray());
2701 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2702 }
2703 }
2704 else
2705 {
2706 packedVaryings.push_back(PackedVarying(*output, interpolation));
2707 }
2708 continue;
2709 }
2710
2711 // Keep Transform FB varyings in the merged list always.
2712 if (!input)
2713 {
2714 continue;
2715 }
2716
2717 for (const std::string &tfVarying : tfVaryings)
2718 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002719 std::vector<unsigned int> subscripts;
2720 std::string baseName = ParseResourceName(tfVarying, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002721 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002722 if (!subscripts.empty())
2723 {
2724 subscript = subscripts.back();
2725 }
jchen10a9042d32017-03-17 08:50:45 +08002726 if (uniqueFullNames.count(tfVarying) > 0)
2727 {
2728 continue;
2729 }
2730 if (baseName == input->name)
Jamie Madill192745a2016-12-22 15:58:21 -05002731 {
2732 // Transform feedback for varying structs is underspecified.
2733 // See Khronos bug 9856.
2734 // TODO(jmadill): Figure out how to be spec-compliant here.
2735 if (!input->isStruct())
2736 {
2737 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2738 packedVaryings.back().vertexOnly = true;
jchen10a9042d32017-03-17 08:50:45 +08002739 packedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
2740 uniqueFullNames.insert(tfVarying);
Jamie Madill192745a2016-12-22 15:58:21 -05002741 }
jchen10a9042d32017-03-17 08:50:45 +08002742 if (subscript == GL_INVALID_INDEX)
2743 {
2744 break;
2745 }
Jamie Madill192745a2016-12-22 15:58:21 -05002746 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002747 }
2748 }
2749
Jamie Madill192745a2016-12-22 15:58:21 -05002750 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2751
2752 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002753}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002754
Jamie Madillbd044ed2017-06-05 12:59:21 -04002755void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002756{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002757 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002758 ASSERT(fragmentShader != nullptr);
2759
Geoff Lange0cff192017-05-30 13:04:56 -04002760 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002761 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002762
2763 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002764 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002765 {
2766 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2767 outputVariable.name != "gl_FragData")
2768 {
2769 continue;
2770 }
2771
2772 unsigned int baseLocation =
2773 (outputVariable.location == -1 ? 0u
2774 : static_cast<unsigned int>(outputVariable.location));
2775 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2776 elementIndex++)
2777 {
2778 const unsigned int location = baseLocation + elementIndex;
2779 if (location >= mState.mOutputVariableTypes.size())
2780 {
2781 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2782 }
Corentin Walleze7557742017-06-01 13:09:57 -04002783 ASSERT(location < mState.mActiveOutputVariables.size());
2784 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002785 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2786 }
2787 }
2788
Jamie Madill80a6fc02015-08-21 16:53:16 -04002789 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002790 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002791 return;
2792
Jamie Madillbd044ed2017-06-05 12:59:21 -04002793 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002794 // TODO(jmadill): any caps validation here?
2795
jchen1015015f72017-03-16 13:54:21 +08002796 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002797 outputVariableIndex++)
2798 {
jchen1015015f72017-03-16 13:54:21 +08002799 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002800
Olli Etuahod2551232017-10-26 20:03:33 +03002801 if (outputVariable.isArray())
2802 {
2803 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2804 // Resources and including [0] at the end of array variable names.
2805 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2806 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2807 }
2808
Jamie Madill80a6fc02015-08-21 16:53:16 -04002809 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2810 if (outputVariable.isBuiltIn())
2811 continue;
2812
2813 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002814 unsigned int baseLocation =
2815 (outputVariable.location == -1 ? 0u
2816 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002817
Jamie Madill80a6fc02015-08-21 16:53:16 -04002818 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2819 elementIndex++)
2820 {
Olli Etuahod2551232017-10-26 20:03:33 +03002821 const unsigned int location = baseLocation + elementIndex;
2822 if (location >= mState.mOutputLocations.size())
2823 {
2824 mState.mOutputLocations.resize(location + 1);
2825 }
2826 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03002827 if (outputVariable.isArray())
2828 {
2829 mState.mOutputLocations[location] =
2830 VariableLocation(elementIndex, outputVariableIndex);
2831 }
2832 else
2833 {
2834 VariableLocation locationInfo;
2835 locationInfo.index = outputVariableIndex;
2836 mState.mOutputLocations[location] = locationInfo;
2837 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04002838 }
2839 }
2840}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002841
Olli Etuaho48fed632017-03-16 12:05:30 +00002842void Program::setUniformValuesFromBindingQualifiers()
2843{
Jamie Madill982f6e02017-06-07 14:33:04 -04002844 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002845 {
2846 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2847 if (samplerUniform.binding != -1)
2848 {
Olli Etuahod2551232017-10-26 20:03:33 +03002849 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00002850 ASSERT(location != -1);
2851 std::vector<GLint> boundTextureUnits;
2852 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2853 ++elementIndex)
2854 {
2855 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2856 }
2857 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2858 boundTextureUnits.data());
2859 }
2860 }
2861}
2862
jchen10eaef1e52017-06-13 10:44:11 +08002863void Program::gatherAtomicCounterBuffers()
2864{
jchen10baf5d942017-08-28 20:45:48 +08002865 for (unsigned int index : mState.mAtomicCounterUniformRange)
2866 {
2867 auto &uniform = mState.mUniforms[index];
2868 uniform.blockInfo.offset = uniform.offset;
2869 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2870 uniform.blockInfo.matrixStride = 0;
2871 uniform.blockInfo.isRowMajorMatrix = false;
2872 }
2873
jchen10eaef1e52017-06-13 10:44:11 +08002874 // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
2875}
2876
Jamie Madill977abce2017-11-07 08:03:19 -05002877void Program::gatherUniformBlockInfo(const gl::Context *context)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002878{
Jamie Madill977abce2017-11-07 08:03:19 -05002879 UniformBlockLinker blockLinker(&mState.mUniformBlocks, &mState.mUniforms);
Jamie Madillc9727f32017-11-07 12:37:07 -05002880 InitUniformBlockLinker(context, mState, &blockLinker);
Jamie Madill977abce2017-11-07 08:03:19 -05002881
2882 auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
2883 size_t *sizeOut) {
2884 return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
2885 };
2886
2887 auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
2888 sh::BlockMemberInfo *infoOut) {
2889 return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
2890 };
2891
2892 blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002893}
Martin Radev4c4c8e72016-08-04 12:25:34 +03002894
Jamie Madill977abce2017-11-07 08:03:19 -05002895void Program::gatherShaderStorageBlockInfo(const gl::Context *context)
Jiajia Qin729b2c62017-08-14 09:36:11 +08002896{
Jamie Madill977abce2017-11-07 08:03:19 -05002897 ShaderStorageBlockLinker blockLinker(&mState.mShaderStorageBlocks);
Jamie Madillc9727f32017-11-07 12:37:07 -05002898 InitShaderStorageBlockLinker(context, mState, &blockLinker);
Jamie Madill977abce2017-11-07 08:03:19 -05002899
2900 // We don't have a way of determining block info for shader storage blocks yet.
2901 // TODO(jiajia.qin@intel.com): Determine correct block size and layout.
2902 auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
2903 size_t *sizeOut) {
2904 return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
2905 };
2906
2907 auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
2908 sh::BlockMemberInfo *infoOut) {
2909 return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
2910 };
2911
2912 blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002913}
2914
2915void Program::gatherInterfaceBlockInfo(const Context *context)
2916{
2917 ASSERT(mState.mUniformBlocks.empty());
2918 ASSERT(mState.mShaderStorageBlocks.empty());
2919
Jamie Madill977abce2017-11-07 08:03:19 -05002920 gatherUniformBlockInfo(context);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002921 if (context->getClientVersion() >= Version(3, 1))
2922 {
Jamie Madill977abce2017-11-07 08:03:19 -05002923 gatherShaderStorageBlockInfo(context);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002924 }
2925
jchen10af713a22017-04-19 09:10:56 +08002926 // Set initial bindings from shader.
2927 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2928 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002929 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08002930 bindUniformBlock(blockIndex, uniformBlock.binding);
2931 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002932}
2933
Jamie Madille7d84322017-01-10 18:21:59 -05002934void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05002935 GLsizei clampedCount,
2936 const GLint *v)
2937{
Jamie Madill81c2e252017-09-09 23:32:46 -04002938 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
2939 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2940 std::vector<GLuint> *boundTextureUnits =
2941 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05002942
Olli Etuaho1734e172017-10-27 15:30:27 +03002943 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04002944
2945 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04002946 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05002947}
2948
2949template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002950GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
2951 GLsizei count,
2952 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05002953 const T *v)
2954{
Jamie Madill134f93d2017-08-31 17:11:00 -04002955 if (count == 1)
2956 return 1;
2957
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002958 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002959
Corentin Wallez15ac5342016-11-03 17:06:39 -04002960 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2961 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03002962 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002963 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002964 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002965
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002966 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002967 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002968 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002969 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002970
2971 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002972}
2973
2974template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002975GLsizei Program::clampMatrixUniformCount(GLint location,
2976 GLsizei count,
2977 GLboolean transpose,
2978 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002979{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002980 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2981
Jamie Madill62d31cb2015-09-11 13:25:51 -04002982 if (!transpose)
2983 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002984 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002985 }
2986
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002987 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04002988
2989 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2990 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho1734e172017-10-27 15:30:27 +03002991 unsigned int remainingElements = linkedUniform.elementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002992 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04002993}
2994
Jamie Madill54164b02017-08-28 15:17:37 -04002995// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
2996// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002997template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04002998void Program::getUniformInternal(const Context *context,
2999 DestT *dataOut,
3000 GLint location,
3001 GLenum nativeType,
3002 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003003{
Jamie Madill54164b02017-08-28 15:17:37 -04003004 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003005 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003006 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003007 {
3008 GLint tempValue[16] = {0};
3009 mProgram->getUniformiv(context, location, tempValue);
3010 UniformStateQueryCastLoop<GLboolean>(
3011 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003012 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003013 }
3014 case GL_INT:
3015 {
3016 GLint tempValue[16] = {0};
3017 mProgram->getUniformiv(context, location, tempValue);
3018 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3019 components);
3020 break;
3021 }
3022 case GL_UNSIGNED_INT:
3023 {
3024 GLuint tempValue[16] = {0};
3025 mProgram->getUniformuiv(context, location, tempValue);
3026 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3027 components);
3028 break;
3029 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003030 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003031 {
3032 GLfloat tempValue[16] = {0};
3033 mProgram->getUniformfv(context, location, tempValue);
3034 UniformStateQueryCastLoop<GLfloat>(
3035 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003036 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003037 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003038 default:
3039 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003040 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003041 }
3042}
Jamie Madilla4595b82017-01-11 17:36:34 -05003043
3044bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3045{
3046 // Must be called after samplers are validated.
3047 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3048
3049 for (const auto &binding : mState.mSamplerBindings)
3050 {
3051 GLenum textureType = binding.textureType;
3052 for (const auto &unit : binding.boundTextureUnits)
3053 {
3054 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3055 if (programTextureID == textureID)
3056 {
3057 // TODO(jmadill): Check for appropriate overlap.
3058 return true;
3059 }
3060 }
3061 }
3062
3063 return false;
3064}
3065
Jamie Madilla2c74982016-12-12 11:20:42 -05003066} // namespace gl