blob: ac4e892f02ec6796faad02bb093152b27107fa46 [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.
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800522SamplerBinding::SamplerBinding(TextureType textureTypeIn, size_t elementCount, bool unreferenced)
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500523 : 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 Madillb7d924a2018-03-10 11:16:54 -0500707 // TODO(jmadill): Handle error in the Context.
708 ANGLE_SWALLOW_ERR(mProgram->destroy(context));
Jamie Madill4928b7c2017-06-20 12:57:39 -0400709
710 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800711 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400712 SafeDelete(mProgram);
713
714 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500715}
716
Geoff Lang70d0f492015-12-10 17:45:46 -0500717void Program::setLabel(const std::string &label)
718{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400719 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500720}
721
722const std::string &Program::getLabel() const
723{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400724 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500725}
726
Jamie Madillef300b12016-10-07 15:12:09 -0400727void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000728{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300729 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000730 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300731 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732 {
Jamie Madillef300b12016-10-07 15:12:09 -0400733 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300734 mState.mAttachedVertexShader = shader;
735 mState.mAttachedVertexShader->addRef();
736 break;
737 }
738 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000739 {
Jamie Madillef300b12016-10-07 15:12:09 -0400740 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300741 mState.mAttachedFragmentShader = shader;
742 mState.mAttachedFragmentShader->addRef();
743 break;
744 }
745 case GL_COMPUTE_SHADER:
746 {
Jamie Madillef300b12016-10-07 15:12:09 -0400747 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300748 mState.mAttachedComputeShader = shader;
749 mState.mAttachedComputeShader->addRef();
750 break;
751 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800752 case GL_GEOMETRY_SHADER_EXT:
753 {
754 ASSERT(!mState.mAttachedGeometryShader);
755 mState.mAttachedGeometryShader = shader;
756 mState.mAttachedGeometryShader->addRef();
757 break;
758 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300759 default:
760 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000762}
763
Jamie Madillc1d770e2017-04-13 17:31:24 -0400764void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000765{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300766 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300768 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400770 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500771 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300772 mState.mAttachedVertexShader = nullptr;
773 break;
774 }
775 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000776 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400777 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500778 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300779 mState.mAttachedFragmentShader = nullptr;
780 break;
781 }
782 case GL_COMPUTE_SHADER:
783 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400784 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500785 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300786 mState.mAttachedComputeShader = nullptr;
787 break;
788 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800789 case GL_GEOMETRY_SHADER_EXT:
790 {
791 ASSERT(mState.mAttachedGeometryShader == shader);
792 shader->release(context);
793 mState.mAttachedGeometryShader = nullptr;
794 break;
795 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300796 default:
797 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000799}
800
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000801int Program::getAttachedShadersCount() const
802{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300803 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800804 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000805}
806
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807void Program::bindAttributeLocation(GLuint index, const char *name)
808{
Geoff Langd8605522016-04-13 10:19:12 -0400809 mAttributeBindings.bindLocation(index, name);
810}
811
812void Program::bindUniformLocation(GLuint index, const char *name)
813{
Olli Etuahod2551232017-10-26 20:03:33 +0300814 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000815}
816
Sami Väisänen46eaa942016-06-29 10:26:37 +0300817void Program::bindFragmentInputLocation(GLint index, const char *name)
818{
819 mFragmentInputBindings.bindLocation(index, name);
820}
821
Jamie Madillbd044ed2017-06-05 12:59:21 -0400822BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300823{
824 BindingInfo ret;
825 ret.type = GL_NONE;
826 ret.valid = false;
827
Jamie Madillbd044ed2017-06-05 12:59:21 -0400828 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300829 ASSERT(fragmentShader);
830
831 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800832 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300833
834 for (const auto &binding : mFragmentInputBindings)
835 {
836 if (binding.second != static_cast<GLuint>(index))
837 continue;
838
839 ret.valid = true;
840
Olli Etuahod2551232017-10-26 20:03:33 +0300841 size_t nameLengthWithoutArrayIndex;
842 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300843
844 for (const auto &in : inputs)
845 {
Olli Etuahod2551232017-10-26 20:03:33 +0300846 if (in.name.length() == nameLengthWithoutArrayIndex &&
847 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300848 {
849 if (in.isArray())
850 {
851 // The client wants to bind either "name" or "name[0]".
852 // GL ES 3.1 spec refers to active array names with language such as:
853 // "if the string identifies the base name of an active array, where the
854 // string would exactly match the name of the variable if the suffix "[0]"
855 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400856 if (arrayIndex == GL_INVALID_INDEX)
857 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300858
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400859 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300860 }
861 else
862 {
863 ret.name = in.mappedName;
864 }
865 ret.type = in.type;
866 return ret;
867 }
868 }
869 }
870
871 return ret;
872}
873
Jamie Madillbd044ed2017-06-05 12:59:21 -0400874void Program::pathFragmentInputGen(const Context *context,
875 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300876 GLenum genMode,
877 GLint components,
878 const GLfloat *coeffs)
879{
880 // If the location is -1 then the command is silently ignored
881 if (index == -1)
882 return;
883
Jamie Madillbd044ed2017-06-05 12:59:21 -0400884 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300885
886 // If the input doesn't exist then then the command is silently ignored
887 // This could happen through optimization for example, the shader translator
888 // decides that a variable is not actually being used and optimizes it away.
889 if (binding.name.empty())
890 return;
891
892 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
893}
894
Martin Radev4c4c8e72016-08-04 12:25:34 +0300895// The attached shaders are checked for linking errors by matching up their variables.
896// Uniform, input and output variables get collected.
897// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500898Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000899{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500900 const auto &data = context->getContextState();
901
Jamie Madill6c58b062017-08-01 13:44:25 -0400902 auto *platform = ANGLEPlatformCurrent();
903 double startTime = platform->currentTime(platform);
904
Jamie Madill6c1f6712017-02-14 19:08:04 -0500905 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000906
Jamie Madill32447362017-06-28 14:53:52 -0400907 ProgramHash programHash;
908 auto *cache = context->getMemoryProgramCache();
909 if (cache)
910 {
911 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400912 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400913 }
914
915 if (mLinked)
916 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400917 double delta = platform->currentTime(platform) - startTime;
918 int us = static_cast<int>(delta * 1000000.0);
919 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400920 return NoError();
921 }
922
923 // Cache load failed, fall through to normal linking.
924 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000925 mInfoLog.reset();
926
Jiawei Shao73618602017-12-20 15:47:15 +0800927 if (!linkValidateShaders(context, mInfoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500928 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300929 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400930 }
931
Jiawei Shao73618602017-12-20 15:47:15 +0800932 if (mState.mAttachedComputeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500933 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400934 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300935 {
936 return NoError();
937 }
938
Jiajia Qin729b2c62017-08-14 09:36:11 +0800939 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300940 {
941 return NoError();
942 }
943
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800944 ProgramLinkedResources resources = {
945 {0, PackMode::ANGLE_RELAXED},
946 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +0800947 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
948 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500949
950 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
951 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
952
953 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500954 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300955 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500956 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300957 }
958 }
959 else
960 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400961 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300962 {
963 return NoError();
964 }
965
Jamie Madillbd044ed2017-06-05 12:59:21 -0400966 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300967 {
968 return NoError();
969 }
970
Jamie Madillbd044ed2017-06-05 12:59:21 -0400971 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300972 {
973 return NoError();
974 }
975
Jiajia Qin729b2c62017-08-14 09:36:11 +0800976 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300977 {
978 return NoError();
979 }
980
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400981 if (!linkValidateGlobalNames(context, mInfoLog))
982 {
983 return NoError();
984 }
985
Jamie Madillbd044ed2017-06-05 12:59:21 -0400986 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300987
Jiawei Shao73618602017-12-20 15:47:15 +0800988 ASSERT(mState.mAttachedVertexShader);
989 mState.mNumViews = mState.mAttachedVertexShader->getNumViews(context);
Martin Radev7cf61662017-07-26 17:10:53 +0300990
Jamie Madillbd044ed2017-06-05 12:59:21 -0400991 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300992
Jamie Madill192745a2016-12-22 15:58:21 -0500993 // Map the varyings to the register file
994 // In WebGL, we use a slightly different handling for packing variables.
Jamie Madill61d53252018-01-31 14:49:24 -0500995 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
996 if (data.getLimitations().noFlexibleVaryingPacking)
997 {
998 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
999 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
1000 }
1001 else if (data.getExtensions().webglCompatibility)
1002 {
1003 packMode = PackMode::WEBGL_STRICT;
1004 }
Jamie Madillc9727f32017-11-07 12:37:07 -05001005
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001006 ProgramLinkedResources resources = {
1007 {data.getCaps().maxVaryingVectors, packMode},
1008 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +08001009 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1010 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -05001011
1012 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
1013 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
1014
Jiawei Shao73618602017-12-20 15:47:15 +08001015 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -05001016 {
1017 return NoError();
1018 }
1019
jchen1085c93c42017-11-12 15:36:47 +08001020 if (!resources.varyingPacking.collectAndPackUserVaryings(
1021 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +03001022 {
1023 return NoError();
1024 }
1025
Jamie Madillc9727f32017-11-07 12:37:07 -05001026 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -05001027 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001028 {
Jamie Madillb0a838b2016-11-13 20:02:12 -05001029 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001030 }
1031
1032 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -05001033 }
1034
Jamie Madill6db1c2e2017-11-08 09:17:40 -05001035 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -04001036
jchen10eaef1e52017-06-13 10:44:11 +08001037 setUniformValuesFromBindingQualifiers();
1038
Yunchao Heece12532017-11-21 15:50:21 +08001039 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
1040 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +08001041 ASSERT(mLinked);
1042 updateLinkedShaderStages();
1043
Jamie Madill54164b02017-08-28 15:17:37 -04001044 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -04001045 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -04001046
Jamie Madill32447362017-06-28 14:53:52 -04001047 // Save to the program cache.
1048 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
1049 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
1050 {
1051 cache->putProgram(programHash, context, this);
1052 }
1053
Jamie Madill6c58b062017-08-01 13:44:25 -04001054 double delta = platform->currentTime(platform) - startTime;
1055 int us = static_cast<int>(delta * 1000000.0);
1056 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
1057
Martin Radev4c4c8e72016-08-04 12:25:34 +03001058 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001059}
1060
Yunchao He85072e82017-11-14 15:43:28 +08001061void Program::updateLinkedShaderStages()
1062{
Yunchao Heece12532017-11-21 15:50:21 +08001063 mState.mLinkedShaderStages.reset();
1064
Yunchao He85072e82017-11-14 15:43:28 +08001065 if (mState.mAttachedVertexShader)
1066 {
1067 mState.mLinkedShaderStages.set(SHADER_VERTEX);
1068 }
1069
1070 if (mState.mAttachedFragmentShader)
1071 {
1072 mState.mLinkedShaderStages.set(SHADER_FRAGMENT);
1073 }
1074
1075 if (mState.mAttachedComputeShader)
1076 {
1077 mState.mLinkedShaderStages.set(SHADER_COMPUTE);
1078 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001079
1080 if (mState.mAttachedGeometryShader)
1081 {
1082 mState.mLinkedShaderStages.set(SHADER_GEOMETRY);
1083 }
Yunchao He85072e82017-11-14 15:43:28 +08001084}
1085
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00001086// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -05001087void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001089 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -08001090 mState.mAttributesTypeMask.reset();
1091 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001092 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001093 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001094 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001095 mState.mUniforms.clear();
1096 mState.mUniformLocations.clear();
1097 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001098 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001099 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001100 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001101 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001102 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001103 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001104 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001105 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001106 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001107 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001108 mState.mNumViews = -1;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001109 mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
1110 mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
1111 mState.mGeometryShaderInvocations = 1;
1112 mState.mGeometryShaderMaxVertices = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001113
Geoff Lang7dd2e102014-11-10 15:19:26 -05001114 mValidated = false;
1115
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001116 mLinked = false;
1117}
1118
Geoff Lange1a27752015-10-05 13:16:04 -04001119bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001120{
1121 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001122}
1123
Jamie Madilla2c74982016-12-12 11:20:42 -05001124Error Program::loadBinary(const Context *context,
1125 GLenum binaryFormat,
1126 const void *binary,
1127 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001128{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001129 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001130
Geoff Lang7dd2e102014-11-10 15:19:26 -05001131#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001132 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001133#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001134 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1135 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001136 {
Jamie Madillf6113162015-05-07 11:49:21 -04001137 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001138 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001139 }
1140
Jamie Madill4f86d052017-06-05 12:59:26 -04001141 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1142 ANGLE_TRY_RESULT(
1143 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001144
1145 // Currently we require the full shader text to compute the program hash.
1146 // TODO(jmadill): Store the binary in the internal program cache.
1147
Jamie Madillb0a838b2016-11-13 20:02:12 -05001148 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001149#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001150}
1151
Jamie Madilla2c74982016-12-12 11:20:42 -05001152Error Program::saveBinary(const Context *context,
1153 GLenum *binaryFormat,
1154 void *binary,
1155 GLsizei bufSize,
1156 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001157{
1158 if (binaryFormat)
1159 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001160 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001161 }
1162
Jamie Madill4f86d052017-06-05 12:59:26 -04001163 angle::MemoryBuffer memoryBuf;
1164 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001165
Jamie Madill4f86d052017-06-05 12:59:26 -04001166 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1167 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001168
1169 if (streamLength > bufSize)
1170 {
1171 if (length)
1172 {
1173 *length = 0;
1174 }
1175
1176 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1177 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1178 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001179 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001180 }
1181
1182 if (binary)
1183 {
1184 char *ptr = reinterpret_cast<char*>(binary);
1185
Jamie Madill48ef11b2016-04-27 15:21:52 -04001186 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001187 ptr += streamLength;
1188
1189 ASSERT(ptr - streamLength == binary);
1190 }
1191
1192 if (length)
1193 {
1194 *length = streamLength;
1195 }
1196
He Yunchaoacd18982017-01-04 10:46:42 +08001197 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001198}
1199
Jamie Madillffe00c02017-06-27 16:26:55 -04001200GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001201{
1202 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001203 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001204 if (error.isError())
1205 {
1206 return 0;
1207 }
1208
1209 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001210}
1211
Geoff Langc5629752015-12-07 16:29:04 -05001212void Program::setBinaryRetrievableHint(bool retrievable)
1213{
1214 // TODO(jmadill) : replace with dirty bits
1215 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001216 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001217}
1218
1219bool Program::getBinaryRetrievableHint() const
1220{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001221 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001222}
1223
Yunchao He61afff12017-03-14 15:34:03 +08001224void Program::setSeparable(bool separable)
1225{
1226 // TODO(yunchao) : replace with dirty bits
1227 if (mState.mSeparable != separable)
1228 {
1229 mProgram->setSeparable(separable);
1230 mState.mSeparable = separable;
1231 }
1232}
1233
1234bool Program::isSeparable() const
1235{
1236 return mState.mSeparable;
1237}
1238
Jamie Madill6c1f6712017-02-14 19:08:04 -05001239void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001240{
1241 mRefCount--;
1242
1243 if (mRefCount == 0 && mDeleteStatus)
1244 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001245 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001246 }
1247}
1248
1249void Program::addRef()
1250{
1251 mRefCount++;
1252}
1253
1254unsigned int Program::getRefCount() const
1255{
1256 return mRefCount;
1257}
1258
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001259int Program::getInfoLogLength() const
1260{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001261 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001262}
1263
Geoff Lange1a27752015-10-05 13:16:04 -04001264void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001265{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001266 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001267}
1268
Geoff Lange1a27752015-10-05 13:16:04 -04001269void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001270{
1271 int total = 0;
1272
Martin Radev4c4c8e72016-08-04 12:25:34 +03001273 if (mState.mAttachedComputeShader)
1274 {
1275 if (total < maxCount)
1276 {
1277 shaders[total] = mState.mAttachedComputeShader->getHandle();
1278 total++;
1279 }
1280 }
1281
Jamie Madill48ef11b2016-04-27 15:21:52 -04001282 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001283 {
1284 if (total < maxCount)
1285 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001286 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001287 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001288 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001289 }
1290
Jamie Madill48ef11b2016-04-27 15:21:52 -04001291 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001292 {
1293 if (total < maxCount)
1294 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001295 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001296 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001297 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001298 }
1299
Jiawei Shao89be29a2017-11-06 14:36:45 +08001300 if (mState.mAttachedGeometryShader)
1301 {
1302 if (total < maxCount)
1303 {
1304 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1305 total++;
1306 }
1307 }
1308
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001309 if (count)
1310 {
1311 *count = total;
1312 }
1313}
1314
Geoff Lange1a27752015-10-05 13:16:04 -04001315GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001316{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001317 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001318}
1319
Jamie Madill63805b42015-08-25 13:17:39 -04001320bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001321{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001322 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1323 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001324}
1325
jchen10fd7c3b52017-03-21 15:36:03 +08001326void Program::getActiveAttribute(GLuint index,
1327 GLsizei bufsize,
1328 GLsizei *length,
1329 GLint *size,
1330 GLenum *type,
1331 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001332{
Jamie Madillc349ec02015-08-21 16:53:12 -04001333 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001334 {
1335 if (bufsize > 0)
1336 {
1337 name[0] = '\0';
1338 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001339
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001340 if (length)
1341 {
1342 *length = 0;
1343 }
1344
1345 *type = GL_NONE;
1346 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001347 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001348 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001349
jchen1036e120e2017-03-14 14:53:58 +08001350 ASSERT(index < mState.mAttributes.size());
1351 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001352
1353 if (bufsize > 0)
1354 {
jchen10fd7c3b52017-03-21 15:36:03 +08001355 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001356 }
1357
1358 // Always a single 'type' instance
1359 *size = 1;
1360 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001361}
1362
Geoff Lange1a27752015-10-05 13:16:04 -04001363GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001364{
Jamie Madillc349ec02015-08-21 16:53:12 -04001365 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001366 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001367 return 0;
1368 }
1369
jchen1036e120e2017-03-14 14:53:58 +08001370 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001371}
1372
Geoff Lange1a27752015-10-05 13:16:04 -04001373GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001374{
Jamie Madillc349ec02015-08-21 16:53:12 -04001375 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001376 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001377 return 0;
1378 }
1379
1380 size_t maxLength = 0;
1381
Jamie Madill48ef11b2016-04-27 15:21:52 -04001382 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001383 {
jchen1036e120e2017-03-14 14:53:58 +08001384 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001385 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386
Jamie Madillc349ec02015-08-21 16:53:12 -04001387 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001388}
1389
jchen1015015f72017-03-16 13:54:21 +08001390GLuint Program::getInputResourceIndex(const GLchar *name) const
1391{
Olli Etuahod2551232017-10-26 20:03:33 +03001392 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001393}
1394
1395GLuint Program::getOutputResourceIndex(const GLchar *name) const
1396{
1397 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1398}
1399
jchen10fd7c3b52017-03-21 15:36:03 +08001400size_t Program::getOutputResourceCount() const
1401{
1402 return (mLinked ? mState.mOutputVariables.size() : 0);
1403}
1404
jchen10baf5d942017-08-28 20:45:48 +08001405template <typename T>
1406void Program::getResourceName(GLuint index,
1407 const std::vector<T> &resources,
1408 GLsizei bufSize,
1409 GLsizei *length,
1410 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001411{
1412 if (length)
1413 {
1414 *length = 0;
1415 }
1416
1417 if (!mLinked)
1418 {
1419 if (bufSize > 0)
1420 {
1421 name[0] = '\0';
1422 }
1423 return;
1424 }
jchen10baf5d942017-08-28 20:45:48 +08001425 ASSERT(index < resources.size());
1426 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001427
1428 if (bufSize > 0)
1429 {
Olli Etuahod2551232017-10-26 20:03:33 +03001430 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001431 }
1432}
1433
jchen10baf5d942017-08-28 20:45:48 +08001434void Program::getInputResourceName(GLuint index,
1435 GLsizei bufSize,
1436 GLsizei *length,
1437 GLchar *name) const
1438{
1439 getResourceName(index, mState.mAttributes, bufSize, length, name);
1440}
1441
1442void Program::getOutputResourceName(GLuint index,
1443 GLsizei bufSize,
1444 GLsizei *length,
1445 GLchar *name) const
1446{
1447 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1448}
1449
1450void Program::getUniformResourceName(GLuint index,
1451 GLsizei bufSize,
1452 GLsizei *length,
1453 GLchar *name) const
1454{
1455 getResourceName(index, mState.mUniforms, bufSize, length, name);
1456}
1457
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001458void Program::getBufferVariableResourceName(GLuint index,
1459 GLsizei bufSize,
1460 GLsizei *length,
1461 GLchar *name) const
1462{
1463 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1464}
1465
jchen10880683b2017-04-12 16:21:55 +08001466const sh::Attribute &Program::getInputResource(GLuint index) const
1467{
1468 ASSERT(index < mState.mAttributes.size());
1469 return mState.mAttributes[index];
1470}
1471
1472const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1473{
1474 ASSERT(index < mState.mOutputVariables.size());
1475 return mState.mOutputVariables[index];
1476}
1477
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478GLint Program::getFragDataLocation(const std::string &name) const
1479{
Olli Etuahod2551232017-10-26 20:03:33 +03001480 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001481}
1482
Geoff Lange1a27752015-10-05 13:16:04 -04001483void Program::getActiveUniform(GLuint index,
1484 GLsizei bufsize,
1485 GLsizei *length,
1486 GLint *size,
1487 GLenum *type,
1488 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001489{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001490 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001491 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001492 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001493 ASSERT(index < mState.mUniforms.size());
1494 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001495
1496 if (bufsize > 0)
1497 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001498 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001499 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001500 }
1501
Olli Etuaho465835d2017-09-26 13:34:10 +03001502 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001503 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001504 }
1505 else
1506 {
1507 if (bufsize > 0)
1508 {
1509 name[0] = '\0';
1510 }
1511
1512 if (length)
1513 {
1514 *length = 0;
1515 }
1516
1517 *size = 0;
1518 *type = GL_NONE;
1519 }
1520}
1521
Geoff Lange1a27752015-10-05 13:16:04 -04001522GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001523{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001524 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001525 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001526 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001527 }
1528 else
1529 {
1530 return 0;
1531 }
1532}
1533
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001534size_t Program::getActiveBufferVariableCount() const
1535{
1536 return mLinked ? mState.mBufferVariables.size() : 0;
1537}
1538
Geoff Lange1a27752015-10-05 13:16:04 -04001539GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001540{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001541 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001542
1543 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001544 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001545 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001546 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001547 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001548 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001549 size_t length = uniform.name.length() + 1u;
1550 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001551 {
1552 length += 3; // Counting in "[0]".
1553 }
1554 maxLength = std::max(length, maxLength);
1555 }
1556 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001557 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558
Jamie Madill62d31cb2015-09-11 13:25:51 -04001559 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001560}
1561
Geoff Lang7dd2e102014-11-10 15:19:26 -05001562bool Program::isValidUniformLocation(GLint location) const
1563{
Jamie Madille2e406c2016-06-02 13:04:10 -04001564 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001565 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001566 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001567}
1568
Jamie Madill62d31cb2015-09-11 13:25:51 -04001569const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001571 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001572 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001573}
1574
Jamie Madillac4e9c32017-01-13 14:07:12 -05001575const VariableLocation &Program::getUniformLocation(GLint location) const
1576{
1577 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1578 return mState.mUniformLocations[location];
1579}
1580
1581const std::vector<VariableLocation> &Program::getUniformLocations() const
1582{
1583 return mState.mUniformLocations;
1584}
1585
1586const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1587{
1588 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1589 return mState.mUniforms[index];
1590}
1591
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001592const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1593{
1594 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1595 return mState.mBufferVariables[index];
1596}
1597
Jamie Madill62d31cb2015-09-11 13:25:51 -04001598GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001599{
Olli Etuahod2551232017-10-26 20:03:33 +03001600 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001601}
1602
Jamie Madill62d31cb2015-09-11 13:25:51 -04001603GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001604{
Jamie Madille7d84322017-01-10 18:21:59 -05001605 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001606}
1607
1608void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1609{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001610 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1611 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001612 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001613}
1614
1615void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1616{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001617 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1618 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001619 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620}
1621
1622void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1623{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001624 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1625 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001626 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001627}
1628
1629void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1630{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001631 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1632 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001633 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001634}
1635
Jamie Madill81c2e252017-09-09 23:32:46 -04001636Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001637{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001638 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1639 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1640
Jamie Madill81c2e252017-09-09 23:32:46 -04001641 mProgram->setUniform1iv(location, clampedCount, v);
1642
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001643 if (mState.isSamplerUniformIndex(locationInfo.index))
1644 {
1645 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001646 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001647 }
1648
Jamie Madill81c2e252017-09-09 23:32:46 -04001649 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001650}
1651
1652void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1653{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001654 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1655 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001656 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001657}
1658
1659void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1660{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001661 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1662 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001663 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001664}
1665
1666void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1667{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001668 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1669 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001670 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001671}
1672
1673void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1674{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001675 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1676 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001677 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001678}
1679
1680void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1681{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001682 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1683 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001684 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001685}
1686
1687void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1688{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001689 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1690 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001691 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001692}
1693
1694void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1695{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001696 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1697 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001698 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001699}
1700
1701void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1702{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001703 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001704 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001705}
1706
1707void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1708{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001709 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001710 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001711}
1712
1713void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1714{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001715 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001716 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001717}
1718
1719void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1720{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001721 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001722 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001723}
1724
1725void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1726{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001727 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001728 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001729}
1730
1731void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1732{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001733 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001734 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001735}
1736
1737void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1738{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001739 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001740 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001741}
1742
1743void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1744{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001745 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001746 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001747}
1748
1749void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1750{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001751 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001752 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001753}
1754
Jamie Madill54164b02017-08-28 15:17:37 -04001755void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001756{
Jamie Madill54164b02017-08-28 15:17:37 -04001757 const auto &uniformLocation = mState.getUniformLocations()[location];
1758 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1759
1760 GLenum nativeType = gl::VariableComponentType(uniform.type);
1761 if (nativeType == GL_FLOAT)
1762 {
1763 mProgram->getUniformfv(context, location, v);
1764 }
1765 else
1766 {
1767 getUniformInternal(context, v, location, nativeType,
1768 gl::VariableComponentCount(uniform.type));
1769 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001770}
1771
Jamie Madill54164b02017-08-28 15:17:37 -04001772void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001773{
Jamie Madill54164b02017-08-28 15:17:37 -04001774 const auto &uniformLocation = mState.getUniformLocations()[location];
1775 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1776
1777 GLenum nativeType = gl::VariableComponentType(uniform.type);
1778 if (nativeType == GL_INT || nativeType == GL_BOOL)
1779 {
1780 mProgram->getUniformiv(context, location, v);
1781 }
1782 else
1783 {
1784 getUniformInternal(context, v, location, nativeType,
1785 gl::VariableComponentCount(uniform.type));
1786 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001787}
1788
Jamie Madill54164b02017-08-28 15:17:37 -04001789void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001790{
Jamie Madill54164b02017-08-28 15:17:37 -04001791 const auto &uniformLocation = mState.getUniformLocations()[location];
1792 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1793
1794 GLenum nativeType = gl::VariableComponentType(uniform.type);
1795 if (nativeType == GL_UNSIGNED_INT)
1796 {
1797 mProgram->getUniformuiv(context, location, v);
1798 }
1799 else
1800 {
1801 getUniformInternal(context, v, location, nativeType,
1802 gl::VariableComponentCount(uniform.type));
1803 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001804}
1805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001806void Program::flagForDeletion()
1807{
1808 mDeleteStatus = true;
1809}
1810
1811bool Program::isFlaggedForDeletion() const
1812{
1813 return mDeleteStatus;
1814}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001815
Brandon Jones43a53e22014-08-28 16:23:22 -07001816void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001817{
1818 mInfoLog.reset();
1819
Geoff Lang7dd2e102014-11-10 15:19:26 -05001820 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001821 {
Geoff Lang92019432017-11-20 13:09:34 -05001822 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001823 }
1824 else
1825 {
Jamie Madillf6113162015-05-07 11:49:21 -04001826 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001827 }
1828}
1829
Geoff Lang7dd2e102014-11-10 15:19:26 -05001830bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1831{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001832 // Skip cache if we're using an infolog, so we get the full error.
1833 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1834 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1835 {
1836 return mCachedValidateSamplersResult.value();
1837 }
1838
1839 if (mTextureUnitTypesCache.empty())
1840 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001841 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, TextureType::InvalidEnum);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001842 }
1843 else
1844 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001845 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(),
1846 TextureType::InvalidEnum);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001847 }
1848
1849 // if any two active samplers in a program are of different types, but refer to the same
1850 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1851 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001852 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001853 {
Jamie Madill54164b02017-08-28 15:17:37 -04001854 if (samplerBinding.unreferenced)
1855 continue;
1856
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001857 TextureType textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001858
Jamie Madille7d84322017-01-10 18:21:59 -05001859 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001860 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001861 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1862 {
1863 if (infoLog)
1864 {
1865 (*infoLog) << "Sampler uniform (" << textureUnit
1866 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1867 << caps.maxCombinedTextureImageUnits << ")";
1868 }
1869
1870 mCachedValidateSamplersResult = false;
1871 return false;
1872 }
1873
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001874 if (mTextureUnitTypesCache[textureUnit] != TextureType::InvalidEnum)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001875 {
1876 if (textureType != mTextureUnitTypesCache[textureUnit])
1877 {
1878 if (infoLog)
1879 {
1880 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1881 "image unit ("
1882 << textureUnit << ").";
1883 }
1884
1885 mCachedValidateSamplersResult = false;
1886 return false;
1887 }
1888 }
1889 else
1890 {
1891 mTextureUnitTypesCache[textureUnit] = textureType;
1892 }
1893 }
1894 }
1895
1896 mCachedValidateSamplersResult = true;
1897 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001898}
1899
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001900bool Program::isValidated() const
1901{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001902 return mValidated;
1903}
1904
Geoff Lange1a27752015-10-05 13:16:04 -04001905GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001906{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001907 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001908}
1909
jchen1058f67be2017-10-27 08:59:27 +08001910GLuint Program::getActiveAtomicCounterBufferCount() const
1911{
1912 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1913}
1914
Jiajia Qin729b2c62017-08-14 09:36:11 +08001915GLuint Program::getActiveShaderStorageBlockCount() const
1916{
1917 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1918}
1919
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001920void Program::getActiveUniformBlockName(const GLuint blockIndex,
1921 GLsizei bufSize,
1922 GLsizei *length,
1923 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001925 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1926}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001927
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001928void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1929 GLsizei bufSize,
1930 GLsizei *length,
1931 GLchar *blockName) const
1932{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001933
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001934 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001935}
1936
Qin Jiajia9bf55522018-01-29 13:56:23 +08001937template <typename T>
1938GLint Program::getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001939{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001940 int maxLength = 0;
1941
1942 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001943 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001944 for (const T &resource : resources)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001945 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001946 if (!resource.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001947 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001948 int length = static_cast<int>(resource.nameWithArrayIndex().length());
jchen10af713a22017-04-19 09:10:56 +08001949 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001950 }
1951 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001952 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001953
1954 return maxLength;
1955}
1956
Qin Jiajia9bf55522018-01-29 13:56:23 +08001957GLint Program::getActiveUniformBlockMaxNameLength() const
1958{
1959 return getActiveInterfaceBlockMaxNameLength(mState.mUniformBlocks);
1960}
1961
1962GLint Program::getActiveShaderStorageBlockMaxNameLength() const
1963{
1964 return getActiveInterfaceBlockMaxNameLength(mState.mShaderStorageBlocks);
1965}
1966
Geoff Lange1a27752015-10-05 13:16:04 -04001967GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001968{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001969 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1970}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001971
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001972GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1973{
1974 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001975}
1976
Jiajia Qin729b2c62017-08-14 09:36:11 +08001977const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001978{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001979 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1980 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001981}
1982
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001983const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1984{
1985 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1986 return mState.mShaderStorageBlocks[index];
1987}
1988
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001989void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1990{
jchen107a20b972017-06-13 14:25:26 +08001991 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001992 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001993 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001994}
1995
1996GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1997{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001998 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001999}
2000
Jiajia Qin729b2c62017-08-14 09:36:11 +08002001GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
2002{
2003 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
2004}
2005
Geoff Lang48dcae72014-02-05 16:28:24 -05002006void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2007{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002008 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05002009 for (GLsizei i = 0; i < count; i++)
2010 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002011 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05002012 }
2013
Jamie Madill48ef11b2016-04-27 15:21:52 -04002014 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05002015}
2016
2017void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2018{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002019 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002020 {
jchen10a9042d32017-03-17 08:50:45 +08002021 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2022 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
2023 std::string varName = var.nameWithArrayIndex();
2024 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05002025 if (length)
2026 {
2027 *length = lastNameIdx;
2028 }
2029 if (size)
2030 {
jchen10a9042d32017-03-17 08:50:45 +08002031 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05002032 }
2033 if (type)
2034 {
jchen10a9042d32017-03-17 08:50:45 +08002035 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05002036 }
2037 if (name)
2038 {
jchen10a9042d32017-03-17 08:50:45 +08002039 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05002040 name[lastNameIdx] = '\0';
2041 }
2042 }
2043}
2044
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002045GLsizei Program::getTransformFeedbackVaryingCount() const
2046{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002047 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002048 {
jchen10a9042d32017-03-17 08:50:45 +08002049 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05002050 }
2051 else
2052 {
2053 return 0;
2054 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002055}
2056
2057GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2058{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002059 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002060 {
2061 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08002062 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05002063 {
jchen10a9042d32017-03-17 08:50:45 +08002064 maxSize =
2065 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05002066 }
2067
2068 return maxSize;
2069 }
2070 else
2071 {
2072 return 0;
2073 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002074}
2075
2076GLenum Program::getTransformFeedbackBufferMode() const
2077{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002078 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002079}
2080
Jiawei Shao73618602017-12-20 15:47:15 +08002081bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
2082{
2083 Shader *vertexShader = mState.mAttachedVertexShader;
2084 Shader *fragmentShader = mState.mAttachedFragmentShader;
2085 Shader *computeShader = mState.mAttachedComputeShader;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002086 Shader *geometryShader = mState.mAttachedGeometryShader;
Jiawei Shao73618602017-12-20 15:47:15 +08002087
2088 bool isComputeShaderAttached = (computeShader != nullptr);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002089 bool isGraphicsShaderAttached =
2090 (vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +08002091 // Check whether we both have a compute and non-compute shaders attached.
2092 // If there are of both types attached, then linking should fail.
2093 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
2094 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
2095 {
2096 infoLog << "Both compute and graphics shaders are attached to the same program.";
2097 return false;
2098 }
2099
2100 if (computeShader)
2101 {
2102 if (!computeShader->isCompiled(context))
2103 {
2104 infoLog << "Attached compute shader is not compiled.";
2105 return false;
2106 }
2107 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
2108
2109 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
2110
2111 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2112 // If the work group size is not specified, a link time error should occur.
2113 if (!mState.mComputeShaderLocalSize.isDeclared())
2114 {
2115 infoLog << "Work group size is not specified.";
2116 return false;
2117 }
2118 }
2119 else
2120 {
2121 if (!fragmentShader || !fragmentShader->isCompiled(context))
2122 {
2123 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2124 return false;
2125 }
2126 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
2127
2128 if (!vertexShader || !vertexShader->isCompiled(context))
2129 {
2130 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2131 return false;
2132 }
2133 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
2134
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002135 int vertexShaderVersion = vertexShader->getShaderVersion(context);
2136 if (fragmentShader->getShaderVersion(context) != vertexShaderVersion)
Jiawei Shao73618602017-12-20 15:47:15 +08002137 {
2138 infoLog << "Fragment shader version does not match vertex shader version.";
2139 return false;
2140 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002141
2142 if (geometryShader)
2143 {
2144 // [GL_EXT_geometry_shader] Chapter 7
2145 // Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
2146 // Language Specification, as well as any of the following reasons:
2147 // * One or more of the shader objects attached to <program> are not compiled
2148 // successfully.
2149 // * The shaders do not use the same shader language version.
2150 // * <program> contains objects to form a geometry shader, and
2151 // - <program> is not separable and contains no objects to form a vertex shader; or
2152 // - the input primitive type, output primitive type, or maximum output vertex count
2153 // is not specified in the compiled geometry shader object.
2154 if (!geometryShader->isCompiled(context))
2155 {
2156 infoLog << "The attached geometry shader isn't compiled.";
2157 return false;
2158 }
2159
2160 if (geometryShader->getShaderVersion(context) != vertexShaderVersion)
2161 {
2162 mInfoLog << "Geometry shader version does not match vertex shader version.";
2163 return false;
2164 }
2165 ASSERT(geometryShader->getType() == GL_GEOMETRY_SHADER_EXT);
2166
2167 Optional<GLenum> inputPrimitive =
2168 geometryShader->getGeometryShaderInputPrimitiveType(context);
2169 if (!inputPrimitive.valid())
2170 {
2171 mInfoLog << "Input primitive type is not specified in the geometry shader.";
2172 return false;
2173 }
2174
2175 Optional<GLenum> outputPrimitive =
2176 geometryShader->getGeometryShaderOutputPrimitiveType(context);
2177 if (!outputPrimitive.valid())
2178 {
2179 mInfoLog << "Output primitive type is not specified in the geometry shader.";
2180 return false;
2181 }
2182
2183 Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices(context);
2184 if (!maxVertices.valid())
2185 {
2186 mInfoLog << "'max_vertices' is not specified in the geometry shader.";
2187 return false;
2188 }
2189
2190 mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
2191 mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
2192 mState.mGeometryShaderMaxVertices = maxVertices.value();
2193 mState.mGeometryShaderInvocations =
2194 geometryShader->getGeometryShaderInvocations(context);
2195 }
Jiawei Shao73618602017-12-20 15:47:15 +08002196 }
2197
2198 return true;
2199}
2200
jchen10910a3da2017-11-15 09:40:11 +08002201GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2202{
2203 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2204 {
2205 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2206 if (tf.nameWithArrayIndex() == name)
2207 {
2208 return tfIndex;
2209 }
2210 }
2211 return GL_INVALID_INDEX;
2212}
2213
2214const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2215{
2216 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2217 return mState.mLinkedTransformFeedbackVaryings[index];
2218}
2219
Jamie Madillbd044ed2017-06-05 12:59:21 -04002220bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002221{
Jiawei Shaod063aff2018-02-22 10:19:09 +08002222 std::vector<Shader *> activeShaders;
2223 activeShaders.push_back(mState.mAttachedVertexShader);
2224 if (mState.mAttachedGeometryShader)
2225 {
2226 activeShaders.push_back(mState.mAttachedGeometryShader);
2227 }
2228 activeShaders.push_back(mState.mAttachedFragmentShader);
Jamie Madill192745a2016-12-22 15:58:21 -05002229
Jiawei Shaod063aff2018-02-22 10:19:09 +08002230 const size_t activeShaderCount = activeShaders.size();
2231 for (size_t shaderIndex = 0; shaderIndex < activeShaderCount - 1; ++shaderIndex)
2232 {
2233 if (!linkValidateShaderInterfaceMatching(context, activeShaders[shaderIndex],
2234 activeShaders[shaderIndex + 1], infoLog))
2235 {
2236 return false;
2237 }
2238 }
2239
2240 if (!linkValidateBuiltInVaryings(context, infoLog))
2241 {
2242 return false;
2243 }
2244
2245 if (!linkValidateFragmentInputBindings(context, infoLog))
2246 {
2247 return false;
2248 }
2249
2250 return true;
2251}
2252
2253// [OpenGL ES 3.1] Chapter 7.4.1 "Shader Interface Matchining" Page 91
2254// TODO(jiawei.shao@intel.com): add validation on input/output blocks matching
2255bool Program::linkValidateShaderInterfaceMatching(const Context *context,
2256 gl::Shader *generatingShader,
2257 gl::Shader *consumingShader,
2258 gl::InfoLog &infoLog) const
2259{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002260 ASSERT(generatingShader->getShaderVersion(context) ==
2261 consumingShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002262
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002263 const std::vector<sh::Varying> &outputVaryings = generatingShader->getOutputVaryings(context);
2264 const std::vector<sh::Varying> &inputVaryings = consumingShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002265
Jiawei Shaod063aff2018-02-22 10:19:09 +08002266 bool validateGeometryShaderInputs = consumingShader->getType() == GL_GEOMETRY_SHADER_EXT;
Sami Väisänen46eaa942016-06-29 10:26:37 +03002267
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002268 for (const sh::Varying &input : inputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002269 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002270 bool matched = false;
2271
2272 // Built-in varyings obey special rules
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002273 if (input.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002274 {
2275 continue;
2276 }
2277
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002278 for (const sh::Varying &output : outputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002279 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002280 if (input.name == output.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002281 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002282 ASSERT(!output.isBuiltIn());
2283
2284 std::string mismatchedStructFieldName;
2285 LinkMismatchError linkError =
2286 LinkValidateVaryings(output, input, generatingShader->getShaderVersion(context),
Jiawei Shaod063aff2018-02-22 10:19:09 +08002287 validateGeometryShaderInputs, &mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002288 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002289 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002290 LogLinkMismatch(infoLog, input.name, "varying", linkError,
2291 mismatchedStructFieldName, generatingShader->getType(),
2292 consumingShader->getType());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002293 return false;
2294 }
2295
Geoff Lang7dd2e102014-11-10 15:19:26 -05002296 matched = true;
2297 break;
2298 }
2299 }
2300
2301 // We permit unmatched, unreferenced varyings
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002302 if (!matched && input.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002303 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002304 infoLog << GetShaderTypeString(consumingShader->getType()) << " varying " << input.name
2305 << " does not match any " << GetShaderTypeString(generatingShader->getType())
2306 << " varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002307 return false;
2308 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002309 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002310
Jiawei Shaod063aff2018-02-22 10:19:09 +08002311 // TODO(jmadill): verify no unmatched output varyings?
Sami Väisänen46eaa942016-06-29 10:26:37 +03002312
Jiawei Shaod063aff2018-02-22 10:19:09 +08002313 return true;
2314}
2315
2316bool Program::linkValidateFragmentInputBindings(const Context *context, gl::InfoLog &infoLog) const
2317{
2318 ASSERT(mState.mAttachedFragmentShader);
2319
2320 std::map<GLuint, std::string> staticFragmentInputLocations;
2321
2322 const std::vector<sh::Varying> &fragmentInputVaryings =
2323 mState.mAttachedFragmentShader->getInputVaryings(context);
2324 for (const sh::Varying &input : fragmentInputVaryings)
2325 {
2326 if (input.isBuiltIn() || !input.staticUse)
2327 {
Sami Väisänen46eaa942016-06-29 10:26:37 +03002328 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002329 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002330
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002331 const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
Sami Väisänen46eaa942016-06-29 10:26:37 +03002332 if (inputBinding == -1)
2333 continue;
2334
2335 const auto it = staticFragmentInputLocations.find(inputBinding);
2336 if (it == std::end(staticFragmentInputLocations))
2337 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002338 staticFragmentInputLocations.insert(std::make_pair(inputBinding, input.name));
Sami Väisänen46eaa942016-06-29 10:26:37 +03002339 }
2340 else
2341 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002342 infoLog << "Binding for fragment input " << input.name << " conflicts with "
Sami Väisänen46eaa942016-06-29 10:26:37 +03002343 << it->second;
2344 return false;
2345 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002346 }
2347
2348 return true;
2349}
2350
Jamie Madillbd044ed2017-06-05 12:59:21 -04002351bool Program::linkUniforms(const Context *context,
2352 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002353 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002354{
Olli Etuahob78707c2017-03-09 15:03:11 +00002355 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002356 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002357 {
2358 return false;
2359 }
2360
Olli Etuahob78707c2017-03-09 15:03:11 +00002361 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002362
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002363 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002364
jchen10eaef1e52017-06-13 10:44:11 +08002365 if (!linkAtomicCounterBuffers())
2366 {
2367 return false;
2368 }
2369
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002370 return true;
2371}
2372
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002373void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002374{
Jamie Madill982f6e02017-06-07 14:33:04 -04002375 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2376 unsigned int low = high;
2377
jchen10eaef1e52017-06-13 10:44:11 +08002378 for (auto counterIter = mState.mUniforms.rbegin();
2379 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2380 {
2381 --low;
2382 }
2383
2384 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2385
2386 high = low;
2387
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002388 for (auto imageIter = mState.mUniforms.rbegin();
2389 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2390 {
2391 --low;
2392 }
2393
2394 mState.mImageUniformRange = RangeUI(low, high);
2395
2396 // If uniform is a image type, insert it into the mImageBindings array.
2397 for (unsigned int imageIndex : mState.mImageUniformRange)
2398 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002399 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2400 // cannot load values into a uniform defined as an image. if declare without a
2401 // binding qualifier, any uniform image variable (include all elements of
2402 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002403 auto &imageUniform = mState.mUniforms[imageIndex];
2404 if (imageUniform.binding == -1)
2405 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002406 mState.mImageBindings.emplace_back(
2407 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002408 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002409 else
2410 {
2411 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002412 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002413 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002414 }
2415
2416 high = low;
2417
2418 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002419 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002420 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002421 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002422 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002423
2424 mState.mSamplerUniformRange = RangeUI(low, high);
2425
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002426 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002427 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002428 {
2429 const auto &samplerUniform = mState.mUniforms[samplerIndex];
Corentin Wallezf0e89be2017-11-08 14:00:32 -08002430 TextureType textureType = SamplerTypeToTextureType(samplerUniform.type);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002431 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002432 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002433 }
2434}
2435
jchen10eaef1e52017-06-13 10:44:11 +08002436bool Program::linkAtomicCounterBuffers()
2437{
2438 for (unsigned int index : mState.mAtomicCounterUniformRange)
2439 {
2440 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002441 uniform.blockInfo.offset = uniform.offset;
2442 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2443 uniform.blockInfo.matrixStride = 0;
2444 uniform.blockInfo.isRowMajorMatrix = false;
2445
jchen10eaef1e52017-06-13 10:44:11 +08002446 bool found = false;
2447 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2448 ++bufferIndex)
2449 {
2450 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2451 if (buffer.binding == uniform.binding)
2452 {
2453 buffer.memberIndexes.push_back(index);
2454 uniform.bufferIndex = bufferIndex;
2455 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002456 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002457 break;
2458 }
2459 }
2460 if (!found)
2461 {
2462 AtomicCounterBuffer atomicCounterBuffer;
2463 atomicCounterBuffer.binding = uniform.binding;
2464 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002465 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002466 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2467 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2468 }
2469 }
2470 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
Jiawei Shao0d88ec92018-02-27 16:25:31 +08002471 // gl_Max[Vertex|Fragment|Compute|Geometry|Combined]AtomicCounterBuffers.
jchen10eaef1e52017-06-13 10:44:11 +08002472
2473 return true;
2474}
2475
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002476LinkMismatchError Program::LinkValidateInterfaceBlockFields(
2477 const sh::InterfaceBlockField &blockField1,
2478 const sh::InterfaceBlockField &blockField2,
2479 bool webglCompatibility,
2480 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002481{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002482 if (blockField1.name != blockField2.name)
2483 {
2484 return LinkMismatchError::FIELD_NAME_MISMATCH;
2485 }
2486
Frank Henigmanfccbac22017-05-28 17:29:26 -04002487 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002488 LinkMismatchError linkError = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08002489 blockField1, blockField2, webglCompatibility, true, mismatchedBlockFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002490 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002491 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002492 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2493 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002494 }
2495
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002496 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002497 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002498 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2499 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002500 }
2501
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002502 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002503}
2504
Jamie Madilleb979bf2016-11-15 12:28:46 -05002505// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002506bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002507{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002508 const ContextState &data = context->getContextState();
2509 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002510
Geoff Lang7dd2e102014-11-10 15:19:26 -05002511 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002512 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002513 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002514
2515 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002516 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002517 {
Jamie Madillf6113162015-05-07 11:49:21 -04002518 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002519 return false;
2520 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002521
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002522 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002523
Jamie Madillc349ec02015-08-21 16:53:12 -04002524 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002525 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002526 {
Olli Etuahod2551232017-10-26 20:03:33 +03002527 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2528 // structures, so we don't need to worry about adjusting their names or generating entries
2529 // for each member/element (unlike uniforms for example).
2530 ASSERT(!attribute.isArray() && !attribute.isStruct());
2531
Jamie Madilleb979bf2016-11-15 12:28:46 -05002532 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002533 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002534 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002535 attribute.location = bindingLocation;
2536 }
2537
2538 if (attribute.location != -1)
2539 {
2540 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002541 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002542
Jamie Madill63805b42015-08-25 13:17:39 -04002543 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002544 {
Jamie Madillf6113162015-05-07 11:49:21 -04002545 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002546 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002547
2548 return false;
2549 }
2550
Jamie Madill63805b42015-08-25 13:17:39 -04002551 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002552 {
Jamie Madill63805b42015-08-25 13:17:39 -04002553 const int regLocation = attribute.location + reg;
2554 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002555
2556 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002557 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002558 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002559 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002560 // TODO(jmadill): fix aliasing on ES2
2561 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002562 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002563 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002564 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002565 return false;
2566 }
2567 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002568 else
2569 {
Jamie Madill63805b42015-08-25 13:17:39 -04002570 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002571 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002572
Jamie Madill63805b42015-08-25 13:17:39 -04002573 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002574 }
2575 }
2576 }
2577
2578 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002579 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002580 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002581 // Not set by glBindAttribLocation or by location layout qualifier
2582 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002583 {
Jamie Madill63805b42015-08-25 13:17:39 -04002584 int regs = VariableRegisterCount(attribute.type);
2585 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002586
Jamie Madill63805b42015-08-25 13:17:39 -04002587 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002588 {
Jamie Madillf6113162015-05-07 11:49:21 -04002589 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002590 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002591 }
2592
Jamie Madillc349ec02015-08-21 16:53:12 -04002593 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002594 }
2595 }
2596
Brandon Jonesc405ae72017-12-06 14:15:03 -08002597 ASSERT(mState.mAttributesTypeMask.none());
2598 ASSERT(mState.mAttributesMask.none());
2599
Jamie Madill48ef11b2016-04-27 15:21:52 -04002600 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002601 {
Jamie Madill63805b42015-08-25 13:17:39 -04002602 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002603 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002604
Jamie Madillbd159f02017-10-09 19:39:06 -04002605 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002606 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002607 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2608 mState.mActiveAttribLocationsMask.set(location);
2609 mState.mMaxActiveAttribLocation =
2610 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08002611
2612 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
2613 if (!attribute.isBuiltIn())
2614 {
2615 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
2616 location);
2617 mState.mAttributesMask.set(location);
2618 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002619 }
2620 }
2621
Geoff Lang7dd2e102014-11-10 15:19:26 -05002622 return true;
2623}
2624
Jiawei Shao73618602017-12-20 15:47:15 +08002625bool Program::ValidateGraphicsInterfaceBlocks(
Martin Radev4c4c8e72016-08-04 12:25:34 +03002626 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2627 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002628 InfoLog &infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002629 bool webglCompatibility,
2630 sh::BlockType blockType,
2631 GLuint maxCombinedInterfaceBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002632{
2633 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002634 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2635 InterfaceBlockMap linkedInterfaceBlocks;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002636 GLuint blockCount = 0;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002637
2638 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2639 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002640 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002641 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2642 {
2643 blockCount += std::max(vertexInterfaceBlock.arraySize, 1u);
2644 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002645 }
2646
Jamie Madille473dee2015-08-18 14:49:01 -04002647 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002648 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002649 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2650 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002651 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002652 const sh::InterfaceBlock &vertexInterfaceBlock = *(entry->second);
2653 std::string mismatchedBlockFieldName;
2654 LinkMismatchError linkError =
2655 AreMatchingInterfaceBlocks(vertexInterfaceBlock, fragmentInterfaceBlock,
2656 webglCompatibility, &mismatchedBlockFieldName);
2657 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002658 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002659 LogLinkMismatch(infoLog, fragmentInterfaceBlock.name, "interface block", linkError,
2660 mismatchedBlockFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002661 return false;
2662 }
2663 }
Jiawei Shaod2cb7ce2018-03-02 09:04:03 +08002664
2665 // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
2666 // If a uniform block is used by multiple shader stages, each such use counts separately
2667 // against this combined limit.
2668 // [OpenGL ES 3.1] Chapter 7.8 Page 111:
2669 // If a shader storage block in a program is referenced by multiple shaders, each such
2670 // reference counts separately against this combined limit.
2671 if (fragmentInterfaceBlock.staticUse ||
2672 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Jiajia Qin8efd1262017-12-19 09:32:55 +08002673 {
Jiawei Shaod2cb7ce2018-03-02 09:04:03 +08002674 blockCount += std::max(fragmentInterfaceBlock.arraySize, 1u);
Jiajia Qin8efd1262017-12-19 09:32:55 +08002675 }
2676 }
2677
2678 if (blockCount > maxCombinedInterfaceBlocks)
2679 {
2680 switch (blockType)
2681 {
2682 case sh::BlockType::BLOCK_UNIFORM:
2683 infoLog << "The sum of the number of active uniform blocks exceeds "
2684 "MAX_COMBINED_UNIFORM_BLOCKS ("
2685 << maxCombinedInterfaceBlocks << ").";
2686 break;
2687 case sh::BlockType::BLOCK_BUFFER:
2688 infoLog << "The sum of the number of active shader storage blocks exceeds "
2689 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2690 << maxCombinedInterfaceBlocks << ").";
2691 break;
2692 default:
2693 UNREACHABLE();
2694 }
2695 return false;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002696 }
2697 return true;
2698}
Jamie Madille473dee2015-08-18 14:49:01 -04002699
Jiajia Qin729b2c62017-08-14 09:36:11 +08002700bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002701{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002702 const auto &caps = context->getCaps();
2703
Martin Radev4c4c8e72016-08-04 12:25:34 +03002704 if (mState.mAttachedComputeShader)
2705 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002706 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002707 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002708
Jiajia Qin729b2c62017-08-14 09:36:11 +08002709 if (!validateInterfaceBlocksCount(
2710 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002711 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2712 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002713 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002714 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002715 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002716
2717 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2718 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2719 computeShaderStorageBlocks,
2720 "Compute shader shader storage block count exceeds "
2721 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2722 infoLog))
2723 {
2724 return false;
2725 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002726 return true;
2727 }
2728
Jamie Madillbd044ed2017-06-05 12:59:21 -04002729 Shader &vertexShader = *mState.mAttachedVertexShader;
2730 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002731
Jiajia Qin729b2c62017-08-14 09:36:11 +08002732 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2733 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002734
Jiajia Qin729b2c62017-08-14 09:36:11 +08002735 if (!validateInterfaceBlocksCount(
2736 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002737 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2738 {
2739 return false;
2740 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002741 if (!validateInterfaceBlocksCount(
2742 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002743 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2744 infoLog))
2745 {
2746
2747 return false;
2748 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002749
2750 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiawei Shao73618602017-12-20 15:47:15 +08002751 if (!ValidateGraphicsInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002752 webglCompatibility, sh::BlockType::BLOCK_UNIFORM,
2753 caps.maxCombinedUniformBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002754 {
2755 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002756 }
Jamie Madille473dee2015-08-18 14:49:01 -04002757
Jiajia Qin729b2c62017-08-14 09:36:11 +08002758 if (context->getClientVersion() >= Version(3, 1))
2759 {
2760 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2761 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2762
2763 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2764 vertexShaderStorageBlocks,
2765 "Vertex shader shader storage block count exceeds "
2766 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2767 infoLog))
2768 {
2769 return false;
2770 }
2771 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2772 fragmentShaderStorageBlocks,
2773 "Fragment shader shader storage block count exceeds "
2774 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2775 infoLog))
2776 {
2777
2778 return false;
2779 }
2780
Jiajia Qin8efd1262017-12-19 09:32:55 +08002781 if (!ValidateGraphicsInterfaceBlocks(
2782 vertexShaderStorageBlocks, fragmentShaderStorageBlocks, infoLog, webglCompatibility,
2783 sh::BlockType::BLOCK_BUFFER, caps.maxCombinedShaderStorageBlocks))
Jiajia Qin729b2c62017-08-14 09:36:11 +08002784 {
2785 return false;
2786 }
2787 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002788 return true;
2789}
2790
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002791LinkMismatchError Program::AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2792 const sh::InterfaceBlock &interfaceBlock2,
2793 bool webglCompatibility,
2794 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002795{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002796 // validate blocks for the same member types
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002797 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002798 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002799 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002800 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002801 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002802 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002803 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002804 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002805 if (interfaceBlock1.layout != interfaceBlock2.layout ||
2806 interfaceBlock1.binding != interfaceBlock2.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002807 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002808 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002809 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002810 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002811 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2812 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002813 const sh::InterfaceBlockField &member1 = interfaceBlock1.fields[blockMemberIndex];
2814 const sh::InterfaceBlockField &member2 = interfaceBlock2.fields[blockMemberIndex];
2815
2816 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2817 member1, member2, webglCompatibility, mismatchedBlockFieldName);
2818 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002819 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002820 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002821 }
2822 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002823 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002824}
2825
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002826LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &variable1,
2827 const sh::ShaderVariable &variable2,
2828 bool validatePrecision,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002829 bool validateArraySize,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002830 std::string *mismatchedStructOrBlockMemberName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002831{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002832 if (variable1.type != variable2.type)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002833 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002834 return LinkMismatchError::TYPE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002835 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002836 if (validateArraySize && variable1.arraySizes != variable2.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002837 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002838 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002839 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002840 if (validatePrecision && variable1.precision != variable2.precision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002841 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002842 return LinkMismatchError::PRECISION_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002843 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002844 if (variable1.structName != variable2.structName)
Geoff Langbb1e7502017-06-05 16:40:09 -04002845 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002846 return LinkMismatchError::STRUCT_NAME_MISMATCH;
Geoff Langbb1e7502017-06-05 16:40:09 -04002847 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002848
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002849 if (variable1.fields.size() != variable2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002850 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002851 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002852 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002853 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002854 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2855 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002856 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2857 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002858
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002859 if (member1.name != member2.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002860 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002861 return LinkMismatchError::FIELD_NAME_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002862 }
2863
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002864 LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08002865 member1, member2, validatePrecision, true, mismatchedStructOrBlockMemberName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002866 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002867 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002868 AddParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2869 return linkErrorOnField;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002870 }
2871 }
2872
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002873 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002874}
2875
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002876LinkMismatchError Program::LinkValidateVaryings(const sh::Varying &outputVarying,
2877 const sh::Varying &inputVarying,
2878 int shaderVersion,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002879 bool validateGeometryShaderInputVarying,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002880 std::string *mismatchedStructFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002881{
Jiawei Shaod063aff2018-02-22 10:19:09 +08002882 if (validateGeometryShaderInputVarying)
2883 {
2884 // [GL_EXT_geometry_shader] Section 11.1gs.4.3:
2885 // The OpenGL ES Shading Language doesn't support multi-dimensional arrays as shader inputs
2886 // or outputs.
2887 ASSERT(inputVarying.arraySizes.size() == 1u);
2888
2889 // Geometry shader input varyings are not treated as arrays, so a vertex array output
2890 // varying cannot match a geometry shader input varying.
2891 // [GL_EXT_geometry_shader] Section 7.4.1:
2892 // Geometry shader per-vertex input variables and blocks are required to be declared as
2893 // arrays, with each element representing input or output values for a single vertex of a
2894 // multi-vertex primitive. For the purposes of interface matching, such variables and blocks
2895 // are treated as though they were not declared as arrays.
2896 if (outputVarying.isArray())
2897 {
2898 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2899 }
2900 }
2901
2902 // Skip the validation on the array sizes between a vertex output varying and a geometry input
2903 // varying as it has been done before.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002904 LinkMismatchError linkError =
Jiawei Shaod063aff2018-02-22 10:19:09 +08002905 LinkValidateVariablesBase(outputVarying, inputVarying, false,
2906 !validateGeometryShaderInputVarying, mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002907 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002908 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002909 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002910 }
2911
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002912 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002913 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002914 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002915 }
2916
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002917 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002918 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002919 return LinkMismatchError::INVARIANCE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002920 }
2921
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002922 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002923}
2924
Jamie Madillbd044ed2017-06-05 12:59:21 -04002925bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002926{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002927 Shader *vertexShader = mState.mAttachedVertexShader;
2928 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002929 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2930 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002931 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002932
2933 if (shaderVersion != 100)
2934 {
2935 // Only ESSL 1.0 has restrictions on matching input and output invariance
2936 return true;
2937 }
2938
2939 bool glPositionIsInvariant = false;
2940 bool glPointSizeIsInvariant = false;
2941 bool glFragCoordIsInvariant = false;
2942 bool glPointCoordIsInvariant = false;
2943
2944 for (const sh::Varying &varying : vertexVaryings)
2945 {
2946 if (!varying.isBuiltIn())
2947 {
2948 continue;
2949 }
2950 if (varying.name.compare("gl_Position") == 0)
2951 {
2952 glPositionIsInvariant = varying.isInvariant;
2953 }
2954 else if (varying.name.compare("gl_PointSize") == 0)
2955 {
2956 glPointSizeIsInvariant = varying.isInvariant;
2957 }
2958 }
2959
2960 for (const sh::Varying &varying : fragmentVaryings)
2961 {
2962 if (!varying.isBuiltIn())
2963 {
2964 continue;
2965 }
2966 if (varying.name.compare("gl_FragCoord") == 0)
2967 {
2968 glFragCoordIsInvariant = varying.isInvariant;
2969 }
2970 else if (varying.name.compare("gl_PointCoord") == 0)
2971 {
2972 glPointCoordIsInvariant = varying.isInvariant;
2973 }
2974 }
2975
2976 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2977 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2978 // Not requiring invariance to match is supported by:
2979 // dEQP, WebGL CTS, Nexus 5X GLES
2980 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2981 {
2982 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2983 "declared invariant.";
2984 return false;
2985 }
2986 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2987 {
2988 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2989 "declared invariant.";
2990 return false;
2991 }
2992
2993 return true;
2994}
2995
jchen10a9042d32017-03-17 08:50:45 +08002996bool Program::linkValidateTransformFeedback(const gl::Context *context,
2997 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002998 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002999 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05003000{
Geoff Lang7dd2e102014-11-10 15:19:26 -05003001
jchen108225e732017-11-14 16:29:03 +08003002 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04003003 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04003004 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003005 {
jchen10a9042d32017-03-17 08:50:45 +08003006 if (context->getClientVersion() < Version(3, 1) &&
3007 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04003008 {
Geoff Lang1a683462015-09-29 15:09:59 -04003009 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04003010 return false;
3011 }
jchen108225e732017-11-14 16:29:03 +08003012 if (context->getClientVersion() >= Version(3, 1))
3013 {
3014 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
3015 {
3016 infoLog << "Two transform feedback varyings include the same array element ("
3017 << tfVaryingName << ").";
3018 return false;
3019 }
3020 }
3021 else
3022 {
3023 if (uniqueNames.count(tfVaryingName) > 0)
3024 {
3025 infoLog << "Two transform feedback varyings specify the same output variable ("
3026 << tfVaryingName << ").";
3027 return false;
3028 }
3029 }
3030 uniqueNames.insert(tfVaryingName);
3031 }
3032
3033 // Validate against program varyings.
3034 size_t totalComponents = 0;
3035 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
3036 {
3037 std::vector<unsigned int> subscripts;
3038 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
3039
3040 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
3041 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08003042 {
3043 infoLog << "Transform feedback varying " << tfVaryingName
3044 << " does not exist in the vertex shader.";
3045 return false;
3046 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003047
jchen108225e732017-11-14 16:29:03 +08003048 // Validate the matching variable.
3049 if (var->isStruct())
3050 {
3051 infoLog << "Struct cannot be captured directly (" << baseName << ").";
3052 return false;
3053 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003054
jchen108225e732017-11-14 16:29:03 +08003055 size_t elementCount = 0;
3056 size_t componentCount = 0;
3057
3058 if (var->isArray())
3059 {
3060 if (context->getClientVersion() < Version(3, 1))
3061 {
3062 infoLog << "Capture of arrays is undefined and not supported.";
3063 return false;
3064 }
3065
3066 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
3067 ASSERT(!var->isArrayOfArrays());
3068
3069 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
3070 {
3071 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
3072 return false;
3073 }
3074 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
3075 }
3076 else
3077 {
3078 if (!subscripts.empty())
3079 {
3080 infoLog << "Varying '" << baseName
3081 << "' is not an array to be captured by element.";
3082 return false;
3083 }
3084 elementCount = 1;
3085 }
3086
3087 // TODO(jmadill): Investigate implementation limits on D3D11
3088 componentCount = VariableComponentCount(var->type) * elementCount;
3089 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
3090 componentCount > caps.maxTransformFeedbackSeparateComponents)
3091 {
3092 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
3093 << componentCount << ") exceed the maximum separate components ("
3094 << caps.maxTransformFeedbackSeparateComponents << ").";
3095 return false;
3096 }
3097
3098 totalComponents += componentCount;
3099 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
3100 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
3101 {
3102 infoLog << "Transform feedback varying total components (" << totalComponents
3103 << ") exceed the maximum interleaved components ("
3104 << caps.maxTransformFeedbackInterleavedComponents << ").";
3105 return false;
3106 }
3107 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003108 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05003109}
3110
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003111bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
3112{
3113 const std::vector<sh::Uniform> &vertexUniforms =
3114 mState.mAttachedVertexShader->getUniforms(context);
3115 const std::vector<sh::Uniform> &fragmentUniforms =
3116 mState.mAttachedFragmentShader->getUniforms(context);
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003117 const std::vector<sh::Uniform> *geometryUniforms =
3118 (mState.mAttachedGeometryShader) ? &mState.mAttachedGeometryShader->getUniforms(context)
3119 : nullptr;
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003120 const std::vector<sh::Attribute> &attributes =
3121 mState.mAttachedVertexShader->getActiveAttributes(context);
3122 for (const auto &attrib : attributes)
3123 {
3124 for (const auto &uniform : vertexUniforms)
3125 {
3126 if (uniform.name == attrib.name)
3127 {
3128 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3129 return false;
3130 }
3131 }
3132 for (const auto &uniform : fragmentUniforms)
3133 {
3134 if (uniform.name == attrib.name)
3135 {
3136 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3137 return false;
3138 }
3139 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003140 if (geometryUniforms)
3141 {
3142 for (const auto &uniform : *geometryUniforms)
3143 {
3144 if (uniform.name == attrib.name)
3145 {
3146 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3147 return false;
3148 }
3149 }
3150 }
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003151 }
3152 return true;
3153}
3154
Jamie Madill3c1da042017-11-27 18:33:40 -05003155void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003156{
3157 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08003158 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04003159 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003160 {
Olli Etuahoc8538042017-09-27 11:20:15 +03003161 std::vector<unsigned int> subscripts;
3162 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08003163 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03003164 if (!subscripts.empty())
3165 {
3166 subscript = subscripts.back();
3167 }
Jamie Madill192745a2016-12-22 15:58:21 -05003168 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003169 {
Jamie Madill192745a2016-12-22 15:58:21 -05003170 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08003171 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003172 {
jchen10a9042d32017-03-17 08:50:45 +08003173 mState.mLinkedTransformFeedbackVaryings.emplace_back(
3174 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04003175 break;
3176 }
jchen108225e732017-11-14 16:29:03 +08003177 else if (varying->isStruct())
3178 {
3179 const auto *field = FindShaderVarField(*varying, tfVaryingName);
3180 if (field != nullptr)
3181 {
3182 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
3183 break;
3184 }
3185 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04003186 }
3187 }
3188}
3189
Jamie Madill3c1da042017-11-27 18:33:40 -05003190ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04003191{
Jamie Madill3c1da042017-11-27 18:33:40 -05003192 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003193
Jiawei Shao3d404882017-10-16 13:30:48 +08003194 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003195 {
Jamie Madill192745a2016-12-22 15:58:21 -05003196 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003197 }
3198
Jiawei Shao3d404882017-10-16 13:30:48 +08003199 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003200 {
Jamie Madill192745a2016-12-22 15:58:21 -05003201 merged[varying.name].fragment = &varying;
3202 }
3203
3204 return merged;
3205}
3206
Jamie Madillbd044ed2017-06-05 12:59:21 -04003207void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003208{
Jamie Madillbd044ed2017-06-05 12:59:21 -04003209 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003210 ASSERT(fragmentShader != nullptr);
3211
Geoff Lange0cff192017-05-30 13:04:56 -04003212 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04003213 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08003214 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04003215
3216 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04003217 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04003218 {
3219 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
3220 outputVariable.name != "gl_FragData")
3221 {
3222 continue;
3223 }
3224
3225 unsigned int baseLocation =
3226 (outputVariable.location == -1 ? 0u
3227 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03003228
3229 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3230 // structures, so we may use getBasicTypeElementCount().
3231 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3232 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04003233 {
3234 const unsigned int location = baseLocation + elementIndex;
3235 if (location >= mState.mOutputVariableTypes.size())
3236 {
3237 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
3238 }
Corentin Walleze7557742017-06-01 13:09:57 -04003239 ASSERT(location < mState.mActiveOutputVariables.size());
3240 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04003241 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08003242 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04003243 }
3244 }
3245
Jamie Madill80a6fc02015-08-21 16:53:16 -04003246 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04003247 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003248 return;
3249
Jamie Madillbd044ed2017-06-05 12:59:21 -04003250 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04003251 // TODO(jmadill): any caps validation here?
3252
jchen1015015f72017-03-16 13:54:21 +08003253 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04003254 outputVariableIndex++)
3255 {
jchen1015015f72017-03-16 13:54:21 +08003256 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003257
Olli Etuahod2551232017-10-26 20:03:33 +03003258 if (outputVariable.isArray())
3259 {
3260 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
3261 // Resources and including [0] at the end of array variable names.
3262 mState.mOutputVariables[outputVariableIndex].name += "[0]";
3263 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
3264 }
3265
Jamie Madill80a6fc02015-08-21 16:53:16 -04003266 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3267 if (outputVariable.isBuiltIn())
3268 continue;
3269
3270 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03003271 unsigned int baseLocation =
3272 (outputVariable.location == -1 ? 0u
3273 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04003274
Olli Etuaho465835d2017-09-26 13:34:10 +03003275 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3276 // structures, so we may use getBasicTypeElementCount().
3277 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3278 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003279 {
Olli Etuahod2551232017-10-26 20:03:33 +03003280 const unsigned int location = baseLocation + elementIndex;
3281 if (location >= mState.mOutputLocations.size())
3282 {
3283 mState.mOutputLocations.resize(location + 1);
3284 }
3285 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03003286 if (outputVariable.isArray())
3287 {
3288 mState.mOutputLocations[location] =
3289 VariableLocation(elementIndex, outputVariableIndex);
3290 }
3291 else
3292 {
3293 VariableLocation locationInfo;
3294 locationInfo.index = outputVariableIndex;
3295 mState.mOutputLocations[location] = locationInfo;
3296 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003297 }
3298 }
3299}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003300
Olli Etuaho48fed632017-03-16 12:05:30 +00003301void Program::setUniformValuesFromBindingQualifiers()
3302{
Jamie Madill982f6e02017-06-07 14:33:04 -04003303 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003304 {
3305 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3306 if (samplerUniform.binding != -1)
3307 {
Olli Etuahod2551232017-10-26 20:03:33 +03003308 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003309 ASSERT(location != -1);
3310 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003311 for (unsigned int elementIndex = 0;
3312 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003313 {
3314 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3315 }
3316 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3317 boundTextureUnits.data());
3318 }
3319 }
3320}
3321
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003322void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003323{
jchen10af713a22017-04-19 09:10:56 +08003324 // Set initial bindings from shader.
3325 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3326 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003327 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003328 bindUniformBlock(blockIndex, uniformBlock.binding);
3329 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003330}
3331
Jamie Madille7d84322017-01-10 18:21:59 -05003332void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003333 GLsizei clampedCount,
3334 const GLint *v)
3335{
Jamie Madill81c2e252017-09-09 23:32:46 -04003336 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3337 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3338 std::vector<GLuint> *boundTextureUnits =
3339 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003340
Olli Etuaho1734e172017-10-27 15:30:27 +03003341 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04003342
3343 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003344 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003345}
3346
3347template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003348GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3349 GLsizei count,
3350 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003351 const T *v)
3352{
Jamie Madill134f93d2017-08-31 17:11:00 -04003353 if (count == 1)
3354 return 1;
3355
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003356 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003357
Corentin Wallez15ac5342016-11-03 17:06:39 -04003358 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3359 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003360 unsigned int remainingElements =
3361 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003362 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003363 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003364
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003365 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003366 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003367 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003368 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003369
3370 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003371}
3372
3373template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003374GLsizei Program::clampMatrixUniformCount(GLint location,
3375 GLsizei count,
3376 GLboolean transpose,
3377 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003378{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003379 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3380
Jamie Madill62d31cb2015-09-11 13:25:51 -04003381 if (!transpose)
3382 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003383 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003384 }
3385
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003386 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003387
3388 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3389 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003390 unsigned int remainingElements =
3391 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003392 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003393}
3394
Jamie Madill54164b02017-08-28 15:17:37 -04003395// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3396// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003397template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003398void Program::getUniformInternal(const Context *context,
3399 DestT *dataOut,
3400 GLint location,
3401 GLenum nativeType,
3402 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003403{
Jamie Madill54164b02017-08-28 15:17:37 -04003404 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003405 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003406 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003407 {
3408 GLint tempValue[16] = {0};
3409 mProgram->getUniformiv(context, location, tempValue);
3410 UniformStateQueryCastLoop<GLboolean>(
3411 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003412 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003413 }
3414 case GL_INT:
3415 {
3416 GLint tempValue[16] = {0};
3417 mProgram->getUniformiv(context, location, tempValue);
3418 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3419 components);
3420 break;
3421 }
3422 case GL_UNSIGNED_INT:
3423 {
3424 GLuint tempValue[16] = {0};
3425 mProgram->getUniformuiv(context, location, tempValue);
3426 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3427 components);
3428 break;
3429 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003430 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003431 {
3432 GLfloat tempValue[16] = {0};
3433 mProgram->getUniformfv(context, location, tempValue);
3434 UniformStateQueryCastLoop<GLfloat>(
3435 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003436 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003437 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003438 default:
3439 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003440 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003441 }
3442}
Jamie Madilla4595b82017-01-11 17:36:34 -05003443
3444bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3445{
3446 // Must be called after samplers are validated.
3447 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3448
3449 for (const auto &binding : mState.mSamplerBindings)
3450 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08003451 TextureType textureType = binding.textureType;
Jamie Madilla4595b82017-01-11 17:36:34 -05003452 for (const auto &unit : binding.boundTextureUnits)
3453 {
3454 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3455 if (programTextureID == textureID)
3456 {
3457 // TODO(jmadill): Check for appropriate overlap.
3458 return true;
3459 }
3460 }
3461 }
3462
3463 return false;
3464}
3465
Jamie Madilla2c74982016-12-12 11:20:42 -05003466} // namespace gl