blob: a65c670cbd8288c18b837e89897972697ca1f846 [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
jchen108225e732017-11-14 16:29:03 +0800323// Find the matching varying or field by name.
324const sh::ShaderVariable *FindVaryingOrField(const ProgramMergedVaryings &varyings,
325 const std::string &name)
326{
327 const sh::ShaderVariable *var = nullptr;
328 for (const auto &ref : varyings)
329 {
330 const sh::Varying *varying = ref.second.get();
331 if (varying->name == name)
332 {
333 var = varying;
334 break;
335 }
336 var = FindShaderVarField(*varying, name);
337 if (var != nullptr)
338 {
339 break;
340 }
341 }
342 return var;
343}
344
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800345void AddParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
346{
347 ASSERT(mismatchedFieldName);
348 if (mismatchedFieldName->empty())
349 {
350 *mismatchedFieldName = parentName;
351 }
352 else
353 {
354 std::ostringstream stream;
355 stream << parentName << "." << *mismatchedFieldName;
356 *mismatchedFieldName = stream.str();
357 }
358}
359
360const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
361{
362 switch (linkError)
363 {
364 case LinkMismatchError::TYPE_MISMATCH:
365 return "Type";
366 case LinkMismatchError::ARRAY_SIZE_MISMATCH:
367 return "Array size";
368 case LinkMismatchError::PRECISION_MISMATCH:
369 return "Precision";
370 case LinkMismatchError::STRUCT_NAME_MISMATCH:
371 return "Structure name";
372 case LinkMismatchError::FIELD_NUMBER_MISMATCH:
373 return "Field number";
374 case LinkMismatchError::FIELD_NAME_MISMATCH:
375 return "Field name";
376
377 case LinkMismatchError::INTERPOLATION_TYPE_MISMATCH:
378 return "Interpolation type";
379 case LinkMismatchError::INVARIANCE_MISMATCH:
380 return "Invariance";
381
382 case LinkMismatchError::BINDING_MISMATCH:
383 return "Binding layout qualifier";
384 case LinkMismatchError::LOCATION_MISMATCH:
385 return "Location layout qualifier";
386 case LinkMismatchError::OFFSET_MISMATCH:
387 return "Offset layout qualilfier";
388
389 case LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH:
390 return "Layout qualifier";
391 case LinkMismatchError::MATRIX_PACKING_MISMATCH:
392 return "Matrix Packing";
393 default:
394 UNREACHABLE();
395 return "";
396 }
397}
398
Jamie Madill62d31cb2015-09-11 13:25:51 -0400399} // anonymous namespace
400
Jamie Madill4a3c2342015-10-08 12:58:45 -0400401const char *const g_fakepath = "C:\\fakepath";
402
Jamie Madill3c1da042017-11-27 18:33:40 -0500403// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400404InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000405{
406}
407
408InfoLog::~InfoLog()
409{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000410}
411
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400412size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000413{
Jamie Madill23176ce2017-07-31 14:14:33 -0400414 if (!mLazyStream)
415 {
416 return 0;
417 }
418
419 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400420 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000421}
422
Geoff Lange1a27752015-10-05 13:16:04 -0400423void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000424{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400425 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000426
427 if (bufSize > 0)
428 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400429 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400430
Jamie Madill23176ce2017-07-31 14:14:33 -0400431 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000432 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400433 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
434 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000435 }
436
437 infoLog[index] = '\0';
438 }
439
440 if (length)
441 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400442 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000443 }
444}
445
446// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300447// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000448// messages, so lets remove all occurrences of this fake file path from the log.
449void InfoLog::appendSanitized(const char *message)
450{
Jamie Madill23176ce2017-07-31 14:14:33 -0400451 ensureInitialized();
452
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000453 std::string msg(message);
454
455 size_t found;
456 do
457 {
458 found = msg.find(g_fakepath);
459 if (found != std::string::npos)
460 {
461 msg.erase(found, strlen(g_fakepath));
462 }
463 }
464 while (found != std::string::npos);
465
Jamie Madill23176ce2017-07-31 14:14:33 -0400466 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000467}
468
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000469void InfoLog::reset()
470{
Jiawei Shao02f15232017-12-27 10:10:28 +0800471 if (mLazyStream)
472 {
473 mLazyStream.reset(nullptr);
474 }
475}
476
477bool InfoLog::empty() const
478{
479 if (!mLazyStream)
480 {
481 return true;
482 }
483
484 return mLazyStream->rdbuf()->in_avail() == 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000485}
486
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800487void LogLinkMismatch(InfoLog &infoLog,
488 const std::string &variableName,
489 const char *variableType,
490 LinkMismatchError linkError,
491 const std::string &mismatchedStructOrBlockFieldName,
492 GLenum shaderType1,
493 GLenum shaderType2)
494{
495 std::ostringstream stream;
496 stream << GetLinkMismatchErrorString(linkError) << "s of " << variableType << " '"
497 << variableName;
498
499 if (!mismatchedStructOrBlockFieldName.empty())
500 {
501 stream << "' member '" << variableName << "." << mismatchedStructOrBlockFieldName;
502 }
503
504 stream << "' differ between " << GetShaderTypeString(shaderType1) << " and "
505 << GetShaderTypeString(shaderType2) << " shaders.";
506
507 infoLog << stream.str();
508}
509
Jamie Madill3c1da042017-11-27 18:33:40 -0500510// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300511VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000512{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500513}
514
Olli Etuahoc8538042017-09-27 11:20:15 +0300515VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300516 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500517{
Olli Etuahoc8538042017-09-27 11:20:15 +0300518 ASSERT(arrayIndex != GL_INVALID_INDEX);
519}
520
Jamie Madill3c1da042017-11-27 18:33:40 -0500521// SamplerBindings implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500522SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced)
523 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
524{
525}
526
527SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
528
529SamplerBinding::~SamplerBinding() = default;
530
Jamie Madill3c1da042017-11-27 18:33:40 -0500531// ProgramBindings implementation.
532ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500533{
534}
535
Jamie Madill3c1da042017-11-27 18:33:40 -0500536ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500537{
538}
539
Jamie Madill3c1da042017-11-27 18:33:40 -0500540void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400541{
542 mBindings[name] = index;
543}
544
Jamie Madill3c1da042017-11-27 18:33:40 -0500545int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400546{
547 auto iter = mBindings.find(name);
548 return (iter != mBindings.end()) ? iter->second : -1;
549}
550
Jamie Madill3c1da042017-11-27 18:33:40 -0500551ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400552{
553 return mBindings.begin();
554}
555
Jamie Madill3c1da042017-11-27 18:33:40 -0500556ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400557{
558 return mBindings.end();
559}
560
Jamie Madill3c1da042017-11-27 18:33:40 -0500561// ImageBinding implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500562ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
563{
564}
565ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
566{
567 for (size_t index = 0; index < count; ++index)
568 {
569 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
570 }
571}
572
573ImageBinding::ImageBinding(const ImageBinding &other) = default;
574
575ImageBinding::~ImageBinding() = default;
576
Jamie Madill3c1da042017-11-27 18:33:40 -0500577// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400578ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500579 : mLabel(),
580 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400581 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300582 mAttachedComputeShader(nullptr),
Jiawei Shao89be29a2017-11-06 14:36:45 +0800583 mAttachedGeometryShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500584 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400585 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500586 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800587 mImageUniformRange(0, 0),
588 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300589 mBinaryRetrieveableHint(false),
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800590 mNumViews(-1),
591 // [GL_EXT_geometry_shader] Table 20.22
592 mGeometryShaderInputPrimitiveType(GL_TRIANGLES),
593 mGeometryShaderOutputPrimitiveType(GL_TRIANGLE_STRIP),
594 mGeometryShaderInvocations(1),
595 mGeometryShaderMaxVertices(0)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400596{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300597 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400598}
599
Jamie Madill48ef11b2016-04-27 15:21:52 -0400600ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400601{
Jiawei Shao89be29a2017-11-06 14:36:45 +0800602 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader &&
603 !mAttachedGeometryShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400604}
605
Jamie Madill48ef11b2016-04-27 15:21:52 -0400606const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500607{
608 return mLabel;
609}
610
Jamie Madille7d84322017-01-10 18:21:59 -0500611GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400612{
jchen1015015f72017-03-16 13:54:21 +0800613 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400614}
615
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800616GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
617{
618 return GetResourceIndexFromName(mBufferVariables, name);
619}
620
Jamie Madille7d84322017-01-10 18:21:59 -0500621GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
622{
623 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
624 return mUniformLocations[location].index;
625}
626
627Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
628{
629 GLuint index = getUniformIndexFromLocation(location);
630 if (!isSamplerUniformIndex(index))
631 {
632 return Optional<GLuint>::Invalid();
633 }
634
635 return getSamplerIndexFromUniformIndex(index);
636}
637
638bool ProgramState::isSamplerUniformIndex(GLuint index) const
639{
Jamie Madill982f6e02017-06-07 14:33:04 -0400640 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500641}
642
643GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
644{
645 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400646 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500647}
648
Jamie Madill34ca4f52017-06-13 11:49:39 -0400649GLuint ProgramState::getAttributeLocation(const std::string &name) const
650{
651 for (const sh::Attribute &attribute : mAttributes)
652 {
653 if (attribute.name == name)
654 {
655 return attribute.location;
656 }
657 }
658
659 return static_cast<GLuint>(-1);
660}
661
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500662Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400663 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400664 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500665 mLinked(false),
666 mDeleteStatus(false),
667 mRefCount(0),
668 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500669 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500670{
671 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000672
Geoff Lang7dd2e102014-11-10 15:19:26 -0500673 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000674}
675
676Program::~Program()
677{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400678 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679}
680
Jamie Madill4928b7c2017-06-20 12:57:39 -0400681void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500682{
683 if (mState.mAttachedVertexShader != nullptr)
684 {
685 mState.mAttachedVertexShader->release(context);
686 mState.mAttachedVertexShader = nullptr;
687 }
688
689 if (mState.mAttachedFragmentShader != nullptr)
690 {
691 mState.mAttachedFragmentShader->release(context);
692 mState.mAttachedFragmentShader = nullptr;
693 }
694
695 if (mState.mAttachedComputeShader != nullptr)
696 {
697 mState.mAttachedComputeShader->release(context);
698 mState.mAttachedComputeShader = nullptr;
699 }
700
Jiawei Shao89be29a2017-11-06 14:36:45 +0800701 if (mState.mAttachedGeometryShader != nullptr)
702 {
703 mState.mAttachedGeometryShader->release(context);
704 mState.mAttachedGeometryShader = nullptr;
705 }
706
Jamie Madillc564c072017-06-01 12:45:42 -0400707 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400708
709 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800710 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400711 SafeDelete(mProgram);
712
713 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500714}
715
Geoff Lang70d0f492015-12-10 17:45:46 -0500716void Program::setLabel(const std::string &label)
717{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400718 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500719}
720
721const std::string &Program::getLabel() const
722{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400723 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500724}
725
Jamie Madillef300b12016-10-07 15:12:09 -0400726void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300728 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000729 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300730 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731 {
Jamie Madillef300b12016-10-07 15:12:09 -0400732 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300733 mState.mAttachedVertexShader = shader;
734 mState.mAttachedVertexShader->addRef();
735 break;
736 }
737 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738 {
Jamie Madillef300b12016-10-07 15:12:09 -0400739 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300740 mState.mAttachedFragmentShader = shader;
741 mState.mAttachedFragmentShader->addRef();
742 break;
743 }
744 case GL_COMPUTE_SHADER:
745 {
Jamie Madillef300b12016-10-07 15:12:09 -0400746 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300747 mState.mAttachedComputeShader = shader;
748 mState.mAttachedComputeShader->addRef();
749 break;
750 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800751 case GL_GEOMETRY_SHADER_EXT:
752 {
753 ASSERT(!mState.mAttachedGeometryShader);
754 mState.mAttachedGeometryShader = shader;
755 mState.mAttachedGeometryShader->addRef();
756 break;
757 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300758 default:
759 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000760 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761}
762
Jamie Madillc1d770e2017-04-13 17:31:24 -0400763void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300765 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300767 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400769 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500770 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300771 mState.mAttachedVertexShader = nullptr;
772 break;
773 }
774 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000775 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400776 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500777 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300778 mState.mAttachedFragmentShader = nullptr;
779 break;
780 }
781 case GL_COMPUTE_SHADER:
782 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400783 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500784 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300785 mState.mAttachedComputeShader = nullptr;
786 break;
787 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800788 case GL_GEOMETRY_SHADER_EXT:
789 {
790 ASSERT(mState.mAttachedGeometryShader == shader);
791 shader->release(context);
792 mState.mAttachedGeometryShader = nullptr;
793 break;
794 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300795 default:
796 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798}
799
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000800int Program::getAttachedShadersCount() const
801{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300802 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800803 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000804}
805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806void Program::bindAttributeLocation(GLuint index, const char *name)
807{
Geoff Langd8605522016-04-13 10:19:12 -0400808 mAttributeBindings.bindLocation(index, name);
809}
810
811void Program::bindUniformLocation(GLuint index, const char *name)
812{
Olli Etuahod2551232017-10-26 20:03:33 +0300813 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814}
815
Sami Väisänen46eaa942016-06-29 10:26:37 +0300816void Program::bindFragmentInputLocation(GLint index, const char *name)
817{
818 mFragmentInputBindings.bindLocation(index, name);
819}
820
Jamie Madillbd044ed2017-06-05 12:59:21 -0400821BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300822{
823 BindingInfo ret;
824 ret.type = GL_NONE;
825 ret.valid = false;
826
Jamie Madillbd044ed2017-06-05 12:59:21 -0400827 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300828 ASSERT(fragmentShader);
829
830 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800831 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300832
833 for (const auto &binding : mFragmentInputBindings)
834 {
835 if (binding.second != static_cast<GLuint>(index))
836 continue;
837
838 ret.valid = true;
839
Olli Etuahod2551232017-10-26 20:03:33 +0300840 size_t nameLengthWithoutArrayIndex;
841 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300842
843 for (const auto &in : inputs)
844 {
Olli Etuahod2551232017-10-26 20:03:33 +0300845 if (in.name.length() == nameLengthWithoutArrayIndex &&
846 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300847 {
848 if (in.isArray())
849 {
850 // The client wants to bind either "name" or "name[0]".
851 // GL ES 3.1 spec refers to active array names with language such as:
852 // "if the string identifies the base name of an active array, where the
853 // string would exactly match the name of the variable if the suffix "[0]"
854 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400855 if (arrayIndex == GL_INVALID_INDEX)
856 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300857
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400858 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300859 }
860 else
861 {
862 ret.name = in.mappedName;
863 }
864 ret.type = in.type;
865 return ret;
866 }
867 }
868 }
869
870 return ret;
871}
872
Jamie Madillbd044ed2017-06-05 12:59:21 -0400873void Program::pathFragmentInputGen(const Context *context,
874 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300875 GLenum genMode,
876 GLint components,
877 const GLfloat *coeffs)
878{
879 // If the location is -1 then the command is silently ignored
880 if (index == -1)
881 return;
882
Jamie Madillbd044ed2017-06-05 12:59:21 -0400883 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300884
885 // If the input doesn't exist then then the command is silently ignored
886 // This could happen through optimization for example, the shader translator
887 // decides that a variable is not actually being used and optimizes it away.
888 if (binding.name.empty())
889 return;
890
891 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
892}
893
Martin Radev4c4c8e72016-08-04 12:25:34 +0300894// The attached shaders are checked for linking errors by matching up their variables.
895// Uniform, input and output variables get collected.
896// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500897Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000898{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500899 const auto &data = context->getContextState();
900
Jamie Madill6c58b062017-08-01 13:44:25 -0400901 auto *platform = ANGLEPlatformCurrent();
902 double startTime = platform->currentTime(platform);
903
Jamie Madill6c1f6712017-02-14 19:08:04 -0500904 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000905
Jamie Madill32447362017-06-28 14:53:52 -0400906 ProgramHash programHash;
907 auto *cache = context->getMemoryProgramCache();
908 if (cache)
909 {
910 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400911 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400912 }
913
914 if (mLinked)
915 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400916 double delta = platform->currentTime(platform) - startTime;
917 int us = static_cast<int>(delta * 1000000.0);
918 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400919 return NoError();
920 }
921
922 // Cache load failed, fall through to normal linking.
923 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000924 mInfoLog.reset();
925
Jiawei Shao73618602017-12-20 15:47:15 +0800926 if (!linkValidateShaders(context, mInfoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500927 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300928 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400929 }
930
Jiawei Shao73618602017-12-20 15:47:15 +0800931 if (mState.mAttachedComputeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500932 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400933 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300934 {
935 return NoError();
936 }
937
Jiajia Qin729b2c62017-08-14 09:36:11 +0800938 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300939 {
940 return NoError();
941 }
942
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800943 ProgramLinkedResources resources = {
944 {0, PackMode::ANGLE_RELAXED},
945 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +0800946 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
947 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500948
949 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
950 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
951
952 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500953 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300954 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500955 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300956 }
957 }
958 else
959 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400960 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300961 {
962 return NoError();
963 }
964
Jamie Madillbd044ed2017-06-05 12:59:21 -0400965 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300966 {
967 return NoError();
968 }
969
Jamie Madillbd044ed2017-06-05 12:59:21 -0400970 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300971 {
972 return NoError();
973 }
974
Jiajia Qin729b2c62017-08-14 09:36:11 +0800975 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300976 {
977 return NoError();
978 }
979
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400980 if (!linkValidateGlobalNames(context, mInfoLog))
981 {
982 return NoError();
983 }
984
Jamie Madillbd044ed2017-06-05 12:59:21 -0400985 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300986
Jiawei Shao73618602017-12-20 15:47:15 +0800987 ASSERT(mState.mAttachedVertexShader);
988 mState.mNumViews = mState.mAttachedVertexShader->getNumViews(context);
Martin Radev7cf61662017-07-26 17:10:53 +0300989
Jamie Madillbd044ed2017-06-05 12:59:21 -0400990 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300991
Jamie Madill192745a2016-12-22 15:58:21 -0500992 // Map the varyings to the register file
993 // In WebGL, we use a slightly different handling for packing variables.
Jamie Madill61d53252018-01-31 14:49:24 -0500994 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
995 if (data.getLimitations().noFlexibleVaryingPacking)
996 {
997 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
998 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
999 }
1000 else if (data.getExtensions().webglCompatibility)
1001 {
1002 packMode = PackMode::WEBGL_STRICT;
1003 }
Jamie Madillc9727f32017-11-07 12:37:07 -05001004
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001005 ProgramLinkedResources resources = {
1006 {data.getCaps().maxVaryingVectors, packMode},
1007 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +08001008 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1009 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -05001010
1011 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
1012 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
1013
Jiawei Shao73618602017-12-20 15:47:15 +08001014 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -05001015 {
1016 return NoError();
1017 }
1018
jchen1085c93c42017-11-12 15:36:47 +08001019 if (!resources.varyingPacking.collectAndPackUserVaryings(
1020 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +03001021 {
1022 return NoError();
1023 }
1024
Jamie Madillc9727f32017-11-07 12:37:07 -05001025 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -05001026 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001027 {
Jamie Madillb0a838b2016-11-13 20:02:12 -05001028 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001029 }
1030
1031 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -05001032 }
1033
Jamie Madill6db1c2e2017-11-08 09:17:40 -05001034 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -04001035
jchen10eaef1e52017-06-13 10:44:11 +08001036 setUniformValuesFromBindingQualifiers();
1037
Yunchao Heece12532017-11-21 15:50:21 +08001038 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
1039 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +08001040 ASSERT(mLinked);
1041 updateLinkedShaderStages();
1042
Jamie Madill54164b02017-08-28 15:17:37 -04001043 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -04001044 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -04001045
Jamie Madill32447362017-06-28 14:53:52 -04001046 // Save to the program cache.
1047 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
1048 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
1049 {
1050 cache->putProgram(programHash, context, this);
1051 }
1052
Jamie Madill6c58b062017-08-01 13:44:25 -04001053 double delta = platform->currentTime(platform) - startTime;
1054 int us = static_cast<int>(delta * 1000000.0);
1055 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
1056
Martin Radev4c4c8e72016-08-04 12:25:34 +03001057 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001058}
1059
Yunchao He85072e82017-11-14 15:43:28 +08001060void Program::updateLinkedShaderStages()
1061{
Yunchao Heece12532017-11-21 15:50:21 +08001062 mState.mLinkedShaderStages.reset();
1063
Yunchao He85072e82017-11-14 15:43:28 +08001064 if (mState.mAttachedVertexShader)
1065 {
1066 mState.mLinkedShaderStages.set(SHADER_VERTEX);
1067 }
1068
1069 if (mState.mAttachedFragmentShader)
1070 {
1071 mState.mLinkedShaderStages.set(SHADER_FRAGMENT);
1072 }
1073
1074 if (mState.mAttachedComputeShader)
1075 {
1076 mState.mLinkedShaderStages.set(SHADER_COMPUTE);
1077 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001078
1079 if (mState.mAttachedGeometryShader)
1080 {
1081 mState.mLinkedShaderStages.set(SHADER_GEOMETRY);
1082 }
Yunchao He85072e82017-11-14 15:43:28 +08001083}
1084
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00001085// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -05001086void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001088 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -08001089 mState.mAttributesTypeMask.reset();
1090 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001091 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001092 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001093 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001094 mState.mUniforms.clear();
1095 mState.mUniformLocations.clear();
1096 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001097 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001098 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001099 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001100 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001101 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001102 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001103 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001104 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001105 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001106 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001107 mState.mNumViews = -1;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001108 mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
1109 mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
1110 mState.mGeometryShaderInvocations = 1;
1111 mState.mGeometryShaderMaxVertices = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001112
Geoff Lang7dd2e102014-11-10 15:19:26 -05001113 mValidated = false;
1114
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001115 mLinked = false;
1116}
1117
Geoff Lange1a27752015-10-05 13:16:04 -04001118bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001119{
1120 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121}
1122
Jamie Madilla2c74982016-12-12 11:20:42 -05001123Error Program::loadBinary(const Context *context,
1124 GLenum binaryFormat,
1125 const void *binary,
1126 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001127{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001128 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001129
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001131 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001132#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001133 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1134 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001135 {
Jamie Madillf6113162015-05-07 11:49:21 -04001136 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001137 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001138 }
1139
Jamie Madill4f86d052017-06-05 12:59:26 -04001140 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1141 ANGLE_TRY_RESULT(
1142 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001143
1144 // Currently we require the full shader text to compute the program hash.
1145 // TODO(jmadill): Store the binary in the internal program cache.
1146
Jamie Madillb0a838b2016-11-13 20:02:12 -05001147 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001148#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001149}
1150
Jamie Madilla2c74982016-12-12 11:20:42 -05001151Error Program::saveBinary(const Context *context,
1152 GLenum *binaryFormat,
1153 void *binary,
1154 GLsizei bufSize,
1155 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001156{
1157 if (binaryFormat)
1158 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001159 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160 }
1161
Jamie Madill4f86d052017-06-05 12:59:26 -04001162 angle::MemoryBuffer memoryBuf;
1163 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001164
Jamie Madill4f86d052017-06-05 12:59:26 -04001165 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1166 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001167
1168 if (streamLength > bufSize)
1169 {
1170 if (length)
1171 {
1172 *length = 0;
1173 }
1174
1175 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1176 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1177 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001178 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001179 }
1180
1181 if (binary)
1182 {
1183 char *ptr = reinterpret_cast<char*>(binary);
1184
Jamie Madill48ef11b2016-04-27 15:21:52 -04001185 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001186 ptr += streamLength;
1187
1188 ASSERT(ptr - streamLength == binary);
1189 }
1190
1191 if (length)
1192 {
1193 *length = streamLength;
1194 }
1195
He Yunchaoacd18982017-01-04 10:46:42 +08001196 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001197}
1198
Jamie Madillffe00c02017-06-27 16:26:55 -04001199GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001200{
1201 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001202 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001203 if (error.isError())
1204 {
1205 return 0;
1206 }
1207
1208 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001209}
1210
Geoff Langc5629752015-12-07 16:29:04 -05001211void Program::setBinaryRetrievableHint(bool retrievable)
1212{
1213 // TODO(jmadill) : replace with dirty bits
1214 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001215 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001216}
1217
1218bool Program::getBinaryRetrievableHint() const
1219{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001220 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001221}
1222
Yunchao He61afff12017-03-14 15:34:03 +08001223void Program::setSeparable(bool separable)
1224{
1225 // TODO(yunchao) : replace with dirty bits
1226 if (mState.mSeparable != separable)
1227 {
1228 mProgram->setSeparable(separable);
1229 mState.mSeparable = separable;
1230 }
1231}
1232
1233bool Program::isSeparable() const
1234{
1235 return mState.mSeparable;
1236}
1237
Jamie Madill6c1f6712017-02-14 19:08:04 -05001238void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001239{
1240 mRefCount--;
1241
1242 if (mRefCount == 0 && mDeleteStatus)
1243 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001244 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001245 }
1246}
1247
1248void Program::addRef()
1249{
1250 mRefCount++;
1251}
1252
1253unsigned int Program::getRefCount() const
1254{
1255 return mRefCount;
1256}
1257
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001258int Program::getInfoLogLength() const
1259{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001260 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001261}
1262
Geoff Lange1a27752015-10-05 13:16:04 -04001263void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001264{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001265 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001266}
1267
Geoff Lange1a27752015-10-05 13:16:04 -04001268void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001269{
1270 int total = 0;
1271
Martin Radev4c4c8e72016-08-04 12:25:34 +03001272 if (mState.mAttachedComputeShader)
1273 {
1274 if (total < maxCount)
1275 {
1276 shaders[total] = mState.mAttachedComputeShader->getHandle();
1277 total++;
1278 }
1279 }
1280
Jamie Madill48ef11b2016-04-27 15:21:52 -04001281 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001282 {
1283 if (total < maxCount)
1284 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001285 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001286 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001287 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001288 }
1289
Jamie Madill48ef11b2016-04-27 15:21:52 -04001290 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001291 {
1292 if (total < maxCount)
1293 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001294 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001295 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001296 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001297 }
1298
Jiawei Shao89be29a2017-11-06 14:36:45 +08001299 if (mState.mAttachedGeometryShader)
1300 {
1301 if (total < maxCount)
1302 {
1303 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1304 total++;
1305 }
1306 }
1307
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001308 if (count)
1309 {
1310 *count = total;
1311 }
1312}
1313
Geoff Lange1a27752015-10-05 13:16:04 -04001314GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001315{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001316 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001317}
1318
Jamie Madill63805b42015-08-25 13:17:39 -04001319bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001320{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001321 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1322 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001323}
1324
jchen10fd7c3b52017-03-21 15:36:03 +08001325void Program::getActiveAttribute(GLuint index,
1326 GLsizei bufsize,
1327 GLsizei *length,
1328 GLint *size,
1329 GLenum *type,
1330 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001331{
Jamie Madillc349ec02015-08-21 16:53:12 -04001332 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001333 {
1334 if (bufsize > 0)
1335 {
1336 name[0] = '\0';
1337 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001338
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001339 if (length)
1340 {
1341 *length = 0;
1342 }
1343
1344 *type = GL_NONE;
1345 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001346 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001347 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001348
jchen1036e120e2017-03-14 14:53:58 +08001349 ASSERT(index < mState.mAttributes.size());
1350 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001351
1352 if (bufsize > 0)
1353 {
jchen10fd7c3b52017-03-21 15:36:03 +08001354 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001355 }
1356
1357 // Always a single 'type' instance
1358 *size = 1;
1359 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001360}
1361
Geoff Lange1a27752015-10-05 13:16:04 -04001362GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001363{
Jamie Madillc349ec02015-08-21 16:53:12 -04001364 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001365 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001366 return 0;
1367 }
1368
jchen1036e120e2017-03-14 14:53:58 +08001369 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001370}
1371
Geoff Lange1a27752015-10-05 13:16:04 -04001372GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001373{
Jamie Madillc349ec02015-08-21 16:53:12 -04001374 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001375 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001376 return 0;
1377 }
1378
1379 size_t maxLength = 0;
1380
Jamie Madill48ef11b2016-04-27 15:21:52 -04001381 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001382 {
jchen1036e120e2017-03-14 14:53:58 +08001383 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001384 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385
Jamie Madillc349ec02015-08-21 16:53:12 -04001386 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387}
1388
jchen1015015f72017-03-16 13:54:21 +08001389GLuint Program::getInputResourceIndex(const GLchar *name) const
1390{
Olli Etuahod2551232017-10-26 20:03:33 +03001391 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001392}
1393
1394GLuint Program::getOutputResourceIndex(const GLchar *name) const
1395{
1396 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1397}
1398
jchen10fd7c3b52017-03-21 15:36:03 +08001399size_t Program::getOutputResourceCount() const
1400{
1401 return (mLinked ? mState.mOutputVariables.size() : 0);
1402}
1403
jchen10baf5d942017-08-28 20:45:48 +08001404template <typename T>
1405void Program::getResourceName(GLuint index,
1406 const std::vector<T> &resources,
1407 GLsizei bufSize,
1408 GLsizei *length,
1409 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001410{
1411 if (length)
1412 {
1413 *length = 0;
1414 }
1415
1416 if (!mLinked)
1417 {
1418 if (bufSize > 0)
1419 {
1420 name[0] = '\0';
1421 }
1422 return;
1423 }
jchen10baf5d942017-08-28 20:45:48 +08001424 ASSERT(index < resources.size());
1425 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001426
1427 if (bufSize > 0)
1428 {
Olli Etuahod2551232017-10-26 20:03:33 +03001429 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001430 }
1431}
1432
jchen10baf5d942017-08-28 20:45:48 +08001433void Program::getInputResourceName(GLuint index,
1434 GLsizei bufSize,
1435 GLsizei *length,
1436 GLchar *name) const
1437{
1438 getResourceName(index, mState.mAttributes, bufSize, length, name);
1439}
1440
1441void Program::getOutputResourceName(GLuint index,
1442 GLsizei bufSize,
1443 GLsizei *length,
1444 GLchar *name) const
1445{
1446 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1447}
1448
1449void Program::getUniformResourceName(GLuint index,
1450 GLsizei bufSize,
1451 GLsizei *length,
1452 GLchar *name) const
1453{
1454 getResourceName(index, mState.mUniforms, bufSize, length, name);
1455}
1456
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001457void Program::getBufferVariableResourceName(GLuint index,
1458 GLsizei bufSize,
1459 GLsizei *length,
1460 GLchar *name) const
1461{
1462 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1463}
1464
jchen10880683b2017-04-12 16:21:55 +08001465const sh::Attribute &Program::getInputResource(GLuint index) const
1466{
1467 ASSERT(index < mState.mAttributes.size());
1468 return mState.mAttributes[index];
1469}
1470
1471const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1472{
1473 ASSERT(index < mState.mOutputVariables.size());
1474 return mState.mOutputVariables[index];
1475}
1476
Geoff Lang7dd2e102014-11-10 15:19:26 -05001477GLint Program::getFragDataLocation(const std::string &name) const
1478{
Olli Etuahod2551232017-10-26 20:03:33 +03001479 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001480}
1481
Geoff Lange1a27752015-10-05 13:16:04 -04001482void Program::getActiveUniform(GLuint index,
1483 GLsizei bufsize,
1484 GLsizei *length,
1485 GLint *size,
1486 GLenum *type,
1487 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001488{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001489 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001490 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001491 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001492 ASSERT(index < mState.mUniforms.size());
1493 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494
1495 if (bufsize > 0)
1496 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001497 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001498 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001499 }
1500
Olli Etuaho465835d2017-09-26 13:34:10 +03001501 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001502 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001503 }
1504 else
1505 {
1506 if (bufsize > 0)
1507 {
1508 name[0] = '\0';
1509 }
1510
1511 if (length)
1512 {
1513 *length = 0;
1514 }
1515
1516 *size = 0;
1517 *type = GL_NONE;
1518 }
1519}
1520
Geoff Lange1a27752015-10-05 13:16:04 -04001521GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001522{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001524 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001525 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001526 }
1527 else
1528 {
1529 return 0;
1530 }
1531}
1532
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001533size_t Program::getActiveBufferVariableCount() const
1534{
1535 return mLinked ? mState.mBufferVariables.size() : 0;
1536}
1537
Geoff Lange1a27752015-10-05 13:16:04 -04001538GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001539{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001540 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001541
1542 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001543 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001544 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001546 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001547 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001548 size_t length = uniform.name.length() + 1u;
1549 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001550 {
1551 length += 3; // Counting in "[0]".
1552 }
1553 maxLength = std::max(length, maxLength);
1554 }
1555 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001556 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557
Jamie Madill62d31cb2015-09-11 13:25:51 -04001558 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001559}
1560
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561bool Program::isValidUniformLocation(GLint location) const
1562{
Jamie Madille2e406c2016-06-02 13:04:10 -04001563 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001564 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001565 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001566}
1567
Jamie Madill62d31cb2015-09-11 13:25:51 -04001568const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001570 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001571 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001572}
1573
Jamie Madillac4e9c32017-01-13 14:07:12 -05001574const VariableLocation &Program::getUniformLocation(GLint location) const
1575{
1576 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1577 return mState.mUniformLocations[location];
1578}
1579
1580const std::vector<VariableLocation> &Program::getUniformLocations() const
1581{
1582 return mState.mUniformLocations;
1583}
1584
1585const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1586{
1587 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1588 return mState.mUniforms[index];
1589}
1590
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001591const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1592{
1593 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1594 return mState.mBufferVariables[index];
1595}
1596
Jamie Madill62d31cb2015-09-11 13:25:51 -04001597GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001598{
Olli Etuahod2551232017-10-26 20:03:33 +03001599 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600}
1601
Jamie Madill62d31cb2015-09-11 13:25:51 -04001602GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001603{
Jamie Madille7d84322017-01-10 18:21:59 -05001604 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001605}
1606
1607void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1608{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001609 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1610 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001611 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001612}
1613
1614void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1615{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001616 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1617 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001618 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001619}
1620
1621void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1622{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001623 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1624 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001625 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626}
1627
1628void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1629{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001630 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1631 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001632 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633}
1634
Jamie Madill81c2e252017-09-09 23:32:46 -04001635Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001637 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1638 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1639
Jamie Madill81c2e252017-09-09 23:32:46 -04001640 mProgram->setUniform1iv(location, clampedCount, v);
1641
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001642 if (mState.isSamplerUniformIndex(locationInfo.index))
1643 {
1644 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001645 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001646 }
1647
Jamie Madill81c2e252017-09-09 23:32:46 -04001648 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001649}
1650
1651void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1652{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001653 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1654 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001655 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656}
1657
1658void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1659{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001660 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1661 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001662 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001663}
1664
1665void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1666{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001667 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1668 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001669 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001670}
1671
1672void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1673{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001674 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1675 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001676 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677}
1678
1679void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1680{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001681 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1682 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001683 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684}
1685
1686void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1687{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001688 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1689 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001690 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691}
1692
1693void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1694{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001695 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1696 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001697 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001698}
1699
1700void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1701{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001702 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001703 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001704}
1705
1706void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1707{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001708 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001709 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001710}
1711
1712void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1713{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001714 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001715 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001716}
1717
1718void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1719{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001720 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001721 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001722}
1723
1724void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1725{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001726 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001727 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001728}
1729
1730void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1731{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001732 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001733 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001734}
1735
1736void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1737{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001738 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001739 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001740}
1741
1742void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1743{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001744 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001745 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001746}
1747
1748void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1749{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001750 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001751 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001752}
1753
Jamie Madill54164b02017-08-28 15:17:37 -04001754void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001755{
Jamie Madill54164b02017-08-28 15:17:37 -04001756 const auto &uniformLocation = mState.getUniformLocations()[location];
1757 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1758
1759 GLenum nativeType = gl::VariableComponentType(uniform.type);
1760 if (nativeType == GL_FLOAT)
1761 {
1762 mProgram->getUniformfv(context, location, v);
1763 }
1764 else
1765 {
1766 getUniformInternal(context, v, location, nativeType,
1767 gl::VariableComponentCount(uniform.type));
1768 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001769}
1770
Jamie Madill54164b02017-08-28 15:17:37 -04001771void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001772{
Jamie Madill54164b02017-08-28 15:17:37 -04001773 const auto &uniformLocation = mState.getUniformLocations()[location];
1774 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1775
1776 GLenum nativeType = gl::VariableComponentType(uniform.type);
1777 if (nativeType == GL_INT || nativeType == GL_BOOL)
1778 {
1779 mProgram->getUniformiv(context, location, v);
1780 }
1781 else
1782 {
1783 getUniformInternal(context, v, location, nativeType,
1784 gl::VariableComponentCount(uniform.type));
1785 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786}
1787
Jamie Madill54164b02017-08-28 15:17:37 -04001788void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001789{
Jamie Madill54164b02017-08-28 15:17:37 -04001790 const auto &uniformLocation = mState.getUniformLocations()[location];
1791 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1792
1793 GLenum nativeType = gl::VariableComponentType(uniform.type);
1794 if (nativeType == GL_UNSIGNED_INT)
1795 {
1796 mProgram->getUniformuiv(context, location, v);
1797 }
1798 else
1799 {
1800 getUniformInternal(context, v, location, nativeType,
1801 gl::VariableComponentCount(uniform.type));
1802 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001803}
1804
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001805void Program::flagForDeletion()
1806{
1807 mDeleteStatus = true;
1808}
1809
1810bool Program::isFlaggedForDeletion() const
1811{
1812 return mDeleteStatus;
1813}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001814
Brandon Jones43a53e22014-08-28 16:23:22 -07001815void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001816{
1817 mInfoLog.reset();
1818
Geoff Lang7dd2e102014-11-10 15:19:26 -05001819 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001820 {
Geoff Lang92019432017-11-20 13:09:34 -05001821 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001822 }
1823 else
1824 {
Jamie Madillf6113162015-05-07 11:49:21 -04001825 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001826 }
1827}
1828
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1830{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001831 // Skip cache if we're using an infolog, so we get the full error.
1832 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1833 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1834 {
1835 return mCachedValidateSamplersResult.value();
1836 }
1837
1838 if (mTextureUnitTypesCache.empty())
1839 {
1840 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1841 }
1842 else
1843 {
1844 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1845 }
1846
1847 // if any two active samplers in a program are of different types, but refer to the same
1848 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1849 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001850 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001851 {
Jamie Madill54164b02017-08-28 15:17:37 -04001852 if (samplerBinding.unreferenced)
1853 continue;
1854
Jamie Madille7d84322017-01-10 18:21:59 -05001855 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001856
Jamie Madille7d84322017-01-10 18:21:59 -05001857 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001858 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001859 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1860 {
1861 if (infoLog)
1862 {
1863 (*infoLog) << "Sampler uniform (" << textureUnit
1864 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1865 << caps.maxCombinedTextureImageUnits << ")";
1866 }
1867
1868 mCachedValidateSamplersResult = false;
1869 return false;
1870 }
1871
1872 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1873 {
1874 if (textureType != mTextureUnitTypesCache[textureUnit])
1875 {
1876 if (infoLog)
1877 {
1878 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1879 "image unit ("
1880 << textureUnit << ").";
1881 }
1882
1883 mCachedValidateSamplersResult = false;
1884 return false;
1885 }
1886 }
1887 else
1888 {
1889 mTextureUnitTypesCache[textureUnit] = textureType;
1890 }
1891 }
1892 }
1893
1894 mCachedValidateSamplersResult = true;
1895 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001896}
1897
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001898bool Program::isValidated() const
1899{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001900 return mValidated;
1901}
1902
Geoff Lange1a27752015-10-05 13:16:04 -04001903GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001905 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001906}
1907
jchen1058f67be2017-10-27 08:59:27 +08001908GLuint Program::getActiveAtomicCounterBufferCount() const
1909{
1910 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1911}
1912
Jiajia Qin729b2c62017-08-14 09:36:11 +08001913GLuint Program::getActiveShaderStorageBlockCount() const
1914{
1915 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1916}
1917
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001918void Program::getActiveUniformBlockName(const GLuint blockIndex,
1919 GLsizei bufSize,
1920 GLsizei *length,
1921 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001922{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001923 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1924}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001925
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001926void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1927 GLsizei bufSize,
1928 GLsizei *length,
1929 GLchar *blockName) const
1930{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001932 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001933}
1934
Qin Jiajia9bf55522018-01-29 13:56:23 +08001935template <typename T>
1936GLint Program::getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001937{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938 int maxLength = 0;
1939
1940 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001941 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001942 for (const T &resource : resources)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001943 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001944 if (!resource.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001945 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001946 int length = static_cast<int>(resource.nameWithArrayIndex().length());
jchen10af713a22017-04-19 09:10:56 +08001947 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001948 }
1949 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001950 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951
1952 return maxLength;
1953}
1954
Qin Jiajia9bf55522018-01-29 13:56:23 +08001955GLint Program::getActiveUniformBlockMaxNameLength() const
1956{
1957 return getActiveInterfaceBlockMaxNameLength(mState.mUniformBlocks);
1958}
1959
1960GLint Program::getActiveShaderStorageBlockMaxNameLength() const
1961{
1962 return getActiveInterfaceBlockMaxNameLength(mState.mShaderStorageBlocks);
1963}
1964
Geoff Lange1a27752015-10-05 13:16:04 -04001965GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001966{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001967 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1968}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001969
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001970GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1971{
1972 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001973}
1974
Jiajia Qin729b2c62017-08-14 09:36:11 +08001975const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001976{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001977 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1978 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001979}
1980
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001981const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1982{
1983 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1984 return mState.mShaderStorageBlocks[index];
1985}
1986
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001987void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1988{
jchen107a20b972017-06-13 14:25:26 +08001989 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001990 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001991 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001992}
1993
1994GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1995{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001996 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001997}
1998
Jiajia Qin729b2c62017-08-14 09:36:11 +08001999GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
2000{
2001 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
2002}
2003
Geoff Lang48dcae72014-02-05 16:28:24 -05002004void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2005{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002006 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05002007 for (GLsizei i = 0; i < count; i++)
2008 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002009 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05002010 }
2011
Jamie Madill48ef11b2016-04-27 15:21:52 -04002012 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05002013}
2014
2015void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2016{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002018 {
jchen10a9042d32017-03-17 08:50:45 +08002019 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2020 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
2021 std::string varName = var.nameWithArrayIndex();
2022 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05002023 if (length)
2024 {
2025 *length = lastNameIdx;
2026 }
2027 if (size)
2028 {
jchen10a9042d32017-03-17 08:50:45 +08002029 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05002030 }
2031 if (type)
2032 {
jchen10a9042d32017-03-17 08:50:45 +08002033 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05002034 }
2035 if (name)
2036 {
jchen10a9042d32017-03-17 08:50:45 +08002037 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05002038 name[lastNameIdx] = '\0';
2039 }
2040 }
2041}
2042
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002043GLsizei Program::getTransformFeedbackVaryingCount() const
2044{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002046 {
jchen10a9042d32017-03-17 08:50:45 +08002047 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05002048 }
2049 else
2050 {
2051 return 0;
2052 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002053}
2054
2055GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2056{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002057 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002058 {
2059 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08002060 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05002061 {
jchen10a9042d32017-03-17 08:50:45 +08002062 maxSize =
2063 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05002064 }
2065
2066 return maxSize;
2067 }
2068 else
2069 {
2070 return 0;
2071 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002072}
2073
2074GLenum Program::getTransformFeedbackBufferMode() const
2075{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002076 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002077}
2078
Jiawei Shao73618602017-12-20 15:47:15 +08002079bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
2080{
2081 Shader *vertexShader = mState.mAttachedVertexShader;
2082 Shader *fragmentShader = mState.mAttachedFragmentShader;
2083 Shader *computeShader = mState.mAttachedComputeShader;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002084 Shader *geometryShader = mState.mAttachedGeometryShader;
Jiawei Shao73618602017-12-20 15:47:15 +08002085
2086 bool isComputeShaderAttached = (computeShader != nullptr);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002087 bool isGraphicsShaderAttached =
2088 (vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +08002089 // Check whether we both have a compute and non-compute shaders attached.
2090 // If there are of both types attached, then linking should fail.
2091 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
2092 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
2093 {
2094 infoLog << "Both compute and graphics shaders are attached to the same program.";
2095 return false;
2096 }
2097
2098 if (computeShader)
2099 {
2100 if (!computeShader->isCompiled(context))
2101 {
2102 infoLog << "Attached compute shader is not compiled.";
2103 return false;
2104 }
2105 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
2106
2107 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
2108
2109 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2110 // If the work group size is not specified, a link time error should occur.
2111 if (!mState.mComputeShaderLocalSize.isDeclared())
2112 {
2113 infoLog << "Work group size is not specified.";
2114 return false;
2115 }
2116 }
2117 else
2118 {
2119 if (!fragmentShader || !fragmentShader->isCompiled(context))
2120 {
2121 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2122 return false;
2123 }
2124 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
2125
2126 if (!vertexShader || !vertexShader->isCompiled(context))
2127 {
2128 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2129 return false;
2130 }
2131 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
2132
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002133 int vertexShaderVersion = vertexShader->getShaderVersion(context);
2134 if (fragmentShader->getShaderVersion(context) != vertexShaderVersion)
Jiawei Shao73618602017-12-20 15:47:15 +08002135 {
2136 infoLog << "Fragment shader version does not match vertex shader version.";
2137 return false;
2138 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002139
2140 if (geometryShader)
2141 {
2142 // [GL_EXT_geometry_shader] Chapter 7
2143 // Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
2144 // Language Specification, as well as any of the following reasons:
2145 // * One or more of the shader objects attached to <program> are not compiled
2146 // successfully.
2147 // * The shaders do not use the same shader language version.
2148 // * <program> contains objects to form a geometry shader, and
2149 // - <program> is not separable and contains no objects to form a vertex shader; or
2150 // - the input primitive type, output primitive type, or maximum output vertex count
2151 // is not specified in the compiled geometry shader object.
2152 if (!geometryShader->isCompiled(context))
2153 {
2154 infoLog << "The attached geometry shader isn't compiled.";
2155 return false;
2156 }
2157
2158 if (geometryShader->getShaderVersion(context) != vertexShaderVersion)
2159 {
2160 mInfoLog << "Geometry shader version does not match vertex shader version.";
2161 return false;
2162 }
2163 ASSERT(geometryShader->getType() == GL_GEOMETRY_SHADER_EXT);
2164
2165 Optional<GLenum> inputPrimitive =
2166 geometryShader->getGeometryShaderInputPrimitiveType(context);
2167 if (!inputPrimitive.valid())
2168 {
2169 mInfoLog << "Input primitive type is not specified in the geometry shader.";
2170 return false;
2171 }
2172
2173 Optional<GLenum> outputPrimitive =
2174 geometryShader->getGeometryShaderOutputPrimitiveType(context);
2175 if (!outputPrimitive.valid())
2176 {
2177 mInfoLog << "Output primitive type is not specified in the geometry shader.";
2178 return false;
2179 }
2180
2181 Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices(context);
2182 if (!maxVertices.valid())
2183 {
2184 mInfoLog << "'max_vertices' is not specified in the geometry shader.";
2185 return false;
2186 }
2187
2188 mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
2189 mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
2190 mState.mGeometryShaderMaxVertices = maxVertices.value();
2191 mState.mGeometryShaderInvocations =
2192 geometryShader->getGeometryShaderInvocations(context);
2193 }
Jiawei Shao73618602017-12-20 15:47:15 +08002194 }
2195
2196 return true;
2197}
2198
jchen10910a3da2017-11-15 09:40:11 +08002199GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2200{
2201 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2202 {
2203 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2204 if (tf.nameWithArrayIndex() == name)
2205 {
2206 return tfIndex;
2207 }
2208 }
2209 return GL_INVALID_INDEX;
2210}
2211
2212const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2213{
2214 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2215 return mState.mLinkedTransformFeedbackVaryings[index];
2216}
2217
Jamie Madillbd044ed2017-06-05 12:59:21 -04002218bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002219{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002220 Shader *generatingShader = mState.mAttachedVertexShader;
2221 Shader *consumingShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05002222
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002223 ASSERT(generatingShader->getShaderVersion(context) ==
2224 consumingShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002225
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002226 const std::vector<sh::Varying> &outputVaryings = generatingShader->getOutputVaryings(context);
2227 const std::vector<sh::Varying> &inputVaryings = consumingShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002228
Sami Väisänen46eaa942016-06-29 10:26:37 +03002229 std::map<GLuint, std::string> staticFragmentInputLocations;
2230
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002231 for (const sh::Varying &input : inputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002232 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002233 bool matched = false;
2234
2235 // Built-in varyings obey special rules
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002236 if (input.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002237 {
2238 continue;
2239 }
2240
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002241 for (const sh::Varying &output : outputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002242 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002243 if (input.name == output.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002244 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002245 ASSERT(!output.isBuiltIn());
2246
2247 std::string mismatchedStructFieldName;
2248 LinkMismatchError linkError =
2249 LinkValidateVaryings(output, input, generatingShader->getShaderVersion(context),
2250 &mismatchedStructFieldName);
2251 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002252 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002253 LogLinkMismatch(infoLog, input.name, "varying", linkError,
2254 mismatchedStructFieldName, generatingShader->getType(),
2255 consumingShader->getType());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002256 return false;
2257 }
2258
Geoff Lang7dd2e102014-11-10 15:19:26 -05002259 matched = true;
2260 break;
2261 }
2262 }
2263
2264 // We permit unmatched, unreferenced varyings
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002265 if (!matched && input.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002266 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002267 infoLog << GetShaderTypeString(consumingShader->getType()) << " varying " << input.name
2268 << " does not match any " << GetShaderTypeString(generatingShader->getType())
2269 << " varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002270 return false;
2271 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002272
2273 // Check for aliased path rendering input bindings (if any).
2274 // If more than one binding refer statically to the same
2275 // location the link must fail.
2276
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002277 if (!input.staticUse)
Sami Väisänen46eaa942016-06-29 10:26:37 +03002278 continue;
2279
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002280 const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
Sami Väisänen46eaa942016-06-29 10:26:37 +03002281 if (inputBinding == -1)
2282 continue;
2283
2284 const auto it = staticFragmentInputLocations.find(inputBinding);
2285 if (it == std::end(staticFragmentInputLocations))
2286 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002287 staticFragmentInputLocations.insert(std::make_pair(inputBinding, input.name));
Sami Väisänen46eaa942016-06-29 10:26:37 +03002288 }
2289 else
2290 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002291 infoLog << "Binding for fragment input " << input.name << " conflicts with "
Sami Väisänen46eaa942016-06-29 10:26:37 +03002292 << it->second;
2293 return false;
2294 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002295 }
2296
Jamie Madillbd044ed2017-06-05 12:59:21 -04002297 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05002298 {
2299 return false;
2300 }
2301
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002302 // TODO(jmadill): verify no unmatched output varyings?
Jamie Madillada9ecc2015-08-17 12:53:37 -04002303
Geoff Lang7dd2e102014-11-10 15:19:26 -05002304 return true;
2305}
2306
Jamie Madillbd044ed2017-06-05 12:59:21 -04002307bool Program::linkUniforms(const Context *context,
2308 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002309 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002310{
Olli Etuahob78707c2017-03-09 15:03:11 +00002311 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002312 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002313 {
2314 return false;
2315 }
2316
Olli Etuahob78707c2017-03-09 15:03:11 +00002317 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002318
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002319 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002320
jchen10eaef1e52017-06-13 10:44:11 +08002321 if (!linkAtomicCounterBuffers())
2322 {
2323 return false;
2324 }
2325
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002326 return true;
2327}
2328
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002329void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002330{
Jamie Madill982f6e02017-06-07 14:33:04 -04002331 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2332 unsigned int low = high;
2333
jchen10eaef1e52017-06-13 10:44:11 +08002334 for (auto counterIter = mState.mUniforms.rbegin();
2335 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2336 {
2337 --low;
2338 }
2339
2340 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2341
2342 high = low;
2343
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002344 for (auto imageIter = mState.mUniforms.rbegin();
2345 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2346 {
2347 --low;
2348 }
2349
2350 mState.mImageUniformRange = RangeUI(low, high);
2351
2352 // If uniform is a image type, insert it into the mImageBindings array.
2353 for (unsigned int imageIndex : mState.mImageUniformRange)
2354 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002355 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2356 // cannot load values into a uniform defined as an image. if declare without a
2357 // binding qualifier, any uniform image variable (include all elements of
2358 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002359 auto &imageUniform = mState.mUniforms[imageIndex];
2360 if (imageUniform.binding == -1)
2361 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002362 mState.mImageBindings.emplace_back(
2363 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002364 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002365 else
2366 {
2367 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002368 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002369 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002370 }
2371
2372 high = low;
2373
2374 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002375 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002376 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002377 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002378 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002379
2380 mState.mSamplerUniformRange = RangeUI(low, high);
2381
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002382 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002383 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002384 {
2385 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2386 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2387 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002388 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002389 }
2390}
2391
jchen10eaef1e52017-06-13 10:44:11 +08002392bool Program::linkAtomicCounterBuffers()
2393{
2394 for (unsigned int index : mState.mAtomicCounterUniformRange)
2395 {
2396 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002397 uniform.blockInfo.offset = uniform.offset;
2398 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2399 uniform.blockInfo.matrixStride = 0;
2400 uniform.blockInfo.isRowMajorMatrix = false;
2401
jchen10eaef1e52017-06-13 10:44:11 +08002402 bool found = false;
2403 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2404 ++bufferIndex)
2405 {
2406 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2407 if (buffer.binding == uniform.binding)
2408 {
2409 buffer.memberIndexes.push_back(index);
2410 uniform.bufferIndex = bufferIndex;
2411 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002412 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002413 break;
2414 }
2415 }
2416 if (!found)
2417 {
2418 AtomicCounterBuffer atomicCounterBuffer;
2419 atomicCounterBuffer.binding = uniform.binding;
2420 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002421 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002422 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2423 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2424 }
2425 }
2426 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2427 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2428
2429 return true;
2430}
2431
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002432LinkMismatchError Program::LinkValidateInterfaceBlockFields(
2433 const sh::InterfaceBlockField &blockField1,
2434 const sh::InterfaceBlockField &blockField2,
2435 bool webglCompatibility,
2436 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002437{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002438 if (blockField1.name != blockField2.name)
2439 {
2440 return LinkMismatchError::FIELD_NAME_MISMATCH;
2441 }
2442
Frank Henigmanfccbac22017-05-28 17:29:26 -04002443 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002444 LinkMismatchError linkError = LinkValidateVariablesBase(
2445 blockField1, blockField2, webglCompatibility, mismatchedBlockFieldName);
2446 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002447 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002448 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2449 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002450 }
2451
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002452 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002453 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002454 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2455 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002456 }
2457
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002458 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002459}
2460
Jamie Madilleb979bf2016-11-15 12:28:46 -05002461// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002462bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002463{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002464 const ContextState &data = context->getContextState();
2465 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002466
Geoff Lang7dd2e102014-11-10 15:19:26 -05002467 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002468 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002469 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002470
2471 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002472 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002473 {
Jamie Madillf6113162015-05-07 11:49:21 -04002474 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002475 return false;
2476 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002477
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002478 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002479
Jamie Madillc349ec02015-08-21 16:53:12 -04002480 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002481 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002482 {
Olli Etuahod2551232017-10-26 20:03:33 +03002483 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2484 // structures, so we don't need to worry about adjusting their names or generating entries
2485 // for each member/element (unlike uniforms for example).
2486 ASSERT(!attribute.isArray() && !attribute.isStruct());
2487
Jamie Madilleb979bf2016-11-15 12:28:46 -05002488 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002489 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002490 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002491 attribute.location = bindingLocation;
2492 }
2493
2494 if (attribute.location != -1)
2495 {
2496 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002497 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002498
Jamie Madill63805b42015-08-25 13:17:39 -04002499 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002500 {
Jamie Madillf6113162015-05-07 11:49:21 -04002501 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002502 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002503
2504 return false;
2505 }
2506
Jamie Madill63805b42015-08-25 13:17:39 -04002507 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002508 {
Jamie Madill63805b42015-08-25 13:17:39 -04002509 const int regLocation = attribute.location + reg;
2510 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002511
2512 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002513 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002514 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002515 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002516 // TODO(jmadill): fix aliasing on ES2
2517 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002518 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002519 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002520 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002521 return false;
2522 }
2523 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002524 else
2525 {
Jamie Madill63805b42015-08-25 13:17:39 -04002526 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002527 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002528
Jamie Madill63805b42015-08-25 13:17:39 -04002529 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002530 }
2531 }
2532 }
2533
2534 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002535 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002536 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002537 // Not set by glBindAttribLocation or by location layout qualifier
2538 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002539 {
Jamie Madill63805b42015-08-25 13:17:39 -04002540 int regs = VariableRegisterCount(attribute.type);
2541 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002542
Jamie Madill63805b42015-08-25 13:17:39 -04002543 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002544 {
Jamie Madillf6113162015-05-07 11:49:21 -04002545 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002546 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002547 }
2548
Jamie Madillc349ec02015-08-21 16:53:12 -04002549 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002550 }
2551 }
2552
Brandon Jonesc405ae72017-12-06 14:15:03 -08002553 ASSERT(mState.mAttributesTypeMask.none());
2554 ASSERT(mState.mAttributesMask.none());
2555
Jamie Madill48ef11b2016-04-27 15:21:52 -04002556 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002557 {
Jamie Madill63805b42015-08-25 13:17:39 -04002558 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002559 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002560
Jamie Madillbd159f02017-10-09 19:39:06 -04002561 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002562 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002563 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2564 mState.mActiveAttribLocationsMask.set(location);
2565 mState.mMaxActiveAttribLocation =
2566 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08002567
2568 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
2569 if (!attribute.isBuiltIn())
2570 {
2571 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
2572 location);
2573 mState.mAttributesMask.set(location);
2574 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002575 }
2576 }
2577
Geoff Lang7dd2e102014-11-10 15:19:26 -05002578 return true;
2579}
2580
Jiawei Shao73618602017-12-20 15:47:15 +08002581bool Program::ValidateGraphicsInterfaceBlocks(
Martin Radev4c4c8e72016-08-04 12:25:34 +03002582 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2583 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002584 InfoLog &infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002585 bool webglCompatibility,
2586 sh::BlockType blockType,
2587 GLuint maxCombinedInterfaceBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002588{
2589 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002590 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2591 InterfaceBlockMap linkedInterfaceBlocks;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002592 GLuint blockCount = 0;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002593
2594 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2595 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002596 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002597 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2598 {
2599 blockCount += std::max(vertexInterfaceBlock.arraySize, 1u);
2600 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002601 }
2602
Jamie Madille473dee2015-08-18 14:49:01 -04002603 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002604 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002605 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2606 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002607 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002608 const sh::InterfaceBlock &vertexInterfaceBlock = *(entry->second);
2609 std::string mismatchedBlockFieldName;
2610 LinkMismatchError linkError =
2611 AreMatchingInterfaceBlocks(vertexInterfaceBlock, fragmentInterfaceBlock,
2612 webglCompatibility, &mismatchedBlockFieldName);
2613 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002614 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002615 LogLinkMismatch(infoLog, fragmentInterfaceBlock.name, "interface block", linkError,
2616 mismatchedBlockFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002617 return false;
2618 }
2619 }
Jiajia Qin8efd1262017-12-19 09:32:55 +08002620 else
2621 {
2622 if (fragmentInterfaceBlock.staticUse ||
2623 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2624 {
2625 blockCount += std::max(fragmentInterfaceBlock.arraySize, 1u);
2626 }
2627 }
2628 }
2629
2630 if (blockCount > maxCombinedInterfaceBlocks)
2631 {
2632 switch (blockType)
2633 {
2634 case sh::BlockType::BLOCK_UNIFORM:
2635 infoLog << "The sum of the number of active uniform blocks exceeds "
2636 "MAX_COMBINED_UNIFORM_BLOCKS ("
2637 << maxCombinedInterfaceBlocks << ").";
2638 break;
2639 case sh::BlockType::BLOCK_BUFFER:
2640 infoLog << "The sum of the number of active shader storage blocks exceeds "
2641 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2642 << maxCombinedInterfaceBlocks << ").";
2643 break;
2644 default:
2645 UNREACHABLE();
2646 }
2647 return false;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002648 }
2649 return true;
2650}
Jamie Madille473dee2015-08-18 14:49:01 -04002651
Jiajia Qin729b2c62017-08-14 09:36:11 +08002652bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002653{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002654 const auto &caps = context->getCaps();
2655
Martin Radev4c4c8e72016-08-04 12:25:34 +03002656 if (mState.mAttachedComputeShader)
2657 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002658 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002659 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002660
Jiajia Qin729b2c62017-08-14 09:36:11 +08002661 if (!validateInterfaceBlocksCount(
2662 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002663 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2664 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002665 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002666 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002667 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002668
2669 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2670 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2671 computeShaderStorageBlocks,
2672 "Compute shader shader storage block count exceeds "
2673 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2674 infoLog))
2675 {
2676 return false;
2677 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002678 return true;
2679 }
2680
Jamie Madillbd044ed2017-06-05 12:59:21 -04002681 Shader &vertexShader = *mState.mAttachedVertexShader;
2682 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002683
Jiajia Qin729b2c62017-08-14 09:36:11 +08002684 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2685 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002686
Jiajia Qin729b2c62017-08-14 09:36:11 +08002687 if (!validateInterfaceBlocksCount(
2688 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002689 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2690 {
2691 return false;
2692 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002693 if (!validateInterfaceBlocksCount(
2694 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002695 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2696 infoLog))
2697 {
2698
2699 return false;
2700 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002701
2702 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiawei Shao73618602017-12-20 15:47:15 +08002703 if (!ValidateGraphicsInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002704 webglCompatibility, sh::BlockType::BLOCK_UNIFORM,
2705 caps.maxCombinedUniformBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002706 {
2707 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002708 }
Jamie Madille473dee2015-08-18 14:49:01 -04002709
Jiajia Qin729b2c62017-08-14 09:36:11 +08002710 if (context->getClientVersion() >= Version(3, 1))
2711 {
2712 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2713 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2714
2715 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2716 vertexShaderStorageBlocks,
2717 "Vertex shader shader storage block count exceeds "
2718 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2719 infoLog))
2720 {
2721 return false;
2722 }
2723 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2724 fragmentShaderStorageBlocks,
2725 "Fragment shader shader storage block count exceeds "
2726 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2727 infoLog))
2728 {
2729
2730 return false;
2731 }
2732
Jiajia Qin8efd1262017-12-19 09:32:55 +08002733 if (!ValidateGraphicsInterfaceBlocks(
2734 vertexShaderStorageBlocks, fragmentShaderStorageBlocks, infoLog, webglCompatibility,
2735 sh::BlockType::BLOCK_BUFFER, caps.maxCombinedShaderStorageBlocks))
Jiajia Qin729b2c62017-08-14 09:36:11 +08002736 {
2737 return false;
2738 }
2739 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002740 return true;
2741}
2742
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002743LinkMismatchError Program::AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2744 const sh::InterfaceBlock &interfaceBlock2,
2745 bool webglCompatibility,
2746 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002747{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002748 // validate blocks for the same member types
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002749 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002750 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002751 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002752 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002753 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002754 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002755 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002756 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002757 if (interfaceBlock1.layout != interfaceBlock2.layout ||
2758 interfaceBlock1.binding != interfaceBlock2.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002759 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002760 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002761 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002762 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002763 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2764 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002765 const sh::InterfaceBlockField &member1 = interfaceBlock1.fields[blockMemberIndex];
2766 const sh::InterfaceBlockField &member2 = interfaceBlock2.fields[blockMemberIndex];
2767
2768 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2769 member1, member2, webglCompatibility, mismatchedBlockFieldName);
2770 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002771 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002772 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002773 }
2774 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002775 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002776}
2777
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002778LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &variable1,
2779 const sh::ShaderVariable &variable2,
2780 bool validatePrecision,
2781 std::string *mismatchedStructOrBlockMemberName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002782{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002783 if (variable1.type != variable2.type)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002784 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002785 return LinkMismatchError::TYPE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002786 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002787 if (variable1.arraySizes != variable2.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002788 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002789 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002790 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002791 if (validatePrecision && variable1.precision != variable2.precision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002792 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002793 return LinkMismatchError::PRECISION_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002794 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002795 if (variable1.structName != variable2.structName)
Geoff Langbb1e7502017-06-05 16:40:09 -04002796 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002797 return LinkMismatchError::STRUCT_NAME_MISMATCH;
Geoff Langbb1e7502017-06-05 16:40:09 -04002798 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002799
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002800 if (variable1.fields.size() != variable2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002801 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002802 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002803 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002804 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002805 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2806 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002807 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2808 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002809
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002810 if (member1.name != member2.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002811 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002812 return LinkMismatchError::FIELD_NAME_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002813 }
2814
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002815 LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
2816 member1, member2, validatePrecision, mismatchedStructOrBlockMemberName);
2817 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002818 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002819 AddParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2820 return linkErrorOnField;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002821 }
2822 }
2823
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002824 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002825}
2826
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002827LinkMismatchError Program::LinkValidateVaryings(const sh::Varying &outputVarying,
2828 const sh::Varying &inputVarying,
2829 int shaderVersion,
2830 std::string *mismatchedStructFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002831{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002832 LinkMismatchError linkError =
2833 LinkValidateVariablesBase(outputVarying, inputVarying, false, mismatchedStructFieldName);
2834 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002835 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002836 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002837 }
2838
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002839 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002840 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002841 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002842 }
2843
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002844 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002845 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002846 return LinkMismatchError::INVARIANCE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002847 }
2848
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002849 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002850}
2851
Jamie Madillbd044ed2017-06-05 12:59:21 -04002852bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002853{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002854 Shader *vertexShader = mState.mAttachedVertexShader;
2855 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002856 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2857 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002858 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002859
2860 if (shaderVersion != 100)
2861 {
2862 // Only ESSL 1.0 has restrictions on matching input and output invariance
2863 return true;
2864 }
2865
2866 bool glPositionIsInvariant = false;
2867 bool glPointSizeIsInvariant = false;
2868 bool glFragCoordIsInvariant = false;
2869 bool glPointCoordIsInvariant = false;
2870
2871 for (const sh::Varying &varying : vertexVaryings)
2872 {
2873 if (!varying.isBuiltIn())
2874 {
2875 continue;
2876 }
2877 if (varying.name.compare("gl_Position") == 0)
2878 {
2879 glPositionIsInvariant = varying.isInvariant;
2880 }
2881 else if (varying.name.compare("gl_PointSize") == 0)
2882 {
2883 glPointSizeIsInvariant = varying.isInvariant;
2884 }
2885 }
2886
2887 for (const sh::Varying &varying : fragmentVaryings)
2888 {
2889 if (!varying.isBuiltIn())
2890 {
2891 continue;
2892 }
2893 if (varying.name.compare("gl_FragCoord") == 0)
2894 {
2895 glFragCoordIsInvariant = varying.isInvariant;
2896 }
2897 else if (varying.name.compare("gl_PointCoord") == 0)
2898 {
2899 glPointCoordIsInvariant = varying.isInvariant;
2900 }
2901 }
2902
2903 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2904 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2905 // Not requiring invariance to match is supported by:
2906 // dEQP, WebGL CTS, Nexus 5X GLES
2907 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2908 {
2909 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2910 "declared invariant.";
2911 return false;
2912 }
2913 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2914 {
2915 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2916 "declared invariant.";
2917 return false;
2918 }
2919
2920 return true;
2921}
2922
jchen10a9042d32017-03-17 08:50:45 +08002923bool Program::linkValidateTransformFeedback(const gl::Context *context,
2924 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002925 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002926 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002927{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002928
jchen108225e732017-11-14 16:29:03 +08002929 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04002930 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002931 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002932 {
jchen10a9042d32017-03-17 08:50:45 +08002933 if (context->getClientVersion() < Version(3, 1) &&
2934 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002935 {
Geoff Lang1a683462015-09-29 15:09:59 -04002936 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002937 return false;
2938 }
jchen108225e732017-11-14 16:29:03 +08002939 if (context->getClientVersion() >= Version(3, 1))
2940 {
2941 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2942 {
2943 infoLog << "Two transform feedback varyings include the same array element ("
2944 << tfVaryingName << ").";
2945 return false;
2946 }
2947 }
2948 else
2949 {
2950 if (uniqueNames.count(tfVaryingName) > 0)
2951 {
2952 infoLog << "Two transform feedback varyings specify the same output variable ("
2953 << tfVaryingName << ").";
2954 return false;
2955 }
2956 }
2957 uniqueNames.insert(tfVaryingName);
2958 }
2959
2960 // Validate against program varyings.
2961 size_t totalComponents = 0;
2962 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
2963 {
2964 std::vector<unsigned int> subscripts;
2965 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
2966
2967 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
2968 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08002969 {
2970 infoLog << "Transform feedback varying " << tfVaryingName
2971 << " does not exist in the vertex shader.";
2972 return false;
2973 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002974
jchen108225e732017-11-14 16:29:03 +08002975 // Validate the matching variable.
2976 if (var->isStruct())
2977 {
2978 infoLog << "Struct cannot be captured directly (" << baseName << ").";
2979 return false;
2980 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002981
jchen108225e732017-11-14 16:29:03 +08002982 size_t elementCount = 0;
2983 size_t componentCount = 0;
2984
2985 if (var->isArray())
2986 {
2987 if (context->getClientVersion() < Version(3, 1))
2988 {
2989 infoLog << "Capture of arrays is undefined and not supported.";
2990 return false;
2991 }
2992
2993 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
2994 ASSERT(!var->isArrayOfArrays());
2995
2996 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
2997 {
2998 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
2999 return false;
3000 }
3001 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
3002 }
3003 else
3004 {
3005 if (!subscripts.empty())
3006 {
3007 infoLog << "Varying '" << baseName
3008 << "' is not an array to be captured by element.";
3009 return false;
3010 }
3011 elementCount = 1;
3012 }
3013
3014 // TODO(jmadill): Investigate implementation limits on D3D11
3015 componentCount = VariableComponentCount(var->type) * elementCount;
3016 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
3017 componentCount > caps.maxTransformFeedbackSeparateComponents)
3018 {
3019 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
3020 << componentCount << ") exceed the maximum separate components ("
3021 << caps.maxTransformFeedbackSeparateComponents << ").";
3022 return false;
3023 }
3024
3025 totalComponents += componentCount;
3026 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
3027 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
3028 {
3029 infoLog << "Transform feedback varying total components (" << totalComponents
3030 << ") exceed the maximum interleaved components ("
3031 << caps.maxTransformFeedbackInterleavedComponents << ").";
3032 return false;
3033 }
3034 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003035 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05003036}
3037
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003038bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
3039{
3040 const std::vector<sh::Uniform> &vertexUniforms =
3041 mState.mAttachedVertexShader->getUniforms(context);
3042 const std::vector<sh::Uniform> &fragmentUniforms =
3043 mState.mAttachedFragmentShader->getUniforms(context);
3044 const std::vector<sh::Attribute> &attributes =
3045 mState.mAttachedVertexShader->getActiveAttributes(context);
3046 for (const auto &attrib : attributes)
3047 {
3048 for (const auto &uniform : vertexUniforms)
3049 {
3050 if (uniform.name == attrib.name)
3051 {
3052 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3053 return false;
3054 }
3055 }
3056 for (const auto &uniform : fragmentUniforms)
3057 {
3058 if (uniform.name == attrib.name)
3059 {
3060 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3061 return false;
3062 }
3063 }
3064 }
3065 return true;
3066}
3067
Jamie Madill3c1da042017-11-27 18:33:40 -05003068void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003069{
3070 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08003071 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04003072 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003073 {
Olli Etuahoc8538042017-09-27 11:20:15 +03003074 std::vector<unsigned int> subscripts;
3075 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08003076 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03003077 if (!subscripts.empty())
3078 {
3079 subscript = subscripts.back();
3080 }
Jamie Madill192745a2016-12-22 15:58:21 -05003081 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003082 {
Jamie Madill192745a2016-12-22 15:58:21 -05003083 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08003084 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003085 {
jchen10a9042d32017-03-17 08:50:45 +08003086 mState.mLinkedTransformFeedbackVaryings.emplace_back(
3087 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04003088 break;
3089 }
jchen108225e732017-11-14 16:29:03 +08003090 else if (varying->isStruct())
3091 {
3092 const auto *field = FindShaderVarField(*varying, tfVaryingName);
3093 if (field != nullptr)
3094 {
3095 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
3096 break;
3097 }
3098 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04003099 }
3100 }
3101}
3102
Jamie Madill3c1da042017-11-27 18:33:40 -05003103ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04003104{
Jamie Madill3c1da042017-11-27 18:33:40 -05003105 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003106
Jiawei Shao3d404882017-10-16 13:30:48 +08003107 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003108 {
Jamie Madill192745a2016-12-22 15:58:21 -05003109 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003110 }
3111
Jiawei Shao3d404882017-10-16 13:30:48 +08003112 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003113 {
Jamie Madill192745a2016-12-22 15:58:21 -05003114 merged[varying.name].fragment = &varying;
3115 }
3116
3117 return merged;
3118}
3119
Jamie Madillbd044ed2017-06-05 12:59:21 -04003120void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003121{
Jamie Madillbd044ed2017-06-05 12:59:21 -04003122 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003123 ASSERT(fragmentShader != nullptr);
3124
Geoff Lange0cff192017-05-30 13:04:56 -04003125 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04003126 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08003127 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04003128
3129 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04003130 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04003131 {
3132 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
3133 outputVariable.name != "gl_FragData")
3134 {
3135 continue;
3136 }
3137
3138 unsigned int baseLocation =
3139 (outputVariable.location == -1 ? 0u
3140 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03003141
3142 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3143 // structures, so we may use getBasicTypeElementCount().
3144 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3145 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04003146 {
3147 const unsigned int location = baseLocation + elementIndex;
3148 if (location >= mState.mOutputVariableTypes.size())
3149 {
3150 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
3151 }
Corentin Walleze7557742017-06-01 13:09:57 -04003152 ASSERT(location < mState.mActiveOutputVariables.size());
3153 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04003154 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08003155 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04003156 }
3157 }
3158
Jamie Madill80a6fc02015-08-21 16:53:16 -04003159 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04003160 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003161 return;
3162
Jamie Madillbd044ed2017-06-05 12:59:21 -04003163 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04003164 // TODO(jmadill): any caps validation here?
3165
jchen1015015f72017-03-16 13:54:21 +08003166 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04003167 outputVariableIndex++)
3168 {
jchen1015015f72017-03-16 13:54:21 +08003169 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003170
Olli Etuahod2551232017-10-26 20:03:33 +03003171 if (outputVariable.isArray())
3172 {
3173 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
3174 // Resources and including [0] at the end of array variable names.
3175 mState.mOutputVariables[outputVariableIndex].name += "[0]";
3176 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
3177 }
3178
Jamie Madill80a6fc02015-08-21 16:53:16 -04003179 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3180 if (outputVariable.isBuiltIn())
3181 continue;
3182
3183 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03003184 unsigned int baseLocation =
3185 (outputVariable.location == -1 ? 0u
3186 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04003187
Olli Etuaho465835d2017-09-26 13:34:10 +03003188 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3189 // structures, so we may use getBasicTypeElementCount().
3190 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3191 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003192 {
Olli Etuahod2551232017-10-26 20:03:33 +03003193 const unsigned int location = baseLocation + elementIndex;
3194 if (location >= mState.mOutputLocations.size())
3195 {
3196 mState.mOutputLocations.resize(location + 1);
3197 }
3198 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03003199 if (outputVariable.isArray())
3200 {
3201 mState.mOutputLocations[location] =
3202 VariableLocation(elementIndex, outputVariableIndex);
3203 }
3204 else
3205 {
3206 VariableLocation locationInfo;
3207 locationInfo.index = outputVariableIndex;
3208 mState.mOutputLocations[location] = locationInfo;
3209 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003210 }
3211 }
3212}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003213
Olli Etuaho48fed632017-03-16 12:05:30 +00003214void Program::setUniformValuesFromBindingQualifiers()
3215{
Jamie Madill982f6e02017-06-07 14:33:04 -04003216 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003217 {
3218 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3219 if (samplerUniform.binding != -1)
3220 {
Olli Etuahod2551232017-10-26 20:03:33 +03003221 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003222 ASSERT(location != -1);
3223 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003224 for (unsigned int elementIndex = 0;
3225 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003226 {
3227 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3228 }
3229 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3230 boundTextureUnits.data());
3231 }
3232 }
3233}
3234
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003235void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003236{
jchen10af713a22017-04-19 09:10:56 +08003237 // Set initial bindings from shader.
3238 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3239 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003240 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003241 bindUniformBlock(blockIndex, uniformBlock.binding);
3242 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003243}
3244
Jamie Madille7d84322017-01-10 18:21:59 -05003245void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003246 GLsizei clampedCount,
3247 const GLint *v)
3248{
Jamie Madill81c2e252017-09-09 23:32:46 -04003249 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3250 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3251 std::vector<GLuint> *boundTextureUnits =
3252 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003253
Olli Etuaho1734e172017-10-27 15:30:27 +03003254 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04003255
3256 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003257 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003258}
3259
3260template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003261GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3262 GLsizei count,
3263 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003264 const T *v)
3265{
Jamie Madill134f93d2017-08-31 17:11:00 -04003266 if (count == 1)
3267 return 1;
3268
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003269 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003270
Corentin Wallez15ac5342016-11-03 17:06:39 -04003271 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3272 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003273 unsigned int remainingElements =
3274 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003275 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003276 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003277
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003278 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003279 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003280 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003281 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003282
3283 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003284}
3285
3286template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003287GLsizei Program::clampMatrixUniformCount(GLint location,
3288 GLsizei count,
3289 GLboolean transpose,
3290 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003291{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003292 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3293
Jamie Madill62d31cb2015-09-11 13:25:51 -04003294 if (!transpose)
3295 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003296 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003297 }
3298
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003299 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003300
3301 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3302 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003303 unsigned int remainingElements =
3304 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003305 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003306}
3307
Jamie Madill54164b02017-08-28 15:17:37 -04003308// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3309// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003310template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003311void Program::getUniformInternal(const Context *context,
3312 DestT *dataOut,
3313 GLint location,
3314 GLenum nativeType,
3315 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003316{
Jamie Madill54164b02017-08-28 15:17:37 -04003317 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003318 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003319 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003320 {
3321 GLint tempValue[16] = {0};
3322 mProgram->getUniformiv(context, location, tempValue);
3323 UniformStateQueryCastLoop<GLboolean>(
3324 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003325 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003326 }
3327 case GL_INT:
3328 {
3329 GLint tempValue[16] = {0};
3330 mProgram->getUniformiv(context, location, tempValue);
3331 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3332 components);
3333 break;
3334 }
3335 case GL_UNSIGNED_INT:
3336 {
3337 GLuint tempValue[16] = {0};
3338 mProgram->getUniformuiv(context, location, tempValue);
3339 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3340 components);
3341 break;
3342 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003343 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003344 {
3345 GLfloat tempValue[16] = {0};
3346 mProgram->getUniformfv(context, location, tempValue);
3347 UniformStateQueryCastLoop<GLfloat>(
3348 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003349 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003350 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003351 default:
3352 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003353 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003354 }
3355}
Jamie Madilla4595b82017-01-11 17:36:34 -05003356
3357bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3358{
3359 // Must be called after samplers are validated.
3360 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3361
3362 for (const auto &binding : mState.mSamplerBindings)
3363 {
3364 GLenum textureType = binding.textureType;
3365 for (const auto &unit : binding.boundTextureUnits)
3366 {
3367 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3368 if (programTextureID == textureID)
3369 {
3370 // TODO(jmadill): Check for appropriate overlap.
3371 return true;
3372 }
3373 }
3374 }
3375
3376 return false;
3377}
3378
Jamie Madilla2c74982016-12-12 11:20:42 -05003379} // namespace gl