blob: 7364f80c5f9d4a4993a3720e58b28b2afeac8e87 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill20e005b2017-04-07 14:19:22 -040014#include "common/bitset_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
Olli Etuahod2551232017-10-26 20:03:33 +030017#include "common/string_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "common/utilities.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021#include "libANGLE/MemoryProgramCache.h"
Jamie Madill7af0de52017-11-06 17:09:33 -050022#include "libANGLE/ProgramLinkedResources.h"
Jamie Madill437d2662014-12-05 14:23:35 -050023#include "libANGLE/ResourceManager.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040024#include "libANGLE/Uniform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040025#include "libANGLE/VaryingPacking.h"
26#include "libANGLE/features.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040027#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040028#include "libANGLE/queryconversions.h"
29#include "libANGLE/renderer/GLImplFactory.h"
30#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040031#include "platform/Platform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050032
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033namespace gl
34{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000035
Geoff Lang7dd2e102014-11-10 15:19:26 -050036namespace
37{
38
Jamie Madill62d31cb2015-09-11 13:25:51 -040039// This simplified cast function doesn't need to worry about advanced concepts like
40// depth range values, or casting to bool.
41template <typename DestT, typename SrcT>
42DestT UniformStateQueryCast(SrcT value);
43
44// From-Float-To-Integer Casts
45template <>
46GLint UniformStateQueryCast(GLfloat value)
47{
48 return clampCast<GLint>(roundf(value));
49}
50
51template <>
52GLuint UniformStateQueryCast(GLfloat value)
53{
54 return clampCast<GLuint>(roundf(value));
55}
56
57// From-Integer-to-Integer Casts
58template <>
59GLint UniformStateQueryCast(GLuint value)
60{
61 return clampCast<GLint>(value);
62}
63
64template <>
65GLuint UniformStateQueryCast(GLint value)
66{
67 return clampCast<GLuint>(value);
68}
69
70// From-Boolean-to-Anything Casts
71template <>
72GLfloat UniformStateQueryCast(GLboolean value)
73{
Geoff Lang92019432017-11-20 13:09:34 -050074 return (ConvertToBool(value) ? 1.0f : 0.0f);
Jamie Madill62d31cb2015-09-11 13:25:51 -040075}
76
77template <>
78GLint UniformStateQueryCast(GLboolean value)
79{
Geoff Lang92019432017-11-20 13:09:34 -050080 return (ConvertToBool(value) ? 1 : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -040081}
82
83template <>
84GLuint UniformStateQueryCast(GLboolean value)
85{
Geoff Lang92019432017-11-20 13:09:34 -050086 return (ConvertToBool(value) ? 1u : 0u);
Jamie Madill62d31cb2015-09-11 13:25:51 -040087}
88
89// Default to static_cast
90template <typename DestT, typename SrcT>
91DestT UniformStateQueryCast(SrcT value)
92{
93 return static_cast<DestT>(value);
94}
95
96template <typename SrcT, typename DestT>
97void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
98{
99 for (int comp = 0; comp < components; ++comp)
100 {
101 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
102 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
103 size_t offset = comp * 4;
104 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
105 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
106 }
107}
108
jchen1015015f72017-03-16 13:54:21 +0800109template <typename VarT>
110GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
111{
Olli Etuahod2551232017-10-26 20:03:33 +0300112 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800113 for (size_t index = 0; index < list.size(); index++)
114 {
115 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300116 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800117 {
Olli Etuahod2551232017-10-26 20:03:33 +0300118 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800119 }
120 }
121
122 return GL_INVALID_INDEX;
123}
124
Olli Etuahod2551232017-10-26 20:03:33 +0300125template <typename VarT>
126GLint GetVariableLocation(const std::vector<VarT> &list,
127 const std::vector<VariableLocation> &locationList,
128 const std::string &name)
129{
130 size_t nameLengthWithoutArrayIndex;
131 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
132
133 for (size_t location = 0u; location < locationList.size(); ++location)
134 {
135 const VariableLocation &variableLocation = locationList[location];
136 if (!variableLocation.used())
137 {
138 continue;
139 }
140
141 const VarT &variable = list[variableLocation.index];
142
143 if (angle::BeginsWith(variable.name, name))
144 {
145 if (name.length() == variable.name.length())
146 {
147 ASSERT(name == variable.name);
148 // GLES 3.1 November 2016 page 87.
149 // The string exactly matches the name of the active variable.
150 return static_cast<GLint>(location);
151 }
152 if (name.length() + 3u == variable.name.length() && variable.isArray())
153 {
154 ASSERT(name + "[0]" == variable.name);
155 // The string identifies the base name of an active array, where the string would
156 // exactly match the name of the variable if the suffix "[0]" were appended to the
157 // string.
158 return static_cast<GLint>(location);
159 }
160 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300161 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300162 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
163 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
164 {
165 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
166 // The string identifies an active element of the array, where the string ends with the
167 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
168 // zeroes, or whitespace) identifying an array element, and the "]" character, the
169 // integer is less than the number of active elements of the array variable, and where
170 // the string would exactly match the enumerated name of the array if the decimal
171 // integer were replaced with zero.
172 return static_cast<GLint>(location);
173 }
174 }
175
176 return -1;
177}
178
jchen10fd7c3b52017-03-21 15:36:03 +0800179void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
180{
181 ASSERT(bufSize > 0);
182 strncpy(buffer, string.c_str(), bufSize);
183 buffer[bufSize - 1] = '\0';
184
185 if (length)
186 {
187 *length = static_cast<GLsizei>(strlen(buffer));
188 }
189}
190
jchen10a9042d32017-03-17 08:50:45 +0800191bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
192{
Olli Etuahoc8538042017-09-27 11:20:15 +0300193 std::vector<unsigned int> subscripts;
194 std::string baseName = ParseResourceName(name, &subscripts);
195 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800196 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300197 std::vector<unsigned int> arrayIndices;
198 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
199 if (baseName == arrayName &&
200 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800201 {
202 return true;
203 }
204 }
205 return false;
206}
207
Jiajia Qin729b2c62017-08-14 09:36:11 +0800208bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
209 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
210 const std::string &errorMessage,
211 InfoLog &infoLog)
212{
213 GLuint blockCount = 0;
214 for (const sh::InterfaceBlock &block : interfaceBlocks)
215 {
216 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
217 {
218 blockCount += (block.arraySize ? block.arraySize : 1);
219 if (blockCount > maxInterfaceBlocks)
220 {
221 infoLog << errorMessage << maxInterfaceBlocks << ")";
222 return false;
223 }
224 }
225 }
226 return true;
227}
228
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800229GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
230{
231 std::vector<unsigned int> subscripts;
232 std::string baseName = ParseResourceName(name, &subscripts);
233
234 unsigned int numBlocks = static_cast<unsigned int>(list.size());
235 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
236 {
237 const auto &block = list[blockIndex];
238 if (block.name == baseName)
239 {
240 const bool arrayElementZero =
241 (subscripts.empty() && (!block.isArray || block.arrayElement == 0));
242 const bool arrayElementMatches =
243 (subscripts.size() == 1 && subscripts[0] == block.arrayElement);
244 if (arrayElementMatches || arrayElementZero)
245 {
246 return blockIndex;
247 }
248 }
249 }
250
251 return GL_INVALID_INDEX;
252}
253
254void GetInterfaceBlockName(const GLuint index,
255 const std::vector<InterfaceBlock> &list,
256 GLsizei bufSize,
257 GLsizei *length,
258 GLchar *name)
259{
260 ASSERT(index < list.size());
261
262 const auto &block = list[index];
263
264 if (bufSize > 0)
265 {
266 std::string blockName = block.name;
267
268 if (block.isArray)
269 {
270 blockName += ArrayString(block.arrayElement);
271 }
272 CopyStringToBuffer(name, blockName, bufSize, length);
273 }
274}
275
Jamie Madillc9727f32017-11-07 12:37:07 -0500276void InitUniformBlockLinker(const gl::Context *context,
277 const ProgramState &state,
278 UniformBlockLinker *blockLinker)
279{
280 if (state.getAttachedVertexShader())
281 {
282 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
283 &state.getAttachedVertexShader()->getUniformBlocks(context));
284 }
285
286 if (state.getAttachedFragmentShader())
287 {
288 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
289 &state.getAttachedFragmentShader()->getUniformBlocks(context));
290 }
291
292 if (state.getAttachedComputeShader())
293 {
294 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
295 &state.getAttachedComputeShader()->getUniformBlocks(context));
296 }
297}
298
299void InitShaderStorageBlockLinker(const gl::Context *context,
300 const ProgramState &state,
301 ShaderStorageBlockLinker *blockLinker)
302{
303 if (state.getAttachedVertexShader())
304 {
305 blockLinker->addShaderBlocks(
306 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
307 }
308
309 if (state.getAttachedFragmentShader())
310 {
311 blockLinker->addShaderBlocks(
312 GL_FRAGMENT_SHADER,
313 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
314 }
315
316 if (state.getAttachedComputeShader())
317 {
318 blockLinker->addShaderBlocks(
319 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
320 }
321}
322
Jamie Madill62d31cb2015-09-11 13:25:51 -0400323} // anonymous namespace
324
Jamie Madill4a3c2342015-10-08 12:58:45 -0400325const char *const g_fakepath = "C:\\fakepath";
326
Jamie Madill3c1da042017-11-27 18:33:40 -0500327// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400328InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000329{
330}
331
332InfoLog::~InfoLog()
333{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000334}
335
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400336size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000337{
Jamie Madill23176ce2017-07-31 14:14:33 -0400338 if (!mLazyStream)
339 {
340 return 0;
341 }
342
343 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400344 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000345}
346
Geoff Lange1a27752015-10-05 13:16:04 -0400347void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000348{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400349 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000350
351 if (bufSize > 0)
352 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400353 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400354
Jamie Madill23176ce2017-07-31 14:14:33 -0400355 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400357 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
358 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000359 }
360
361 infoLog[index] = '\0';
362 }
363
364 if (length)
365 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400366 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000367 }
368}
369
370// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300371// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000372// messages, so lets remove all occurrences of this fake file path from the log.
373void InfoLog::appendSanitized(const char *message)
374{
Jamie Madill23176ce2017-07-31 14:14:33 -0400375 ensureInitialized();
376
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000377 std::string msg(message);
378
379 size_t found;
380 do
381 {
382 found = msg.find(g_fakepath);
383 if (found != std::string::npos)
384 {
385 msg.erase(found, strlen(g_fakepath));
386 }
387 }
388 while (found != std::string::npos);
389
Jamie Madill23176ce2017-07-31 14:14:33 -0400390 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000391}
392
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000393void InfoLog::reset()
394{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000395}
396
Jamie Madill3c1da042017-11-27 18:33:40 -0500397// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300398VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000399{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500400}
401
Olli Etuahoc8538042017-09-27 11:20:15 +0300402VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300403 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500404{
Olli Etuahoc8538042017-09-27 11:20:15 +0300405 ASSERT(arrayIndex != GL_INVALID_INDEX);
406}
407
Jamie Madill3c1da042017-11-27 18:33:40 -0500408// SamplerBindings implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500409SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced)
410 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
411{
412}
413
414SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
415
416SamplerBinding::~SamplerBinding() = default;
417
Jamie Madill3c1da042017-11-27 18:33:40 -0500418// ProgramBindings implementation.
419ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500420{
421}
422
Jamie Madill3c1da042017-11-27 18:33:40 -0500423ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500424{
425}
426
Jamie Madill3c1da042017-11-27 18:33:40 -0500427void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400428{
429 mBindings[name] = index;
430}
431
Jamie Madill3c1da042017-11-27 18:33:40 -0500432int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400433{
434 auto iter = mBindings.find(name);
435 return (iter != mBindings.end()) ? iter->second : -1;
436}
437
Jamie Madill3c1da042017-11-27 18:33:40 -0500438ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400439{
440 return mBindings.begin();
441}
442
Jamie Madill3c1da042017-11-27 18:33:40 -0500443ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400444{
445 return mBindings.end();
446}
447
Jamie Madill3c1da042017-11-27 18:33:40 -0500448// ImageBinding implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500449ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
450{
451}
452ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
453{
454 for (size_t index = 0; index < count; ++index)
455 {
456 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
457 }
458}
459
460ImageBinding::ImageBinding(const ImageBinding &other) = default;
461
462ImageBinding::~ImageBinding() = default;
463
Jamie Madill3c1da042017-11-27 18:33:40 -0500464// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400465ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500466 : mLabel(),
467 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400468 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300469 mAttachedComputeShader(nullptr),
Jiawei Shao89be29a2017-11-06 14:36:45 +0800470 mAttachedGeometryShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500471 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400472 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500473 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800474 mImageUniformRange(0, 0),
475 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300476 mBinaryRetrieveableHint(false),
477 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400478{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300479 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400480}
481
Jamie Madill48ef11b2016-04-27 15:21:52 -0400482ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400483{
Jiawei Shao89be29a2017-11-06 14:36:45 +0800484 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader &&
485 !mAttachedGeometryShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400486}
487
Jamie Madill48ef11b2016-04-27 15:21:52 -0400488const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500489{
490 return mLabel;
491}
492
Jamie Madille7d84322017-01-10 18:21:59 -0500493GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400494{
jchen1015015f72017-03-16 13:54:21 +0800495 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400496}
497
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800498GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
499{
500 return GetResourceIndexFromName(mBufferVariables, name);
501}
502
Jamie Madille7d84322017-01-10 18:21:59 -0500503GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
504{
505 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
506 return mUniformLocations[location].index;
507}
508
509Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
510{
511 GLuint index = getUniformIndexFromLocation(location);
512 if (!isSamplerUniformIndex(index))
513 {
514 return Optional<GLuint>::Invalid();
515 }
516
517 return getSamplerIndexFromUniformIndex(index);
518}
519
520bool ProgramState::isSamplerUniformIndex(GLuint index) const
521{
Jamie Madill982f6e02017-06-07 14:33:04 -0400522 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500523}
524
525GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
526{
527 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400528 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500529}
530
Jamie Madill34ca4f52017-06-13 11:49:39 -0400531GLuint ProgramState::getAttributeLocation(const std::string &name) const
532{
533 for (const sh::Attribute &attribute : mAttributes)
534 {
535 if (attribute.name == name)
536 {
537 return attribute.location;
538 }
539 }
540
541 return static_cast<GLuint>(-1);
542}
543
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500544Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400545 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400546 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500547 mLinked(false),
548 mDeleteStatus(false),
549 mRefCount(0),
550 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500551 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500552{
553 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000554
Geoff Lang7dd2e102014-11-10 15:19:26 -0500555 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000556}
557
558Program::~Program()
559{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400560 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000561}
562
Jamie Madill4928b7c2017-06-20 12:57:39 -0400563void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500564{
565 if (mState.mAttachedVertexShader != nullptr)
566 {
567 mState.mAttachedVertexShader->release(context);
568 mState.mAttachedVertexShader = nullptr;
569 }
570
571 if (mState.mAttachedFragmentShader != nullptr)
572 {
573 mState.mAttachedFragmentShader->release(context);
574 mState.mAttachedFragmentShader = nullptr;
575 }
576
577 if (mState.mAttachedComputeShader != nullptr)
578 {
579 mState.mAttachedComputeShader->release(context);
580 mState.mAttachedComputeShader = nullptr;
581 }
582
Jiawei Shao89be29a2017-11-06 14:36:45 +0800583 if (mState.mAttachedGeometryShader != nullptr)
584 {
585 mState.mAttachedGeometryShader->release(context);
586 mState.mAttachedGeometryShader = nullptr;
587 }
588
Jamie Madillc564c072017-06-01 12:45:42 -0400589 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400590
591 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800592 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400593 SafeDelete(mProgram);
594
595 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500596}
597
Geoff Lang70d0f492015-12-10 17:45:46 -0500598void Program::setLabel(const std::string &label)
599{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400600 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500601}
602
603const std::string &Program::getLabel() const
604{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400605 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500606}
607
Jamie Madillef300b12016-10-07 15:12:09 -0400608void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000609{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300610 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300612 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000613 {
Jamie Madillef300b12016-10-07 15:12:09 -0400614 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300615 mState.mAttachedVertexShader = shader;
616 mState.mAttachedVertexShader->addRef();
617 break;
618 }
619 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620 {
Jamie Madillef300b12016-10-07 15:12:09 -0400621 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300622 mState.mAttachedFragmentShader = shader;
623 mState.mAttachedFragmentShader->addRef();
624 break;
625 }
626 case GL_COMPUTE_SHADER:
627 {
Jamie Madillef300b12016-10-07 15:12:09 -0400628 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300629 mState.mAttachedComputeShader = shader;
630 mState.mAttachedComputeShader->addRef();
631 break;
632 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800633 case GL_GEOMETRY_SHADER_EXT:
634 {
635 ASSERT(!mState.mAttachedGeometryShader);
636 mState.mAttachedGeometryShader = shader;
637 mState.mAttachedGeometryShader->addRef();
638 break;
639 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300640 default:
641 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643}
644
Jamie Madillc1d770e2017-04-13 17:31:24 -0400645void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300647 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000648 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300649 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400651 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500652 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300653 mState.mAttachedVertexShader = nullptr;
654 break;
655 }
656 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000657 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400658 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500659 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300660 mState.mAttachedFragmentShader = nullptr;
661 break;
662 }
663 case GL_COMPUTE_SHADER:
664 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400665 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500666 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300667 mState.mAttachedComputeShader = nullptr;
668 break;
669 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800670 case GL_GEOMETRY_SHADER_EXT:
671 {
672 ASSERT(mState.mAttachedGeometryShader == shader);
673 shader->release(context);
674 mState.mAttachedGeometryShader = nullptr;
675 break;
676 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300677 default:
678 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680}
681
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000682int Program::getAttachedShadersCount() const
683{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300684 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800685 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000686}
687
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688void Program::bindAttributeLocation(GLuint index, const char *name)
689{
Geoff Langd8605522016-04-13 10:19:12 -0400690 mAttributeBindings.bindLocation(index, name);
691}
692
693void Program::bindUniformLocation(GLuint index, const char *name)
694{
Olli Etuahod2551232017-10-26 20:03:33 +0300695 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000696}
697
Sami Väisänen46eaa942016-06-29 10:26:37 +0300698void Program::bindFragmentInputLocation(GLint index, const char *name)
699{
700 mFragmentInputBindings.bindLocation(index, name);
701}
702
Jamie Madillbd044ed2017-06-05 12:59:21 -0400703BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300704{
705 BindingInfo ret;
706 ret.type = GL_NONE;
707 ret.valid = false;
708
Jamie Madillbd044ed2017-06-05 12:59:21 -0400709 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300710 ASSERT(fragmentShader);
711
712 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800713 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300714
715 for (const auto &binding : mFragmentInputBindings)
716 {
717 if (binding.second != static_cast<GLuint>(index))
718 continue;
719
720 ret.valid = true;
721
Olli Etuahod2551232017-10-26 20:03:33 +0300722 size_t nameLengthWithoutArrayIndex;
723 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300724
725 for (const auto &in : inputs)
726 {
Olli Etuahod2551232017-10-26 20:03:33 +0300727 if (in.name.length() == nameLengthWithoutArrayIndex &&
728 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300729 {
730 if (in.isArray())
731 {
732 // The client wants to bind either "name" or "name[0]".
733 // GL ES 3.1 spec refers to active array names with language such as:
734 // "if the string identifies the base name of an active array, where the
735 // string would exactly match the name of the variable if the suffix "[0]"
736 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400737 if (arrayIndex == GL_INVALID_INDEX)
738 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300739
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400740 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300741 }
742 else
743 {
744 ret.name = in.mappedName;
745 }
746 ret.type = in.type;
747 return ret;
748 }
749 }
750 }
751
752 return ret;
753}
754
Jamie Madillbd044ed2017-06-05 12:59:21 -0400755void Program::pathFragmentInputGen(const Context *context,
756 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300757 GLenum genMode,
758 GLint components,
759 const GLfloat *coeffs)
760{
761 // If the location is -1 then the command is silently ignored
762 if (index == -1)
763 return;
764
Jamie Madillbd044ed2017-06-05 12:59:21 -0400765 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300766
767 // If the input doesn't exist then then the command is silently ignored
768 // This could happen through optimization for example, the shader translator
769 // decides that a variable is not actually being used and optimizes it away.
770 if (binding.name.empty())
771 return;
772
773 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
774}
775
Martin Radev4c4c8e72016-08-04 12:25:34 +0300776// The attached shaders are checked for linking errors by matching up their variables.
777// Uniform, input and output variables get collected.
778// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500779Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000780{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500781 const auto &data = context->getContextState();
782
Jamie Madill6c58b062017-08-01 13:44:25 -0400783 auto *platform = ANGLEPlatformCurrent();
784 double startTime = platform->currentTime(platform);
785
Jamie Madill6c1f6712017-02-14 19:08:04 -0500786 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000787
Jamie Madill32447362017-06-28 14:53:52 -0400788 ProgramHash programHash;
789 auto *cache = context->getMemoryProgramCache();
790 if (cache)
791 {
792 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400793 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400794 }
795
796 if (mLinked)
797 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400798 double delta = platform->currentTime(platform) - startTime;
799 int us = static_cast<int>(delta * 1000000.0);
800 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400801 return NoError();
802 }
803
804 // Cache load failed, fall through to normal linking.
805 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000806 mInfoLog.reset();
807
Martin Radev4c4c8e72016-08-04 12:25:34 +0300808 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500809
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500810 Shader *vertexShader = mState.mAttachedVertexShader;
811 Shader *fragmentShader = mState.mAttachedFragmentShader;
812 Shader *computeShader = mState.mAttachedComputeShader;
Jamie Madill192745a2016-12-22 15:58:21 -0500813
814 bool isComputeShaderAttached = (computeShader != nullptr);
815 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300816 // Check whether we both have a compute and non-compute shaders attached.
817 // If there are of both types attached, then linking should fail.
818 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
819 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500820 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300821 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
822 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400823 }
824
Jamie Madill192745a2016-12-22 15:58:21 -0500825 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500826 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400827 if (!computeShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300828 {
829 mInfoLog << "Attached compute shader is not compiled.";
830 return NoError();
831 }
Jamie Madill192745a2016-12-22 15:58:21 -0500832 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300833
Jamie Madillbd044ed2017-06-05 12:59:21 -0400834 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300835
836 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
837 // If the work group size is not specified, a link time error should occur.
838 if (!mState.mComputeShaderLocalSize.isDeclared())
839 {
840 mInfoLog << "Work group size is not specified.";
841 return NoError();
842 }
843
Jamie Madillbd044ed2017-06-05 12:59:21 -0400844 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300845 {
846 return NoError();
847 }
848
Jiajia Qin729b2c62017-08-14 09:36:11 +0800849 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300850 {
851 return NoError();
852 }
853
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800854 ProgramLinkedResources resources = {
855 {0, PackMode::ANGLE_RELAXED},
856 {&mState.mUniformBlocks, &mState.mUniforms},
857 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500858
859 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
860 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
861
862 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500863 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300864 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500865 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300866 }
867 }
868 else
869 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400870 if (!fragmentShader || !fragmentShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300871 {
872 return NoError();
873 }
Jamie Madill192745a2016-12-22 15:58:21 -0500874 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300875
Jamie Madillbd044ed2017-06-05 12:59:21 -0400876 if (!vertexShader || !vertexShader->isCompiled(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300877 {
878 return NoError();
879 }
Jamie Madill192745a2016-12-22 15:58:21 -0500880 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300881
Jamie Madillbd044ed2017-06-05 12:59:21 -0400882 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300883 {
884 mInfoLog << "Fragment shader version does not match vertex shader version.";
885 return NoError();
886 }
887
Jamie Madillbd044ed2017-06-05 12:59:21 -0400888 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300889 {
890 return NoError();
891 }
892
Jamie Madillbd044ed2017-06-05 12:59:21 -0400893 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300894 {
895 return NoError();
896 }
897
Jamie Madillbd044ed2017-06-05 12:59:21 -0400898 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300899 {
900 return NoError();
901 }
902
Jiajia Qin729b2c62017-08-14 09:36:11 +0800903 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300904 {
905 return NoError();
906 }
907
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400908 if (!linkValidateGlobalNames(context, mInfoLog))
909 {
910 return NoError();
911 }
912
Jamie Madillbd044ed2017-06-05 12:59:21 -0400913 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300914
Martin Radev7cf61662017-07-26 17:10:53 +0300915 mState.mNumViews = vertexShader->getNumViews(context);
916
Jamie Madillbd044ed2017-06-05 12:59:21 -0400917 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300918
Jamie Madill192745a2016-12-22 15:58:21 -0500919 // Map the varyings to the register file
920 // In WebGL, we use a slightly different handling for packing variables.
921 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
922 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500923
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800924 ProgramLinkedResources resources = {
925 {data.getCaps().maxVaryingVectors, packMode},
926 {&mState.mUniformBlocks, &mState.mUniforms},
927 {&mState.mShaderStorageBlocks, &mState.mBufferVariables}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500928
929 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
930 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
931
jchen1085c93c42017-11-12 15:36:47 +0800932 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps))
Jamie Madill192745a2016-12-22 15:58:21 -0500933 {
934 return NoError();
935 }
936
jchen1085c93c42017-11-12 15:36:47 +0800937 if (!resources.varyingPacking.collectAndPackUserVaryings(
938 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +0300939 {
940 return NoError();
941 }
942
Jamie Madillc9727f32017-11-07 12:37:07 -0500943 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500944 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300945 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500946 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300947 }
948
949 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500950 }
951
jchen10eaef1e52017-06-13 10:44:11 +0800952 gatherAtomicCounterBuffers();
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500953 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400954
jchen10eaef1e52017-06-13 10:44:11 +0800955 setUniformValuesFromBindingQualifiers();
956
Yunchao He85072e82017-11-14 15:43:28 +0800957 ASSERT(mLinked);
958 updateLinkedShaderStages();
959
Jamie Madill54164b02017-08-28 15:17:37 -0400960 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400961 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400962
Jamie Madill32447362017-06-28 14:53:52 -0400963 // Save to the program cache.
964 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
965 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
966 {
967 cache->putProgram(programHash, context, this);
968 }
969
Jamie Madill6c58b062017-08-01 13:44:25 -0400970 double delta = platform->currentTime(platform) - startTime;
971 int us = static_cast<int>(delta * 1000000.0);
972 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
973
Martin Radev4c4c8e72016-08-04 12:25:34 +0300974 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000975}
976
Yunchao He85072e82017-11-14 15:43:28 +0800977void Program::updateLinkedShaderStages()
978{
979 if (mState.mAttachedVertexShader)
980 {
981 mState.mLinkedShaderStages.set(SHADER_VERTEX);
982 }
983
984 if (mState.mAttachedFragmentShader)
985 {
986 mState.mLinkedShaderStages.set(SHADER_FRAGMENT);
987 }
988
989 if (mState.mAttachedComputeShader)
990 {
991 mState.mLinkedShaderStages.set(SHADER_COMPUTE);
992 }
993}
994
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000995// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500996void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400998 mState.mAttributes.clear();
999 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001000 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001001 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001002 mState.mUniforms.clear();
1003 mState.mUniformLocations.clear();
1004 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001005 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001006 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001007 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001008 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001009 mState.mOutputVariableTypes.clear();
Corentin Walleze7557742017-06-01 13:09:57 -04001010 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001011 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001012 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001013 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001014 mState.mNumViews = -1;
Yunchao He85072e82017-11-14 15:43:28 +08001015 mState.mLinkedShaderStages.reset();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001016
Geoff Lang7dd2e102014-11-10 15:19:26 -05001017 mValidated = false;
1018
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001019 mLinked = false;
1020}
1021
Geoff Lange1a27752015-10-05 13:16:04 -04001022bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001023{
1024 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025}
1026
Jamie Madilla2c74982016-12-12 11:20:42 -05001027Error Program::loadBinary(const Context *context,
1028 GLenum binaryFormat,
1029 const void *binary,
1030 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001031{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001032 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001033
Geoff Lang7dd2e102014-11-10 15:19:26 -05001034#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001035 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001036#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001037 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1038 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001039 {
Jamie Madillf6113162015-05-07 11:49:21 -04001040 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001041 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042 }
1043
Jamie Madill4f86d052017-06-05 12:59:26 -04001044 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1045 ANGLE_TRY_RESULT(
1046 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001047
1048 // Currently we require the full shader text to compute the program hash.
1049 // TODO(jmadill): Store the binary in the internal program cache.
1050
Jamie Madillb0a838b2016-11-13 20:02:12 -05001051 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001052#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001053}
1054
Jamie Madilla2c74982016-12-12 11:20:42 -05001055Error Program::saveBinary(const Context *context,
1056 GLenum *binaryFormat,
1057 void *binary,
1058 GLsizei bufSize,
1059 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001060{
1061 if (binaryFormat)
1062 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001063 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001064 }
1065
Jamie Madill4f86d052017-06-05 12:59:26 -04001066 angle::MemoryBuffer memoryBuf;
1067 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001068
Jamie Madill4f86d052017-06-05 12:59:26 -04001069 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1070 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001071
1072 if (streamLength > bufSize)
1073 {
1074 if (length)
1075 {
1076 *length = 0;
1077 }
1078
1079 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1080 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1081 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001082 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001083 }
1084
1085 if (binary)
1086 {
1087 char *ptr = reinterpret_cast<char*>(binary);
1088
Jamie Madill48ef11b2016-04-27 15:21:52 -04001089 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001090 ptr += streamLength;
1091
1092 ASSERT(ptr - streamLength == binary);
1093 }
1094
1095 if (length)
1096 {
1097 *length = streamLength;
1098 }
1099
He Yunchaoacd18982017-01-04 10:46:42 +08001100 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001101}
1102
Jamie Madillffe00c02017-06-27 16:26:55 -04001103GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001104{
1105 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001106 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001107 if (error.isError())
1108 {
1109 return 0;
1110 }
1111
1112 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001113}
1114
Geoff Langc5629752015-12-07 16:29:04 -05001115void Program::setBinaryRetrievableHint(bool retrievable)
1116{
1117 // TODO(jmadill) : replace with dirty bits
1118 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001119 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001120}
1121
1122bool Program::getBinaryRetrievableHint() const
1123{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001124 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001125}
1126
Yunchao He61afff12017-03-14 15:34:03 +08001127void Program::setSeparable(bool separable)
1128{
1129 // TODO(yunchao) : replace with dirty bits
1130 if (mState.mSeparable != separable)
1131 {
1132 mProgram->setSeparable(separable);
1133 mState.mSeparable = separable;
1134 }
1135}
1136
1137bool Program::isSeparable() const
1138{
1139 return mState.mSeparable;
1140}
1141
Jamie Madill6c1f6712017-02-14 19:08:04 -05001142void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001143{
1144 mRefCount--;
1145
1146 if (mRefCount == 0 && mDeleteStatus)
1147 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001148 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001149 }
1150}
1151
1152void Program::addRef()
1153{
1154 mRefCount++;
1155}
1156
1157unsigned int Program::getRefCount() const
1158{
1159 return mRefCount;
1160}
1161
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001162int Program::getInfoLogLength() const
1163{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001164 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001165}
1166
Geoff Lange1a27752015-10-05 13:16:04 -04001167void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001168{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001169 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001170}
1171
Geoff Lange1a27752015-10-05 13:16:04 -04001172void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001173{
1174 int total = 0;
1175
Martin Radev4c4c8e72016-08-04 12:25:34 +03001176 if (mState.mAttachedComputeShader)
1177 {
1178 if (total < maxCount)
1179 {
1180 shaders[total] = mState.mAttachedComputeShader->getHandle();
1181 total++;
1182 }
1183 }
1184
Jamie Madill48ef11b2016-04-27 15:21:52 -04001185 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001186 {
1187 if (total < maxCount)
1188 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001189 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001190 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001191 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001192 }
1193
Jamie Madill48ef11b2016-04-27 15:21:52 -04001194 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001195 {
1196 if (total < maxCount)
1197 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001198 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001199 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001200 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001201 }
1202
Jiawei Shao89be29a2017-11-06 14:36:45 +08001203 if (mState.mAttachedGeometryShader)
1204 {
1205 if (total < maxCount)
1206 {
1207 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1208 total++;
1209 }
1210 }
1211
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001212 if (count)
1213 {
1214 *count = total;
1215 }
1216}
1217
Geoff Lange1a27752015-10-05 13:16:04 -04001218GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001219{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001220 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001221}
1222
Jamie Madill63805b42015-08-25 13:17:39 -04001223bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001224{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001225 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1226 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001227}
1228
jchen10fd7c3b52017-03-21 15:36:03 +08001229void Program::getActiveAttribute(GLuint index,
1230 GLsizei bufsize,
1231 GLsizei *length,
1232 GLint *size,
1233 GLenum *type,
1234 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001235{
Jamie Madillc349ec02015-08-21 16:53:12 -04001236 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001237 {
1238 if (bufsize > 0)
1239 {
1240 name[0] = '\0';
1241 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001242
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001243 if (length)
1244 {
1245 *length = 0;
1246 }
1247
1248 *type = GL_NONE;
1249 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001250 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001251 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001252
jchen1036e120e2017-03-14 14:53:58 +08001253 ASSERT(index < mState.mAttributes.size());
1254 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001255
1256 if (bufsize > 0)
1257 {
jchen10fd7c3b52017-03-21 15:36:03 +08001258 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001259 }
1260
1261 // Always a single 'type' instance
1262 *size = 1;
1263 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001264}
1265
Geoff Lange1a27752015-10-05 13:16:04 -04001266GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001267{
Jamie Madillc349ec02015-08-21 16:53:12 -04001268 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001269 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001270 return 0;
1271 }
1272
jchen1036e120e2017-03-14 14:53:58 +08001273 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001274}
1275
Geoff Lange1a27752015-10-05 13:16:04 -04001276GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001277{
Jamie Madillc349ec02015-08-21 16:53:12 -04001278 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001279 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001280 return 0;
1281 }
1282
1283 size_t maxLength = 0;
1284
Jamie Madill48ef11b2016-04-27 15:21:52 -04001285 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001286 {
jchen1036e120e2017-03-14 14:53:58 +08001287 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001288 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289
Jamie Madillc349ec02015-08-21 16:53:12 -04001290 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001291}
1292
jchen1015015f72017-03-16 13:54:21 +08001293GLuint Program::getInputResourceIndex(const GLchar *name) const
1294{
Olli Etuahod2551232017-10-26 20:03:33 +03001295 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001296}
1297
1298GLuint Program::getOutputResourceIndex(const GLchar *name) const
1299{
1300 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1301}
1302
jchen10fd7c3b52017-03-21 15:36:03 +08001303size_t Program::getOutputResourceCount() const
1304{
1305 return (mLinked ? mState.mOutputVariables.size() : 0);
1306}
1307
jchen10baf5d942017-08-28 20:45:48 +08001308template <typename T>
1309void Program::getResourceName(GLuint index,
1310 const std::vector<T> &resources,
1311 GLsizei bufSize,
1312 GLsizei *length,
1313 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001314{
1315 if (length)
1316 {
1317 *length = 0;
1318 }
1319
1320 if (!mLinked)
1321 {
1322 if (bufSize > 0)
1323 {
1324 name[0] = '\0';
1325 }
1326 return;
1327 }
jchen10baf5d942017-08-28 20:45:48 +08001328 ASSERT(index < resources.size());
1329 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001330
1331 if (bufSize > 0)
1332 {
Olli Etuahod2551232017-10-26 20:03:33 +03001333 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001334 }
1335}
1336
jchen10baf5d942017-08-28 20:45:48 +08001337void Program::getInputResourceName(GLuint index,
1338 GLsizei bufSize,
1339 GLsizei *length,
1340 GLchar *name) const
1341{
1342 getResourceName(index, mState.mAttributes, bufSize, length, name);
1343}
1344
1345void Program::getOutputResourceName(GLuint index,
1346 GLsizei bufSize,
1347 GLsizei *length,
1348 GLchar *name) const
1349{
1350 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1351}
1352
1353void Program::getUniformResourceName(GLuint index,
1354 GLsizei bufSize,
1355 GLsizei *length,
1356 GLchar *name) const
1357{
1358 getResourceName(index, mState.mUniforms, bufSize, length, name);
1359}
1360
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001361void Program::getBufferVariableResourceName(GLuint index,
1362 GLsizei bufSize,
1363 GLsizei *length,
1364 GLchar *name) const
1365{
1366 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1367}
1368
jchen10880683b2017-04-12 16:21:55 +08001369const sh::Attribute &Program::getInputResource(GLuint index) const
1370{
1371 ASSERT(index < mState.mAttributes.size());
1372 return mState.mAttributes[index];
1373}
1374
1375const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1376{
1377 ASSERT(index < mState.mOutputVariables.size());
1378 return mState.mOutputVariables[index];
1379}
1380
Geoff Lang7dd2e102014-11-10 15:19:26 -05001381GLint Program::getFragDataLocation(const std::string &name) const
1382{
Olli Etuahod2551232017-10-26 20:03:33 +03001383 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001384}
1385
Geoff Lange1a27752015-10-05 13:16:04 -04001386void Program::getActiveUniform(GLuint index,
1387 GLsizei bufsize,
1388 GLsizei *length,
1389 GLint *size,
1390 GLenum *type,
1391 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001392{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001394 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001395 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001396 ASSERT(index < mState.mUniforms.size());
1397 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398
1399 if (bufsize > 0)
1400 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001401 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001402 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001403 }
1404
Olli Etuaho465835d2017-09-26 13:34:10 +03001405 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001406 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001407 }
1408 else
1409 {
1410 if (bufsize > 0)
1411 {
1412 name[0] = '\0';
1413 }
1414
1415 if (length)
1416 {
1417 *length = 0;
1418 }
1419
1420 *size = 0;
1421 *type = GL_NONE;
1422 }
1423}
1424
Geoff Lange1a27752015-10-05 13:16:04 -04001425GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001426{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001427 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001428 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001429 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001430 }
1431 else
1432 {
1433 return 0;
1434 }
1435}
1436
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001437size_t Program::getActiveBufferVariableCount() const
1438{
1439 return mLinked ? mState.mBufferVariables.size() : 0;
1440}
1441
Geoff Lange1a27752015-10-05 13:16:04 -04001442GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001443{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001444 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001445
1446 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001447 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001448 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001449 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001450 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001451 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001452 size_t length = uniform.name.length() + 1u;
1453 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001454 {
1455 length += 3; // Counting in "[0]".
1456 }
1457 maxLength = std::max(length, maxLength);
1458 }
1459 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001460 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461
Jamie Madill62d31cb2015-09-11 13:25:51 -04001462 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001463}
1464
Geoff Lang7dd2e102014-11-10 15:19:26 -05001465bool Program::isValidUniformLocation(GLint location) const
1466{
Jamie Madille2e406c2016-06-02 13:04:10 -04001467 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001468 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001469 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001470}
1471
Jamie Madill62d31cb2015-09-11 13:25:51 -04001472const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001474 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001475 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001476}
1477
Jamie Madillac4e9c32017-01-13 14:07:12 -05001478const VariableLocation &Program::getUniformLocation(GLint location) const
1479{
1480 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1481 return mState.mUniformLocations[location];
1482}
1483
1484const std::vector<VariableLocation> &Program::getUniformLocations() const
1485{
1486 return mState.mUniformLocations;
1487}
1488
1489const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1490{
1491 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1492 return mState.mUniforms[index];
1493}
1494
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001495const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1496{
1497 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1498 return mState.mBufferVariables[index];
1499}
1500
Jamie Madill62d31cb2015-09-11 13:25:51 -04001501GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001502{
Olli Etuahod2551232017-10-26 20:03:33 +03001503 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504}
1505
Jamie Madill62d31cb2015-09-11 13:25:51 -04001506GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001507{
Jamie Madille7d84322017-01-10 18:21:59 -05001508 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1512{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001513 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1514 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001515 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001516}
1517
1518void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1519{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001520 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1521 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001522 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523}
1524
1525void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1526{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001527 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1528 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001529 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001530}
1531
1532void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1533{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001534 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1535 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001536 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001537}
1538
Jamie Madill81c2e252017-09-09 23:32:46 -04001539Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001540{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001541 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1542 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1543
Jamie Madill81c2e252017-09-09 23:32:46 -04001544 mProgram->setUniform1iv(location, clampedCount, v);
1545
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001546 if (mState.isSamplerUniformIndex(locationInfo.index))
1547 {
1548 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001549 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001550 }
1551
Jamie Madill81c2e252017-09-09 23:32:46 -04001552 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001553}
1554
1555void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1556{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001557 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1558 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001559 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001560}
1561
1562void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1563{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001564 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1565 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001566 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001567}
1568
1569void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1570{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001571 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1572 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001573 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001574}
1575
1576void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1577{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001578 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1579 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001580 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001581}
1582
1583void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1584{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001585 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1586 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001587 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001588}
1589
1590void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1591{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001592 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1593 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001594 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001595}
1596
1597void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1598{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001599 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1600 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001601 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001602}
1603
1604void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1605{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001606 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001607 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001608}
1609
1610void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1611{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001612 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001613 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001614}
1615
1616void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1617{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001618 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001619 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620}
1621
1622void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1623{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001624 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001625 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626}
1627
1628void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1629{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001630 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001631 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001632}
1633
1634void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1635{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001636 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001637 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638}
1639
1640void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1641{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001642 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001643 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001644}
1645
1646void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1647{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001648 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001649 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650}
1651
1652void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1653{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001654 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001655 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656}
1657
Jamie Madill54164b02017-08-28 15:17:37 -04001658void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001659{
Jamie Madill54164b02017-08-28 15:17:37 -04001660 const auto &uniformLocation = mState.getUniformLocations()[location];
1661 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1662
1663 GLenum nativeType = gl::VariableComponentType(uniform.type);
1664 if (nativeType == GL_FLOAT)
1665 {
1666 mProgram->getUniformfv(context, location, v);
1667 }
1668 else
1669 {
1670 getUniformInternal(context, v, location, nativeType,
1671 gl::VariableComponentCount(uniform.type));
1672 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001673}
1674
Jamie Madill54164b02017-08-28 15:17:37 -04001675void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001676{
Jamie Madill54164b02017-08-28 15:17:37 -04001677 const auto &uniformLocation = mState.getUniformLocations()[location];
1678 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1679
1680 GLenum nativeType = gl::VariableComponentType(uniform.type);
1681 if (nativeType == GL_INT || nativeType == GL_BOOL)
1682 {
1683 mProgram->getUniformiv(context, location, v);
1684 }
1685 else
1686 {
1687 getUniformInternal(context, v, location, nativeType,
1688 gl::VariableComponentCount(uniform.type));
1689 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001690}
1691
Jamie Madill54164b02017-08-28 15:17:37 -04001692void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693{
Jamie Madill54164b02017-08-28 15:17:37 -04001694 const auto &uniformLocation = mState.getUniformLocations()[location];
1695 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1696
1697 GLenum nativeType = gl::VariableComponentType(uniform.type);
1698 if (nativeType == GL_UNSIGNED_INT)
1699 {
1700 mProgram->getUniformuiv(context, location, v);
1701 }
1702 else
1703 {
1704 getUniformInternal(context, v, location, nativeType,
1705 gl::VariableComponentCount(uniform.type));
1706 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001707}
1708
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001709void Program::flagForDeletion()
1710{
1711 mDeleteStatus = true;
1712}
1713
1714bool Program::isFlaggedForDeletion() const
1715{
1716 return mDeleteStatus;
1717}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001718
Brandon Jones43a53e22014-08-28 16:23:22 -07001719void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001720{
1721 mInfoLog.reset();
1722
Geoff Lang7dd2e102014-11-10 15:19:26 -05001723 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001724 {
Geoff Lang92019432017-11-20 13:09:34 -05001725 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001726 }
1727 else
1728 {
Jamie Madillf6113162015-05-07 11:49:21 -04001729 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001730 }
1731}
1732
Geoff Lang7dd2e102014-11-10 15:19:26 -05001733bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1734{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001735 // Skip cache if we're using an infolog, so we get the full error.
1736 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1737 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1738 {
1739 return mCachedValidateSamplersResult.value();
1740 }
1741
1742 if (mTextureUnitTypesCache.empty())
1743 {
1744 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1745 }
1746 else
1747 {
1748 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1749 }
1750
1751 // if any two active samplers in a program are of different types, but refer to the same
1752 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1753 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001754 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001755 {
Jamie Madill54164b02017-08-28 15:17:37 -04001756 if (samplerBinding.unreferenced)
1757 continue;
1758
Jamie Madille7d84322017-01-10 18:21:59 -05001759 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001760
Jamie Madille7d84322017-01-10 18:21:59 -05001761 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001762 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001763 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1764 {
1765 if (infoLog)
1766 {
1767 (*infoLog) << "Sampler uniform (" << textureUnit
1768 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1769 << caps.maxCombinedTextureImageUnits << ")";
1770 }
1771
1772 mCachedValidateSamplersResult = false;
1773 return false;
1774 }
1775
1776 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1777 {
1778 if (textureType != mTextureUnitTypesCache[textureUnit])
1779 {
1780 if (infoLog)
1781 {
1782 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1783 "image unit ("
1784 << textureUnit << ").";
1785 }
1786
1787 mCachedValidateSamplersResult = false;
1788 return false;
1789 }
1790 }
1791 else
1792 {
1793 mTextureUnitTypesCache[textureUnit] = textureType;
1794 }
1795 }
1796 }
1797
1798 mCachedValidateSamplersResult = true;
1799 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001800}
1801
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001802bool Program::isValidated() const
1803{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001804 return mValidated;
1805}
1806
Geoff Lange1a27752015-10-05 13:16:04 -04001807GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001808{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001809 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001810}
1811
jchen1058f67be2017-10-27 08:59:27 +08001812GLuint Program::getActiveAtomicCounterBufferCount() const
1813{
1814 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1815}
1816
Jiajia Qin729b2c62017-08-14 09:36:11 +08001817GLuint Program::getActiveShaderStorageBlockCount() const
1818{
1819 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1820}
1821
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001822void Program::getActiveUniformBlockName(const GLuint blockIndex,
1823 GLsizei bufSize,
1824 GLsizei *length,
1825 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001826{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001827 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1828}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001830void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1831 GLsizei bufSize,
1832 GLsizei *length,
1833 GLchar *blockName) const
1834{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001835
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001836 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001837}
1838
Geoff Lange1a27752015-10-05 13:16:04 -04001839GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001840{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 int maxLength = 0;
1842
1843 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001844 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001845 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001846 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1847 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001848 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001849 if (!uniformBlock.name.empty())
1850 {
jchen10af713a22017-04-19 09:10:56 +08001851 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1852 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001853 }
1854 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001855 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856
1857 return maxLength;
1858}
1859
Geoff Lange1a27752015-10-05 13:16:04 -04001860GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001862 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1863}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001864
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001865GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1866{
1867 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001868}
1869
Jiajia Qin729b2c62017-08-14 09:36:11 +08001870const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001871{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001872 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1873 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001874}
1875
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001876const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1877{
1878 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1879 return mState.mShaderStorageBlocks[index];
1880}
1881
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001882void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1883{
jchen107a20b972017-06-13 14:25:26 +08001884 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001885 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001886 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001887}
1888
1889GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1890{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001891 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001892}
1893
Jiajia Qin729b2c62017-08-14 09:36:11 +08001894GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1895{
1896 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1897}
1898
Geoff Lang48dcae72014-02-05 16:28:24 -05001899void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1900{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001901 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001902 for (GLsizei i = 0; i < count; i++)
1903 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001904 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001905 }
1906
Jamie Madill48ef11b2016-04-27 15:21:52 -04001907 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001908}
1909
1910void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1911{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001912 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001913 {
jchen10a9042d32017-03-17 08:50:45 +08001914 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1915 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1916 std::string varName = var.nameWithArrayIndex();
1917 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001918 if (length)
1919 {
1920 *length = lastNameIdx;
1921 }
1922 if (size)
1923 {
jchen10a9042d32017-03-17 08:50:45 +08001924 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001925 }
1926 if (type)
1927 {
jchen10a9042d32017-03-17 08:50:45 +08001928 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001929 }
1930 if (name)
1931 {
jchen10a9042d32017-03-17 08:50:45 +08001932 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001933 name[lastNameIdx] = '\0';
1934 }
1935 }
1936}
1937
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001938GLsizei Program::getTransformFeedbackVaryingCount() const
1939{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001940 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001941 {
jchen10a9042d32017-03-17 08:50:45 +08001942 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001943 }
1944 else
1945 {
1946 return 0;
1947 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001948}
1949
1950GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1951{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001952 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001953 {
1954 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001955 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001956 {
jchen10a9042d32017-03-17 08:50:45 +08001957 maxSize =
1958 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001959 }
1960
1961 return maxSize;
1962 }
1963 else
1964 {
1965 return 0;
1966 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001967}
1968
1969GLenum Program::getTransformFeedbackBufferMode() const
1970{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001971 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001972}
1973
Jamie Madillbd044ed2017-06-05 12:59:21 -04001974bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001975{
Jamie Madillbd044ed2017-06-05 12:59:21 -04001976 Shader *vertexShader = mState.mAttachedVertexShader;
1977 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05001978
Jamie Madillbd044ed2017-06-05 12:59:21 -04001979 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001980
Jiawei Shao3d404882017-10-16 13:30:48 +08001981 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
1982 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983
Sami Väisänen46eaa942016-06-29 10:26:37 +03001984 std::map<GLuint, std::string> staticFragmentInputLocations;
1985
Jamie Madill4cff2472015-08-21 16:53:18 -04001986 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001987 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001988 bool matched = false;
1989
1990 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001991 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001992 {
1993 continue;
1994 }
1995
Jamie Madill4cff2472015-08-21 16:53:18 -04001996 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001997 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001998 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001999 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04002000 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002001 if (!linkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04002002 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002003 {
2004 return false;
2005 }
2006
Geoff Lang7dd2e102014-11-10 15:19:26 -05002007 matched = true;
2008 break;
2009 }
2010 }
2011
2012 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04002013 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002014 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04002015 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002016 return false;
2017 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002018
2019 // Check for aliased path rendering input bindings (if any).
2020 // If more than one binding refer statically to the same
2021 // location the link must fail.
2022
2023 if (!output.staticUse)
2024 continue;
2025
2026 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
2027 if (inputBinding == -1)
2028 continue;
2029
2030 const auto it = staticFragmentInputLocations.find(inputBinding);
2031 if (it == std::end(staticFragmentInputLocations))
2032 {
2033 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
2034 }
2035 else
2036 {
2037 infoLog << "Binding for fragment input " << output.name << " conflicts with "
2038 << it->second;
2039 return false;
2040 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002041 }
2042
Jamie Madillbd044ed2017-06-05 12:59:21 -04002043 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05002044 {
2045 return false;
2046 }
2047
Jamie Madillada9ecc2015-08-17 12:53:37 -04002048 // TODO(jmadill): verify no unmatched vertex varyings?
2049
Geoff Lang7dd2e102014-11-10 15:19:26 -05002050 return true;
2051}
2052
Jamie Madillbd044ed2017-06-05 12:59:21 -04002053bool Program::linkUniforms(const Context *context,
2054 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002055 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002056{
Olli Etuahob78707c2017-03-09 15:03:11 +00002057 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002058 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002059 {
2060 return false;
2061 }
2062
Olli Etuahob78707c2017-03-09 15:03:11 +00002063 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002064
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002065 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002066
jchen10eaef1e52017-06-13 10:44:11 +08002067 if (!linkAtomicCounterBuffers())
2068 {
2069 return false;
2070 }
2071
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002072 return true;
2073}
2074
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002075void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002076{
Jamie Madill982f6e02017-06-07 14:33:04 -04002077 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2078 unsigned int low = high;
2079
jchen10eaef1e52017-06-13 10:44:11 +08002080 for (auto counterIter = mState.mUniforms.rbegin();
2081 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2082 {
2083 --low;
2084 }
2085
2086 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2087
2088 high = low;
2089
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002090 for (auto imageIter = mState.mUniforms.rbegin();
2091 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2092 {
2093 --low;
2094 }
2095
2096 mState.mImageUniformRange = RangeUI(low, high);
2097
2098 // If uniform is a image type, insert it into the mImageBindings array.
2099 for (unsigned int imageIndex : mState.mImageUniformRange)
2100 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002101 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2102 // cannot load values into a uniform defined as an image. if declare without a
2103 // binding qualifier, any uniform image variable (include all elements of
2104 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002105 auto &imageUniform = mState.mUniforms[imageIndex];
2106 if (imageUniform.binding == -1)
2107 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002108 mState.mImageBindings.emplace_back(
2109 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002110 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002111 else
2112 {
2113 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002114 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002115 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002116 }
2117
2118 high = low;
2119
2120 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002121 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002122 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002123 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002124 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002125
2126 mState.mSamplerUniformRange = RangeUI(low, high);
2127
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002128 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002129 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002130 {
2131 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2132 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2133 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002134 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002135 }
2136}
2137
jchen10eaef1e52017-06-13 10:44:11 +08002138bool Program::linkAtomicCounterBuffers()
2139{
2140 for (unsigned int index : mState.mAtomicCounterUniformRange)
2141 {
2142 auto &uniform = mState.mUniforms[index];
2143 bool found = false;
2144 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2145 ++bufferIndex)
2146 {
2147 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2148 if (buffer.binding == uniform.binding)
2149 {
2150 buffer.memberIndexes.push_back(index);
2151 uniform.bufferIndex = bufferIndex;
2152 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002153 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002154 break;
2155 }
2156 }
2157 if (!found)
2158 {
2159 AtomicCounterBuffer atomicCounterBuffer;
2160 atomicCounterBuffer.binding = uniform.binding;
2161 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002162 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002163 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2164 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2165 }
2166 }
2167 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2168 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2169
2170 return true;
2171}
2172
Martin Radev4c4c8e72016-08-04 12:25:34 +03002173bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
2174 const std::string &uniformName,
2175 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002176 const sh::InterfaceBlockField &fragmentUniform,
2177 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002178{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002179 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2180 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
2181 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002182 {
2183 return false;
2184 }
2185
2186 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2187 {
Jamie Madillf6113162015-05-07 11:49:21 -04002188 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189 return false;
2190 }
2191
2192 return true;
2193}
2194
Jamie Madilleb979bf2016-11-15 12:28:46 -05002195// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002196bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002197{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002198 const ContextState &data = context->getContextState();
2199 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002200
Geoff Lang7dd2e102014-11-10 15:19:26 -05002201 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002202 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002203 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002204
2205 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002206 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002207 {
Jamie Madillf6113162015-05-07 11:49:21 -04002208 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002209 return false;
2210 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002211
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002212 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002213
Jamie Madillc349ec02015-08-21 16:53:12 -04002214 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002215 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002216 {
Olli Etuahod2551232017-10-26 20:03:33 +03002217 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2218 // structures, so we don't need to worry about adjusting their names or generating entries
2219 // for each member/element (unlike uniforms for example).
2220 ASSERT(!attribute.isArray() && !attribute.isStruct());
2221
Jamie Madilleb979bf2016-11-15 12:28:46 -05002222 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002223 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002224 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002225 attribute.location = bindingLocation;
2226 }
2227
2228 if (attribute.location != -1)
2229 {
2230 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002231 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002232
Jamie Madill63805b42015-08-25 13:17:39 -04002233 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002234 {
Jamie Madillf6113162015-05-07 11:49:21 -04002235 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002236 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002237
2238 return false;
2239 }
2240
Jamie Madill63805b42015-08-25 13:17:39 -04002241 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002242 {
Jamie Madill63805b42015-08-25 13:17:39 -04002243 const int regLocation = attribute.location + reg;
2244 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002245
2246 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002247 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002248 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002249 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002250 // TODO(jmadill): fix aliasing on ES2
2251 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002252 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002253 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002254 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002255 return false;
2256 }
2257 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002258 else
2259 {
Jamie Madill63805b42015-08-25 13:17:39 -04002260 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002261 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002262
Jamie Madill63805b42015-08-25 13:17:39 -04002263 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002264 }
2265 }
2266 }
2267
2268 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002269 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002270 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002271 // Not set by glBindAttribLocation or by location layout qualifier
2272 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002273 {
Jamie Madill63805b42015-08-25 13:17:39 -04002274 int regs = VariableRegisterCount(attribute.type);
2275 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002276
Jamie Madill63805b42015-08-25 13:17:39 -04002277 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002278 {
Jamie Madillf6113162015-05-07 11:49:21 -04002279 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002280 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002281 }
2282
Jamie Madillc349ec02015-08-21 16:53:12 -04002283 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002284 }
2285 }
2286
Jamie Madill48ef11b2016-04-27 15:21:52 -04002287 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002288 {
Jamie Madill63805b42015-08-25 13:17:39 -04002289 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002290 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002291
Jamie Madillbd159f02017-10-09 19:39:06 -04002292 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002293 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002294 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2295 mState.mActiveAttribLocationsMask.set(location);
2296 mState.mMaxActiveAttribLocation =
2297 std::max(mState.mMaxActiveAttribLocation, location + 1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002298 }
2299 }
2300
Geoff Lang7dd2e102014-11-10 15:19:26 -05002301 return true;
2302}
2303
Martin Radev4c4c8e72016-08-04 12:25:34 +03002304bool Program::validateVertexAndFragmentInterfaceBlocks(
2305 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2306 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002307 InfoLog &infoLog,
2308 bool webglCompatibility) const
Martin Radev4c4c8e72016-08-04 12:25:34 +03002309{
2310 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002311 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2312 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002313
2314 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2315 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002316 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002317 }
2318
Jamie Madille473dee2015-08-18 14:49:01 -04002319 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002320 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002321 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2322 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002323 {
2324 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Frank Henigmanfccbac22017-05-28 17:29:26 -04002325 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
2326 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002327 {
2328 return false;
2329 }
2330 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002331 // TODO(jiajia.qin@intel.com): Add
2332 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002333 }
2334 return true;
2335}
Jamie Madille473dee2015-08-18 14:49:01 -04002336
Jiajia Qin729b2c62017-08-14 09:36:11 +08002337bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002338{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002339 const auto &caps = context->getCaps();
2340
Martin Radev4c4c8e72016-08-04 12:25:34 +03002341 if (mState.mAttachedComputeShader)
2342 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002343 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002344 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002345
Jiajia Qin729b2c62017-08-14 09:36:11 +08002346 if (!validateInterfaceBlocksCount(
2347 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002348 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2349 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002350 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002351 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002352 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002353
2354 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2355 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2356 computeShaderStorageBlocks,
2357 "Compute shader shader storage block count exceeds "
2358 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2359 infoLog))
2360 {
2361 return false;
2362 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002363 return true;
2364 }
2365
Jamie Madillbd044ed2017-06-05 12:59:21 -04002366 Shader &vertexShader = *mState.mAttachedVertexShader;
2367 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002368
Jiajia Qin729b2c62017-08-14 09:36:11 +08002369 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2370 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002371
Jiajia Qin729b2c62017-08-14 09:36:11 +08002372 if (!validateInterfaceBlocksCount(
2373 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002374 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2375 {
2376 return false;
2377 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002378 if (!validateInterfaceBlocksCount(
2379 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002380 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2381 infoLog))
2382 {
2383
2384 return false;
2385 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002386
2387 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002388 if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002389 infoLog, webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002390 {
2391 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 }
Jamie Madille473dee2015-08-18 14:49:01 -04002393
Jiajia Qin729b2c62017-08-14 09:36:11 +08002394 if (context->getClientVersion() >= Version(3, 1))
2395 {
2396 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2397 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2398
2399 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2400 vertexShaderStorageBlocks,
2401 "Vertex shader shader storage block count exceeds "
2402 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2403 infoLog))
2404 {
2405 return false;
2406 }
2407 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2408 fragmentShaderStorageBlocks,
2409 "Fragment shader shader storage block count exceeds "
2410 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2411 infoLog))
2412 {
2413
2414 return false;
2415 }
2416
2417 if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
2418 fragmentShaderStorageBlocks, infoLog,
2419 webglCompatibility))
2420 {
2421 return false;
2422 }
2423 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002424 return true;
2425}
2426
Jamie Madilla2c74982016-12-12 11:20:42 -05002427bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002428 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002429 const sh::InterfaceBlock &fragmentInterfaceBlock,
2430 bool webglCompatibility) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002431{
2432 const char* blockName = vertexInterfaceBlock.name.c_str();
2433 // validate blocks for the same member types
2434 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2435 {
Jamie Madillf6113162015-05-07 11:49:21 -04002436 infoLog << "Types for interface block '" << blockName
2437 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002438 return false;
2439 }
2440 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2441 {
Jamie Madillf6113162015-05-07 11:49:21 -04002442 infoLog << "Array sizes differ for interface block '" << blockName
2443 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002444 return false;
2445 }
jchen10af713a22017-04-19 09:10:56 +08002446 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
2447 vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout ||
2448 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002449 {
Jamie Madillf6113162015-05-07 11:49:21 -04002450 infoLog << "Layout qualifiers differ for interface block '" << blockName
2451 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002452 return false;
2453 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002454 const unsigned int numBlockMembers =
2455 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002456 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2457 {
2458 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2459 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2460 if (vertexMember.name != fragmentMember.name)
2461 {
Jamie Madillf6113162015-05-07 11:49:21 -04002462 infoLog << "Name mismatch for field " << blockMemberIndex
2463 << " of interface block '" << blockName
2464 << "': (in vertex: '" << vertexMember.name
2465 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002466 return false;
2467 }
2468 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Frank Henigmanfccbac22017-05-28 17:29:26 -04002469 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
2470 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002471 {
2472 return false;
2473 }
2474 }
2475 return true;
2476}
2477
2478bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2479 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2480{
2481 if (vertexVariable.type != fragmentVariable.type)
2482 {
Jamie Madillf6113162015-05-07 11:49:21 -04002483 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002484 return false;
2485 }
Olli Etuaho465835d2017-09-26 13:34:10 +03002486 if (vertexVariable.arraySizes != fragmentVariable.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002487 {
Jamie Madillf6113162015-05-07 11:49:21 -04002488 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002489 return false;
2490 }
2491 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2492 {
Jamie Madillf6113162015-05-07 11:49:21 -04002493 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002494 return false;
2495 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002496 if (vertexVariable.structName != fragmentVariable.structName)
2497 {
2498 infoLog << "Structure names for " << variableName
2499 << " differ between vertex and fragment shaders";
2500 return false;
2501 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002502
2503 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2504 {
Jamie Madillf6113162015-05-07 11:49:21 -04002505 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002506 return false;
2507 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002508 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002509 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2510 {
2511 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2512 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2513
2514 if (vertexMember.name != fragmentMember.name)
2515 {
Jamie Madillf6113162015-05-07 11:49:21 -04002516 infoLog << "Name mismatch for field '" << memberIndex
2517 << "' of " << variableName
2518 << ": (in vertex: '" << vertexMember.name
2519 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002520 return false;
2521 }
2522
2523 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2524 vertexMember.name + "'";
2525
2526 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2527 {
2528 return false;
2529 }
2530 }
2531
2532 return true;
2533}
2534
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002535bool Program::linkValidateVaryings(InfoLog &infoLog,
2536 const std::string &varyingName,
2537 const sh::Varying &vertexVarying,
2538 const sh::Varying &fragmentVarying,
2539 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002540{
2541 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2542 {
2543 return false;
2544 }
2545
Jamie Madille9cc4692015-02-19 16:00:13 -05002546 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002547 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002548 infoLog << "Interpolation types for " << varyingName
2549 << " differ between vertex and fragment shaders.";
2550 return false;
2551 }
2552
2553 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2554 {
2555 infoLog << "Invariance for " << varyingName
2556 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002557 return false;
2558 }
2559
2560 return true;
2561}
2562
Jamie Madillbd044ed2017-06-05 12:59:21 -04002563bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002564{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002565 Shader *vertexShader = mState.mAttachedVertexShader;
2566 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002567 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2568 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002569 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002570
2571 if (shaderVersion != 100)
2572 {
2573 // Only ESSL 1.0 has restrictions on matching input and output invariance
2574 return true;
2575 }
2576
2577 bool glPositionIsInvariant = false;
2578 bool glPointSizeIsInvariant = false;
2579 bool glFragCoordIsInvariant = false;
2580 bool glPointCoordIsInvariant = false;
2581
2582 for (const sh::Varying &varying : vertexVaryings)
2583 {
2584 if (!varying.isBuiltIn())
2585 {
2586 continue;
2587 }
2588 if (varying.name.compare("gl_Position") == 0)
2589 {
2590 glPositionIsInvariant = varying.isInvariant;
2591 }
2592 else if (varying.name.compare("gl_PointSize") == 0)
2593 {
2594 glPointSizeIsInvariant = varying.isInvariant;
2595 }
2596 }
2597
2598 for (const sh::Varying &varying : fragmentVaryings)
2599 {
2600 if (!varying.isBuiltIn())
2601 {
2602 continue;
2603 }
2604 if (varying.name.compare("gl_FragCoord") == 0)
2605 {
2606 glFragCoordIsInvariant = varying.isInvariant;
2607 }
2608 else if (varying.name.compare("gl_PointCoord") == 0)
2609 {
2610 glPointCoordIsInvariant = varying.isInvariant;
2611 }
2612 }
2613
2614 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2615 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2616 // Not requiring invariance to match is supported by:
2617 // dEQP, WebGL CTS, Nexus 5X GLES
2618 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2619 {
2620 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2621 "declared invariant.";
2622 return false;
2623 }
2624 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2625 {
2626 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2627 "declared invariant.";
2628 return false;
2629 }
2630
2631 return true;
2632}
2633
jchen10a9042d32017-03-17 08:50:45 +08002634bool Program::linkValidateTransformFeedback(const gl::Context *context,
2635 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002636 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002637 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002638{
2639 size_t totalComponents = 0;
2640
Jamie Madillccdf74b2015-08-18 10:46:12 -04002641 std::set<std::string> uniqueNames;
2642
Jamie Madill48ef11b2016-04-27 15:21:52 -04002643 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002644 {
2645 bool found = false;
Olli Etuahoc8538042017-09-27 11:20:15 +03002646 std::vector<unsigned int> subscripts;
2647 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002648
Jamie Madill192745a2016-12-22 15:58:21 -05002649 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002650 {
Jamie Madill192745a2016-12-22 15:58:21 -05002651 const sh::Varying *varying = ref.second.get();
2652
jchen10a9042d32017-03-17 08:50:45 +08002653 if (baseName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002654 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002655 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002656 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002657 infoLog << "Two transform feedback varyings specify the same output variable ("
2658 << tfVaryingName << ").";
2659 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002660 }
jchen10a9042d32017-03-17 08:50:45 +08002661 if (context->getClientVersion() >= Version(3, 1))
2662 {
2663 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2664 {
2665 infoLog
2666 << "Two transform feedback varyings include the same array element ("
2667 << tfVaryingName << ").";
2668 return false;
2669 }
2670 }
2671 else if (varying->isArray())
Geoff Lang1a683462015-09-29 15:09:59 -04002672 {
2673 infoLog << "Capture of arrays is undefined and not supported.";
2674 return false;
2675 }
2676
jchen10a9042d32017-03-17 08:50:45 +08002677 uniqueNames.insert(tfVaryingName);
2678
Jamie Madillccdf74b2015-08-18 10:46:12 -04002679 // TODO(jmadill): Investigate implementation limits on D3D11
Olli Etuaho465835d2017-09-26 13:34:10 +03002680
2681 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
2682 ASSERT(!varying->isArrayOfArrays());
jchen10a9042d32017-03-17 08:50:45 +08002683 size_t elementCount =
Olli Etuaho465835d2017-09-26 13:34:10 +03002684 ((varying->isArray() && subscripts.empty()) ? varying->getOutermostArraySize()
2685 : 1);
jchen10a9042d32017-03-17 08:50:45 +08002686 size_t componentCount = VariableComponentCount(varying->type) * elementCount;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002687 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002688 componentCount > caps.maxTransformFeedbackSeparateComponents)
2689 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002690 infoLog << "Transform feedback varying's " << varying->name << " components ("
2691 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002692 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002693 return false;
2694 }
2695
2696 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002697 found = true;
2698 break;
2699 }
2700 }
jchen10a9042d32017-03-17 08:50:45 +08002701 if (context->getClientVersion() < Version(3, 1) &&
2702 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002703 {
Geoff Lang1a683462015-09-29 15:09:59 -04002704 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002705 return false;
2706 }
jchen1085c93c42017-11-12 15:36:47 +08002707 if (!found)
2708 {
2709 infoLog << "Transform feedback varying " << tfVaryingName
2710 << " does not exist in the vertex shader.";
2711 return false;
2712 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002713 }
2714
Jamie Madill48ef11b2016-04-27 15:21:52 -04002715 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002716 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002717 {
Jamie Madillf6113162015-05-07 11:49:21 -04002718 infoLog << "Transform feedback varying total components (" << totalComponents
2719 << ") exceed the maximum interleaved components ("
2720 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002721 return false;
2722 }
2723
2724 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002725}
2726
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002727bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
2728{
2729 const std::vector<sh::Uniform> &vertexUniforms =
2730 mState.mAttachedVertexShader->getUniforms(context);
2731 const std::vector<sh::Uniform> &fragmentUniforms =
2732 mState.mAttachedFragmentShader->getUniforms(context);
2733 const std::vector<sh::Attribute> &attributes =
2734 mState.mAttachedVertexShader->getActiveAttributes(context);
2735 for (const auto &attrib : attributes)
2736 {
2737 for (const auto &uniform : vertexUniforms)
2738 {
2739 if (uniform.name == attrib.name)
2740 {
2741 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2742 return false;
2743 }
2744 }
2745 for (const auto &uniform : fragmentUniforms)
2746 {
2747 if (uniform.name == attrib.name)
2748 {
2749 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2750 return false;
2751 }
2752 }
2753 }
2754 return true;
2755}
2756
Jamie Madill3c1da042017-11-27 18:33:40 -05002757void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002758{
2759 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002760 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002761 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002762 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002763 std::vector<unsigned int> subscripts;
2764 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002765 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002766 if (!subscripts.empty())
2767 {
2768 subscript = subscripts.back();
2769 }
Jamie Madill192745a2016-12-22 15:58:21 -05002770 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002771 {
Jamie Madill192745a2016-12-22 15:58:21 -05002772 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002773 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002774 {
jchen10a9042d32017-03-17 08:50:45 +08002775 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2776 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002777 break;
2778 }
2779 }
2780 }
2781}
2782
Jamie Madill3c1da042017-11-27 18:33:40 -05002783ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002784{
Jamie Madill3c1da042017-11-27 18:33:40 -05002785 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002786
Jiawei Shao3d404882017-10-16 13:30:48 +08002787 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002788 {
Jamie Madill192745a2016-12-22 15:58:21 -05002789 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002790 }
2791
Jiawei Shao3d404882017-10-16 13:30:48 +08002792 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002793 {
Jamie Madill192745a2016-12-22 15:58:21 -05002794 merged[varying.name].fragment = &varying;
2795 }
2796
2797 return merged;
2798}
2799
Jamie Madill80a6fc02015-08-21 16:53:16 -04002800
Jamie Madillbd044ed2017-06-05 12:59:21 -04002801void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002802{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002803 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002804 ASSERT(fragmentShader != nullptr);
2805
Geoff Lange0cff192017-05-30 13:04:56 -04002806 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002807 ASSERT(mState.mActiveOutputVariables.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002808
2809 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002810 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002811 {
2812 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2813 outputVariable.name != "gl_FragData")
2814 {
2815 continue;
2816 }
2817
2818 unsigned int baseLocation =
2819 (outputVariable.location == -1 ? 0u
2820 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03002821
2822 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
2823 // structures, so we may use getBasicTypeElementCount().
2824 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
2825 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04002826 {
2827 const unsigned int location = baseLocation + elementIndex;
2828 if (location >= mState.mOutputVariableTypes.size())
2829 {
2830 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2831 }
Corentin Walleze7557742017-06-01 13:09:57 -04002832 ASSERT(location < mState.mActiveOutputVariables.size());
2833 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002834 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
2835 }
2836 }
2837
Jamie Madill80a6fc02015-08-21 16:53:16 -04002838 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002839 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002840 return;
2841
Jamie Madillbd044ed2017-06-05 12:59:21 -04002842 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002843 // TODO(jmadill): any caps validation here?
2844
jchen1015015f72017-03-16 13:54:21 +08002845 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002846 outputVariableIndex++)
2847 {
jchen1015015f72017-03-16 13:54:21 +08002848 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002849
Olli Etuahod2551232017-10-26 20:03:33 +03002850 if (outputVariable.isArray())
2851 {
2852 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2853 // Resources and including [0] at the end of array variable names.
2854 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2855 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2856 }
2857
Jamie Madill80a6fc02015-08-21 16:53:16 -04002858 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2859 if (outputVariable.isBuiltIn())
2860 continue;
2861
2862 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002863 unsigned int baseLocation =
2864 (outputVariable.location == -1 ? 0u
2865 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002866
Olli Etuaho465835d2017-09-26 13:34:10 +03002867 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
2868 // structures, so we may use getBasicTypeElementCount().
2869 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
2870 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002871 {
Olli Etuahod2551232017-10-26 20:03:33 +03002872 const unsigned int location = baseLocation + elementIndex;
2873 if (location >= mState.mOutputLocations.size())
2874 {
2875 mState.mOutputLocations.resize(location + 1);
2876 }
2877 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03002878 if (outputVariable.isArray())
2879 {
2880 mState.mOutputLocations[location] =
2881 VariableLocation(elementIndex, outputVariableIndex);
2882 }
2883 else
2884 {
2885 VariableLocation locationInfo;
2886 locationInfo.index = outputVariableIndex;
2887 mState.mOutputLocations[location] = locationInfo;
2888 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04002889 }
2890 }
2891}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002892
Olli Etuaho48fed632017-03-16 12:05:30 +00002893void Program::setUniformValuesFromBindingQualifiers()
2894{
Jamie Madill982f6e02017-06-07 14:33:04 -04002895 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00002896 {
2897 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2898 if (samplerUniform.binding != -1)
2899 {
Olli Etuahod2551232017-10-26 20:03:33 +03002900 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00002901 ASSERT(location != -1);
2902 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03002903 for (unsigned int elementIndex = 0;
2904 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00002905 {
2906 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2907 }
2908 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2909 boundTextureUnits.data());
2910 }
2911 }
2912}
2913
jchen10eaef1e52017-06-13 10:44:11 +08002914void Program::gatherAtomicCounterBuffers()
2915{
jchen10baf5d942017-08-28 20:45:48 +08002916 for (unsigned int index : mState.mAtomicCounterUniformRange)
2917 {
2918 auto &uniform = mState.mUniforms[index];
2919 uniform.blockInfo.offset = uniform.offset;
2920 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2921 uniform.blockInfo.matrixStride = 0;
2922 uniform.blockInfo.isRowMajorMatrix = false;
2923 }
2924
jchen10eaef1e52017-06-13 10:44:11 +08002925 // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
2926}
2927
Jamie Madill6db1c2e2017-11-08 09:17:40 -05002928void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04002929{
jchen10af713a22017-04-19 09:10:56 +08002930 // Set initial bindings from shader.
2931 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
2932 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002933 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08002934 bindUniformBlock(blockIndex, uniformBlock.binding);
2935 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002936}
2937
Jamie Madille7d84322017-01-10 18:21:59 -05002938void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05002939 GLsizei clampedCount,
2940 const GLint *v)
2941{
Jamie Madill81c2e252017-09-09 23:32:46 -04002942 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
2943 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2944 std::vector<GLuint> *boundTextureUnits =
2945 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05002946
Olli Etuaho1734e172017-10-27 15:30:27 +03002947 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04002948
2949 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04002950 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05002951}
2952
2953template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002954GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
2955 GLsizei count,
2956 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05002957 const T *v)
2958{
Jamie Madill134f93d2017-08-31 17:11:00 -04002959 if (count == 1)
2960 return 1;
2961
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002962 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002963
Corentin Wallez15ac5342016-11-03 17:06:39 -04002964 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2965 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03002966 unsigned int remainingElements =
2967 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002968 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002969 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002970
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002971 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002972 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002973 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002974 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002975
2976 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002977}
2978
2979template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002980GLsizei Program::clampMatrixUniformCount(GLint location,
2981 GLsizei count,
2982 GLboolean transpose,
2983 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002984{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002985 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2986
Jamie Madill62d31cb2015-09-11 13:25:51 -04002987 if (!transpose)
2988 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002989 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002990 }
2991
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002992 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04002993
2994 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2995 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03002996 unsigned int remainingElements =
2997 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002998 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04002999}
3000
Jamie Madill54164b02017-08-28 15:17:37 -04003001// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3002// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003003template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003004void Program::getUniformInternal(const Context *context,
3005 DestT *dataOut,
3006 GLint location,
3007 GLenum nativeType,
3008 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003009{
Jamie Madill54164b02017-08-28 15:17:37 -04003010 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003011 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003012 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003013 {
3014 GLint tempValue[16] = {0};
3015 mProgram->getUniformiv(context, location, tempValue);
3016 UniformStateQueryCastLoop<GLboolean>(
3017 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003018 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003019 }
3020 case GL_INT:
3021 {
3022 GLint tempValue[16] = {0};
3023 mProgram->getUniformiv(context, location, tempValue);
3024 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3025 components);
3026 break;
3027 }
3028 case GL_UNSIGNED_INT:
3029 {
3030 GLuint tempValue[16] = {0};
3031 mProgram->getUniformuiv(context, location, tempValue);
3032 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3033 components);
3034 break;
3035 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003036 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003037 {
3038 GLfloat tempValue[16] = {0};
3039 mProgram->getUniformfv(context, location, tempValue);
3040 UniformStateQueryCastLoop<GLfloat>(
3041 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003042 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003043 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003044 default:
3045 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003046 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003047 }
3048}
Jamie Madilla4595b82017-01-11 17:36:34 -05003049
3050bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3051{
3052 // Must be called after samplers are validated.
3053 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3054
3055 for (const auto &binding : mState.mSamplerBindings)
3056 {
3057 GLenum textureType = binding.textureType;
3058 for (const auto &unit : binding.boundTextureUnits)
3059 {
3060 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3061 if (programTextureID == textureID)
3062 {
3063 // TODO(jmadill): Check for appropriate overlap.
3064 return true;
3065 }
3066 }
3067 }
3068
3069 return false;
3070}
3071
Jamie Madilla2c74982016-12-12 11:20:42 -05003072} // namespace gl