blob: 85f809e7f0513a24701e13439e0a9796b067b0b2 [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
Jiawei Shao427071e2018-03-19 09:21:37 +0800208bool ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
Jiajia Qin729b2c62017-08-14 09:36:11 +0800209 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 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200216 if (block.active || block.layout != sh::BLOCKLAYOUT_PACKED)
Jiajia Qin729b2c62017-08-14 09:36:11 +0800217 {
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{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800280 for (ShaderType shaderType : AllShaderTypes())
Jamie Madillc9727f32017-11-07 12:37:07 -0500281 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800282 Shader *shader = state.getAttachedShader(shaderType);
283 if (shader)
284 {
285 blockLinker->addShaderBlocks(shaderType, &shader->getUniformBlocks(context));
286 }
Jamie Madillc9727f32017-11-07 12:37:07 -0500287 }
288}
289
290void InitShaderStorageBlockLinker(const gl::Context *context,
291 const ProgramState &state,
292 ShaderStorageBlockLinker *blockLinker)
293{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800294 for (ShaderType shaderType : AllShaderTypes())
Jamie Madillc9727f32017-11-07 12:37:07 -0500295 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800296 Shader *shader = state.getAttachedShader(shaderType);
297 if (shader != nullptr)
298 {
299 blockLinker->addShaderBlocks(shaderType, &shader->getShaderStorageBlocks(context));
300 }
Jamie Madillc9727f32017-11-07 12:37:07 -0500301 }
302}
303
jchen108225e732017-11-14 16:29:03 +0800304// Find the matching varying or field by name.
305const sh::ShaderVariable *FindVaryingOrField(const ProgramMergedVaryings &varyings,
306 const std::string &name)
307{
308 const sh::ShaderVariable *var = nullptr;
309 for (const auto &ref : varyings)
310 {
311 const sh::Varying *varying = ref.second.get();
312 if (varying->name == name)
313 {
314 var = varying;
315 break;
316 }
317 var = FindShaderVarField(*varying, name);
318 if (var != nullptr)
319 {
320 break;
321 }
322 }
323 return var;
324}
325
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800326void AddParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
327{
328 ASSERT(mismatchedFieldName);
329 if (mismatchedFieldName->empty())
330 {
331 *mismatchedFieldName = parentName;
332 }
333 else
334 {
335 std::ostringstream stream;
336 stream << parentName << "." << *mismatchedFieldName;
337 *mismatchedFieldName = stream.str();
338 }
339}
340
341const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
342{
343 switch (linkError)
344 {
345 case LinkMismatchError::TYPE_MISMATCH:
346 return "Type";
347 case LinkMismatchError::ARRAY_SIZE_MISMATCH:
348 return "Array size";
349 case LinkMismatchError::PRECISION_MISMATCH:
350 return "Precision";
351 case LinkMismatchError::STRUCT_NAME_MISMATCH:
352 return "Structure name";
353 case LinkMismatchError::FIELD_NUMBER_MISMATCH:
354 return "Field number";
355 case LinkMismatchError::FIELD_NAME_MISMATCH:
356 return "Field name";
357
358 case LinkMismatchError::INTERPOLATION_TYPE_MISMATCH:
359 return "Interpolation type";
360 case LinkMismatchError::INVARIANCE_MISMATCH:
361 return "Invariance";
362
363 case LinkMismatchError::BINDING_MISMATCH:
364 return "Binding layout qualifier";
365 case LinkMismatchError::LOCATION_MISMATCH:
366 return "Location layout qualifier";
367 case LinkMismatchError::OFFSET_MISMATCH:
368 return "Offset layout qualilfier";
369
370 case LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH:
371 return "Layout qualifier";
372 case LinkMismatchError::MATRIX_PACKING_MISMATCH:
373 return "Matrix Packing";
374 default:
375 UNREACHABLE();
376 return "";
377 }
378}
379
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800380LinkMismatchError LinkValidateInterfaceBlockFields(const sh::InterfaceBlockField &blockField1,
381 const sh::InterfaceBlockField &blockField2,
382 bool webglCompatibility,
383 std::string *mismatchedBlockFieldName)
384{
385 if (blockField1.name != blockField2.name)
386 {
387 return LinkMismatchError::FIELD_NAME_MISMATCH;
388 }
389
390 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
391 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
392 blockField1, blockField2, webglCompatibility, true, mismatchedBlockFieldName);
393 if (linkError != LinkMismatchError::NO_MISMATCH)
394 {
395 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
396 return linkError;
397 }
398
399 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
400 {
401 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
402 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
403 }
404
405 return LinkMismatchError::NO_MISMATCH;
406}
407
408LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
409 const sh::InterfaceBlock &interfaceBlock2,
410 bool webglCompatibility,
411 std::string *mismatchedBlockFieldName)
412{
413 // validate blocks for the same member types
414 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
415 {
416 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
417 }
418 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
419 {
420 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
421 }
422 if (interfaceBlock1.layout != interfaceBlock2.layout ||
423 interfaceBlock1.binding != interfaceBlock2.binding)
424 {
425 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
426 }
427 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
428 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
429 {
430 const sh::InterfaceBlockField &member1 = interfaceBlock1.fields[blockMemberIndex];
431 const sh::InterfaceBlockField &member2 = interfaceBlock2.fields[blockMemberIndex];
432
433 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
434 member1, member2, webglCompatibility, mismatchedBlockFieldName);
435 if (linkError != LinkMismatchError::NO_MISMATCH)
436 {
437 return linkError;
438 }
439 }
440 return LinkMismatchError::NO_MISMATCH;
441}
442
443bool ValidateGraphicsInterfaceBlocks(const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
444 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
445 InfoLog &infoLog,
446 bool webglCompatibility,
447 sh::BlockType blockType,
448 GLuint maxCombinedInterfaceBlocks)
449{
450 // Check that interface blocks defined in the vertex and fragment shaders are identical
451 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
452 InterfaceBlockMap linkedInterfaceBlocks;
453 GLuint blockCount = 0;
454
455 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
456 {
457 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
458 if (IsActiveInterfaceBlock(vertexInterfaceBlock))
459 {
460 blockCount += std::max(vertexInterfaceBlock.arraySize, 1u);
461 }
462 }
463
464 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
465 {
466 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
467 if (entry != linkedInterfaceBlocks.end())
468 {
469 const sh::InterfaceBlock &vertexInterfaceBlock = *(entry->second);
470 std::string mismatchedBlockFieldName;
471 LinkMismatchError linkError =
472 AreMatchingInterfaceBlocks(vertexInterfaceBlock, fragmentInterfaceBlock,
473 webglCompatibility, &mismatchedBlockFieldName);
474 if (linkError != LinkMismatchError::NO_MISMATCH)
475 {
476 LogLinkMismatch(infoLog, fragmentInterfaceBlock.name, "interface block", linkError,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800477 mismatchedBlockFieldName, ShaderType::Vertex, ShaderType::Fragment);
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800478 return false;
479 }
480 }
481
482 // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
483 // If a uniform block is used by multiple shader stages, each such use counts separately
484 // against this combined limit.
485 // [OpenGL ES 3.1] Chapter 7.8 Page 111:
486 // If a shader storage block in a program is referenced by multiple shaders, each such
487 // reference counts separately against this combined limit.
488 if (IsActiveInterfaceBlock(fragmentInterfaceBlock))
489 {
490 blockCount += std::max(fragmentInterfaceBlock.arraySize, 1u);
491 }
492 }
493
494 if (blockCount > maxCombinedInterfaceBlocks)
495 {
496 switch (blockType)
497 {
498 case sh::BlockType::BLOCK_UNIFORM:
499 infoLog << "The sum of the number of active uniform blocks exceeds "
500 "MAX_COMBINED_UNIFORM_BLOCKS ("
501 << maxCombinedInterfaceBlocks << ").";
502 break;
503 case sh::BlockType::BLOCK_BUFFER:
504 infoLog << "The sum of the number of active shader storage blocks exceeds "
505 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
506 << maxCombinedInterfaceBlocks << ").";
507 break;
508 default:
509 UNREACHABLE();
510 }
511 return false;
512 }
513 return true;
514}
515
Jamie Madill62d31cb2015-09-11 13:25:51 -0400516} // anonymous namespace
517
Jamie Madill4a3c2342015-10-08 12:58:45 -0400518const char *const g_fakepath = "C:\\fakepath";
519
Jamie Madill3c1da042017-11-27 18:33:40 -0500520// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400521InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000522{
523}
524
525InfoLog::~InfoLog()
526{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000527}
528
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400529size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000530{
Jamie Madill23176ce2017-07-31 14:14:33 -0400531 if (!mLazyStream)
532 {
533 return 0;
534 }
535
536 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400537 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000538}
539
Geoff Lange1a27752015-10-05 13:16:04 -0400540void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000541{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400542 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000543
544 if (bufSize > 0)
545 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400546 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400547
Jamie Madill23176ce2017-07-31 14:14:33 -0400548 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000549 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400550 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
551 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000552 }
553
554 infoLog[index] = '\0';
555 }
556
557 if (length)
558 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400559 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000560 }
561}
562
563// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300564// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000565// messages, so lets remove all occurrences of this fake file path from the log.
566void InfoLog::appendSanitized(const char *message)
567{
Jamie Madill23176ce2017-07-31 14:14:33 -0400568 ensureInitialized();
569
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000570 std::string msg(message);
571
572 size_t found;
573 do
574 {
575 found = msg.find(g_fakepath);
576 if (found != std::string::npos)
577 {
578 msg.erase(found, strlen(g_fakepath));
579 }
580 }
581 while (found != std::string::npos);
582
Jamie Madill23176ce2017-07-31 14:14:33 -0400583 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000584}
585
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000586void InfoLog::reset()
587{
Jiawei Shao02f15232017-12-27 10:10:28 +0800588 if (mLazyStream)
589 {
590 mLazyStream.reset(nullptr);
591 }
592}
593
594bool InfoLog::empty() const
595{
596 if (!mLazyStream)
597 {
598 return true;
599 }
600
601 return mLazyStream->rdbuf()->in_avail() == 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000602}
603
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800604void LogLinkMismatch(InfoLog &infoLog,
605 const std::string &variableName,
606 const char *variableType,
607 LinkMismatchError linkError,
608 const std::string &mismatchedStructOrBlockFieldName,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800609 ShaderType shaderType1,
610 ShaderType shaderType2)
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800611{
612 std::ostringstream stream;
613 stream << GetLinkMismatchErrorString(linkError) << "s of " << variableType << " '"
614 << variableName;
615
616 if (!mismatchedStructOrBlockFieldName.empty())
617 {
618 stream << "' member '" << variableName << "." << mismatchedStructOrBlockFieldName;
619 }
620
621 stream << "' differ between " << GetShaderTypeString(shaderType1) << " and "
622 << GetShaderTypeString(shaderType2) << " shaders.";
623
624 infoLog << stream.str();
625}
626
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800627bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock)
628{
629 // Only 'packed' blocks are allowed to be considered inactive.
Olli Etuaho107c7242018-03-20 15:45:35 +0200630 return interfaceBlock.active || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED;
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800631}
632
Jamie Madill3c1da042017-11-27 18:33:40 -0500633// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300634VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000635{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500636}
637
Olli Etuahoc8538042017-09-27 11:20:15 +0300638VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300639 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500640{
Olli Etuahoc8538042017-09-27 11:20:15 +0300641 ASSERT(arrayIndex != GL_INVALID_INDEX);
642}
643
Jamie Madill3c1da042017-11-27 18:33:40 -0500644// SamplerBindings implementation.
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800645SamplerBinding::SamplerBinding(TextureType textureTypeIn, size_t elementCount, bool unreferenced)
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500646 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
647{
648}
649
650SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
651
652SamplerBinding::~SamplerBinding() = default;
653
Jamie Madill3c1da042017-11-27 18:33:40 -0500654// ProgramBindings implementation.
655ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500656{
657}
658
Jamie Madill3c1da042017-11-27 18:33:40 -0500659ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500660{
661}
662
Jamie Madill3c1da042017-11-27 18:33:40 -0500663void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400664{
665 mBindings[name] = index;
666}
667
Jamie Madill3c1da042017-11-27 18:33:40 -0500668int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400669{
670 auto iter = mBindings.find(name);
671 return (iter != mBindings.end()) ? iter->second : -1;
672}
673
Jamie Madill3c1da042017-11-27 18:33:40 -0500674ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400675{
676 return mBindings.begin();
677}
678
Jamie Madill3c1da042017-11-27 18:33:40 -0500679ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400680{
681 return mBindings.end();
682}
683
Jamie Madill3c1da042017-11-27 18:33:40 -0500684// ImageBinding implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500685ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
686{
687}
688ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
689{
690 for (size_t index = 0; index < count; ++index)
691 {
692 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
693 }
694}
695
696ImageBinding::ImageBinding(const ImageBinding &other) = default;
697
698ImageBinding::~ImageBinding() = default;
699
Jamie Madill3c1da042017-11-27 18:33:40 -0500700// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400701ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500702 : mLabel(),
Jiawei Shao016105b2018-04-12 16:38:31 +0800703 mAttachedShaders({}),
Geoff Langc5629752015-12-07 16:29:04 -0500704 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400705 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500706 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800707 mImageUniformRange(0, 0),
708 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300709 mBinaryRetrieveableHint(false),
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800710 mNumViews(-1),
711 // [GL_EXT_geometry_shader] Table 20.22
712 mGeometryShaderInputPrimitiveType(GL_TRIANGLES),
713 mGeometryShaderOutputPrimitiveType(GL_TRIANGLE_STRIP),
714 mGeometryShaderInvocations(1),
715 mGeometryShaderMaxVertices(0)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400716{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300717 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400718}
719
Jamie Madill48ef11b2016-04-27 15:21:52 -0400720ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400721{
Jiawei Shao016105b2018-04-12 16:38:31 +0800722 ASSERT(!hasAttachedShader());
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400723}
724
Jamie Madill48ef11b2016-04-27 15:21:52 -0400725const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500726{
727 return mLabel;
728}
729
Jiawei Shao385b3e02018-03-21 09:43:28 +0800730Shader *ProgramState::getAttachedShader(ShaderType shaderType) const
731{
Jiawei Shao016105b2018-04-12 16:38:31 +0800732 ASSERT(shaderType != ShaderType::InvalidEnum);
733 return mAttachedShaders[shaderType];
Jiawei Shao385b3e02018-03-21 09:43:28 +0800734}
735
Jamie Madille7d84322017-01-10 18:21:59 -0500736GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400737{
jchen1015015f72017-03-16 13:54:21 +0800738 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400739}
740
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800741GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
742{
743 return GetResourceIndexFromName(mBufferVariables, name);
744}
745
Jamie Madille7d84322017-01-10 18:21:59 -0500746GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
747{
748 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
749 return mUniformLocations[location].index;
750}
751
752Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
753{
754 GLuint index = getUniformIndexFromLocation(location);
755 if (!isSamplerUniformIndex(index))
756 {
757 return Optional<GLuint>::Invalid();
758 }
759
760 return getSamplerIndexFromUniformIndex(index);
761}
762
763bool ProgramState::isSamplerUniformIndex(GLuint index) const
764{
Jamie Madill982f6e02017-06-07 14:33:04 -0400765 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500766}
767
768GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
769{
770 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400771 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500772}
773
Jamie Madill34ca4f52017-06-13 11:49:39 -0400774GLuint ProgramState::getAttributeLocation(const std::string &name) const
775{
776 for (const sh::Attribute &attribute : mAttributes)
777 {
778 if (attribute.name == name)
779 {
780 return attribute.location;
781 }
782 }
783
784 return static_cast<GLuint>(-1);
785}
786
Jiawei Shao016105b2018-04-12 16:38:31 +0800787bool ProgramState::hasAttachedShader() const
788{
789 for (const Shader *shader : mAttachedShaders)
790 {
791 if (shader)
792 {
793 return true;
794 }
795 }
796 return false;
797}
798
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500799Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400800 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400801 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500802 mLinked(false),
803 mDeleteStatus(false),
804 mRefCount(0),
805 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500806 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500807{
808 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000809
Geoff Lang7dd2e102014-11-10 15:19:26 -0500810 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811}
812
813Program::~Program()
814{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400815 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816}
817
Jamie Madill4928b7c2017-06-20 12:57:39 -0400818void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500819{
Jiawei Shao016105b2018-04-12 16:38:31 +0800820 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill6c1f6712017-02-14 19:08:04 -0500821 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800822 if (mState.mAttachedShaders[shaderType])
823 {
824 mState.mAttachedShaders[shaderType]->release(context);
825 mState.mAttachedShaders[shaderType] = nullptr;
826 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800827 }
828
Jamie Madillb7d924a2018-03-10 11:16:54 -0500829 // TODO(jmadill): Handle error in the Context.
830 ANGLE_SWALLOW_ERR(mProgram->destroy(context));
Jamie Madill4928b7c2017-06-20 12:57:39 -0400831
Jiawei Shao016105b2018-04-12 16:38:31 +0800832 ASSERT(!mState.hasAttachedShader());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400833 SafeDelete(mProgram);
834
835 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500836}
837
Geoff Lang70d0f492015-12-10 17:45:46 -0500838void Program::setLabel(const std::string &label)
839{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400840 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500841}
842
843const std::string &Program::getLabel() const
844{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400845 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500846}
847
Jamie Madillef300b12016-10-07 15:12:09 -0400848void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000849{
Jiawei Shao016105b2018-04-12 16:38:31 +0800850 ShaderType shaderType = shader->getType();
851 ASSERT(shaderType != ShaderType::InvalidEnum);
852
853 mState.mAttachedShaders[shaderType] = shader;
854 mState.mAttachedShaders[shaderType]->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000855}
856
Jamie Madillc1d770e2017-04-13 17:31:24 -0400857void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000858{
Jiawei Shao016105b2018-04-12 16:38:31 +0800859 ShaderType shaderType = shader->getType();
860 ASSERT(shaderType != ShaderType::InvalidEnum);
861
862 ASSERT(mState.mAttachedShaders[shaderType] == shader);
863 shader->release(context);
864 mState.mAttachedShaders[shaderType] = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000865}
866
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000867int Program::getAttachedShadersCount() const
868{
Jiawei Shao016105b2018-04-12 16:38:31 +0800869 int numAttachedShaders = 0;
870 for (const Shader *shader : mState.mAttachedShaders)
871 {
872 if (shader)
873 {
874 ++numAttachedShaders;
875 }
876 }
877
878 return numAttachedShaders;
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000879}
880
Jiawei Shao385b3e02018-03-21 09:43:28 +0800881const Shader *Program::getAttachedShader(ShaderType shaderType) const
882{
883 return mState.getAttachedShader(shaderType);
884}
885
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000886void Program::bindAttributeLocation(GLuint index, const char *name)
887{
Geoff Langd8605522016-04-13 10:19:12 -0400888 mAttributeBindings.bindLocation(index, name);
889}
890
891void Program::bindUniformLocation(GLuint index, const char *name)
892{
Olli Etuahod2551232017-10-26 20:03:33 +0300893 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000894}
895
Sami Väisänen46eaa942016-06-29 10:26:37 +0300896void Program::bindFragmentInputLocation(GLint index, const char *name)
897{
898 mFragmentInputBindings.bindLocation(index, name);
899}
900
Jamie Madillbd044ed2017-06-05 12:59:21 -0400901BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300902{
903 BindingInfo ret;
904 ret.type = GL_NONE;
905 ret.valid = false;
906
Jiawei Shao385b3e02018-03-21 09:43:28 +0800907 Shader *fragmentShader = mState.getAttachedShader(ShaderType::Fragment);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300908 ASSERT(fragmentShader);
909
910 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800911 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300912
913 for (const auto &binding : mFragmentInputBindings)
914 {
915 if (binding.second != static_cast<GLuint>(index))
916 continue;
917
918 ret.valid = true;
919
Olli Etuahod2551232017-10-26 20:03:33 +0300920 size_t nameLengthWithoutArrayIndex;
921 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300922
923 for (const auto &in : inputs)
924 {
Olli Etuahod2551232017-10-26 20:03:33 +0300925 if (in.name.length() == nameLengthWithoutArrayIndex &&
926 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300927 {
928 if (in.isArray())
929 {
930 // The client wants to bind either "name" or "name[0]".
931 // GL ES 3.1 spec refers to active array names with language such as:
932 // "if the string identifies the base name of an active array, where the
933 // string would exactly match the name of the variable if the suffix "[0]"
934 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400935 if (arrayIndex == GL_INVALID_INDEX)
936 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300937
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400938 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300939 }
940 else
941 {
942 ret.name = in.mappedName;
943 }
944 ret.type = in.type;
945 return ret;
946 }
947 }
948 }
949
950 return ret;
951}
952
Jamie Madillbd044ed2017-06-05 12:59:21 -0400953void Program::pathFragmentInputGen(const Context *context,
954 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300955 GLenum genMode,
956 GLint components,
957 const GLfloat *coeffs)
958{
959 // If the location is -1 then the command is silently ignored
960 if (index == -1)
961 return;
962
Jamie Madillbd044ed2017-06-05 12:59:21 -0400963 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300964
965 // If the input doesn't exist then then the command is silently ignored
966 // This could happen through optimization for example, the shader translator
967 // decides that a variable is not actually being used and optimizes it away.
968 if (binding.name.empty())
969 return;
970
971 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
972}
973
Martin Radev4c4c8e72016-08-04 12:25:34 +0300974// The attached shaders are checked for linking errors by matching up their variables.
975// Uniform, input and output variables get collected.
976// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500977Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000978{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500979 const auto &data = context->getContextState();
980
Jamie Madill6c58b062017-08-01 13:44:25 -0400981 auto *platform = ANGLEPlatformCurrent();
982 double startTime = platform->currentTime(platform);
983
Jamie Madill6c1f6712017-02-14 19:08:04 -0500984 unlink();
Jamie Madill6bc264a2018-03-31 15:36:05 -0400985 mInfoLog.reset();
986
987 // Validate we have properly attached shaders before checking the cache.
988 if (!linkValidateShaders(context, mInfoLog))
989 {
990 return NoError();
991 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000992
Jamie Madill32447362017-06-28 14:53:52 -0400993 ProgramHash programHash;
Jamie Madill6bc264a2018-03-31 15:36:05 -0400994 MemoryProgramCache *cache = context->getMemoryProgramCache();
Jamie Madill32447362017-06-28 14:53:52 -0400995 if (cache)
996 {
997 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400998 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400999 }
1000
1001 if (mLinked)
1002 {
Jamie Madill6c58b062017-08-01 13:44:25 -04001003 double delta = platform->currentTime(platform) - startTime;
1004 int us = static_cast<int>(delta * 1000000.0);
1005 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -04001006 return NoError();
1007 }
1008
1009 // Cache load failed, fall through to normal linking.
1010 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001011
Jamie Madill6bc264a2018-03-31 15:36:05 -04001012 // Re-link shaders after the unlink call.
1013 ASSERT(linkValidateShaders(context, mInfoLog));
Yuly Novikovcfa48d32016-06-15 22:14:36 -04001014
Jiawei Shao016105b2018-04-12 16:38:31 +08001015 if (mState.mAttachedShaders[ShaderType::Compute])
Jamie Madill437d2662014-12-05 14:23:35 -05001016 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04001017 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001018 {
1019 return NoError();
1020 }
1021
Jiajia Qin729b2c62017-08-14 09:36:11 +08001022 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001023 {
1024 return NoError();
1025 }
1026
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001027 ProgramLinkedResources resources = {
1028 {0, PackMode::ANGLE_RELAXED},
1029 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +08001030 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1031 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -05001032
1033 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
1034 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
1035
1036 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -05001037 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001038 {
Jamie Madillb0a838b2016-11-13 20:02:12 -05001039 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001040 }
1041 }
1042 else
1043 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04001044 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001045 {
1046 return NoError();
1047 }
1048
Jamie Madillbd044ed2017-06-05 12:59:21 -04001049 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001050 {
1051 return NoError();
1052 }
1053
Jamie Madillbd044ed2017-06-05 12:59:21 -04001054 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001055 {
1056 return NoError();
1057 }
1058
Jiajia Qin729b2c62017-08-14 09:36:11 +08001059 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001060 {
1061 return NoError();
1062 }
1063
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04001064 if (!linkValidateGlobalNames(context, mInfoLog))
1065 {
1066 return NoError();
1067 }
1068
Jamie Madillbd044ed2017-06-05 12:59:21 -04001069 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03001070
Jiawei Shao016105b2018-04-12 16:38:31 +08001071 ASSERT(mState.mAttachedShaders[ShaderType::Vertex]);
1072 mState.mNumViews = mState.mAttachedShaders[ShaderType::Vertex]->getNumViews(context);
Martin Radev7cf61662017-07-26 17:10:53 +03001073
Jamie Madillbd044ed2017-06-05 12:59:21 -04001074 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03001075
Jamie Madill192745a2016-12-22 15:58:21 -05001076 // Map the varyings to the register file
1077 // In WebGL, we use a slightly different handling for packing variables.
Jamie Madill61d53252018-01-31 14:49:24 -05001078 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
1079 if (data.getLimitations().noFlexibleVaryingPacking)
1080 {
1081 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
1082 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
1083 }
1084 else if (data.getExtensions().webglCompatibility)
1085 {
1086 packMode = PackMode::WEBGL_STRICT;
1087 }
Jamie Madillc9727f32017-11-07 12:37:07 -05001088
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001089 ProgramLinkedResources resources = {
1090 {data.getCaps().maxVaryingVectors, packMode},
1091 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +08001092 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1093 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -05001094
1095 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
1096 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
1097
Jiawei Shao73618602017-12-20 15:47:15 +08001098 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -05001099 {
1100 return NoError();
1101 }
1102
jchen1085c93c42017-11-12 15:36:47 +08001103 if (!resources.varyingPacking.collectAndPackUserVaryings(
1104 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +03001105 {
1106 return NoError();
1107 }
1108
Jamie Madillc9727f32017-11-07 12:37:07 -05001109 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -05001110 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001111 {
Jamie Madillb0a838b2016-11-13 20:02:12 -05001112 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001113 }
1114
1115 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -05001116 }
1117
Jamie Madill6db1c2e2017-11-08 09:17:40 -05001118 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -04001119
jchen10eaef1e52017-06-13 10:44:11 +08001120 setUniformValuesFromBindingQualifiers();
1121
Yunchao Heece12532017-11-21 15:50:21 +08001122 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
1123 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +08001124 ASSERT(mLinked);
1125 updateLinkedShaderStages();
1126
Jamie Madill54164b02017-08-28 15:17:37 -04001127 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -04001128 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -04001129
Jamie Madill32447362017-06-28 14:53:52 -04001130 // Save to the program cache.
1131 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
1132 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
1133 {
1134 cache->putProgram(programHash, context, this);
1135 }
1136
Jamie Madill6c58b062017-08-01 13:44:25 -04001137 double delta = platform->currentTime(platform) - startTime;
1138 int us = static_cast<int>(delta * 1000000.0);
1139 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
1140
Martin Radev4c4c8e72016-08-04 12:25:34 +03001141 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001142}
1143
Yunchao He85072e82017-11-14 15:43:28 +08001144void Program::updateLinkedShaderStages()
1145{
Yunchao Heece12532017-11-21 15:50:21 +08001146 mState.mLinkedShaderStages.reset();
1147
Jiawei Shao016105b2018-04-12 16:38:31 +08001148 for (const Shader *shader : mState.mAttachedShaders)
Yunchao He85072e82017-11-14 15:43:28 +08001149 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001150 if (shader)
1151 {
1152 mState.mLinkedShaderStages.set(shader->getType());
1153 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001154 }
Yunchao He85072e82017-11-14 15:43:28 +08001155}
1156
James Darpinian30b604d2018-03-12 17:26:57 -07001157void ProgramState::updateTransformFeedbackStrides()
1158{
1159 if (mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS)
1160 {
1161 mTransformFeedbackStrides.resize(1);
1162 size_t totalSize = 0;
1163 for (auto &varying : mLinkedTransformFeedbackVaryings)
1164 {
1165 totalSize += varying.size() * VariableExternalSize(varying.type);
1166 }
1167 mTransformFeedbackStrides[0] = static_cast<GLsizei>(totalSize);
1168 }
1169 else
1170 {
1171 mTransformFeedbackStrides.resize(mLinkedTransformFeedbackVaryings.size());
1172 for (size_t i = 0; i < mLinkedTransformFeedbackVaryings.size(); i++)
1173 {
1174 auto &varying = mLinkedTransformFeedbackVaryings[i];
1175 mTransformFeedbackStrides[i] =
1176 static_cast<GLsizei>(varying.size() * VariableExternalSize(varying.type));
1177 }
1178 }
1179}
1180
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00001181// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -05001182void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001183{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001184 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -08001185 mState.mAttributesTypeMask.reset();
1186 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001187 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001188 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001189 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001190 mState.mUniforms.clear();
1191 mState.mUniformLocations.clear();
1192 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001193 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001194 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001195 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001196 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001197 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001198 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001199 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001200 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001201 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001202 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001203 mState.mNumViews = -1;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001204 mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
1205 mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
1206 mState.mGeometryShaderInvocations = 1;
1207 mState.mGeometryShaderMaxVertices = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001208
Geoff Lang7dd2e102014-11-10 15:19:26 -05001209 mValidated = false;
1210
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001211 mLinked = false;
Jamie Madill6bc264a2018-03-31 15:36:05 -04001212 mInfoLog.reset();
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001213}
1214
Geoff Lange1a27752015-10-05 13:16:04 -04001215bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001216{
1217 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218}
1219
Jiawei Shao385b3e02018-03-21 09:43:28 +08001220bool Program::hasLinkedShaderStage(ShaderType shaderType) const
1221{
1222 ASSERT(shaderType != ShaderType::InvalidEnum);
1223 return mState.mLinkedShaderStages[shaderType];
1224}
1225
Jamie Madilla2c74982016-12-12 11:20:42 -05001226Error Program::loadBinary(const Context *context,
1227 GLenum binaryFormat,
1228 const void *binary,
1229 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001230{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001231 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001232
Geoff Lang7dd2e102014-11-10 15:19:26 -05001233#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001234 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001235#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001236 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1237 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001238 {
Jamie Madillf6113162015-05-07 11:49:21 -04001239 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001240 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001241 }
1242
Jamie Madill4f86d052017-06-05 12:59:26 -04001243 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1244 ANGLE_TRY_RESULT(
1245 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001246
1247 // Currently we require the full shader text to compute the program hash.
1248 // TODO(jmadill): Store the binary in the internal program cache.
1249
Jamie Madillb0a838b2016-11-13 20:02:12 -05001250 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001251#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001252}
1253
Jamie Madilla2c74982016-12-12 11:20:42 -05001254Error Program::saveBinary(const Context *context,
1255 GLenum *binaryFormat,
1256 void *binary,
1257 GLsizei bufSize,
1258 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001259{
1260 if (binaryFormat)
1261 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001262 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001263 }
1264
Jamie Madill4f86d052017-06-05 12:59:26 -04001265 angle::MemoryBuffer memoryBuf;
1266 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001267
Jamie Madill4f86d052017-06-05 12:59:26 -04001268 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1269 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001270
1271 if (streamLength > bufSize)
1272 {
1273 if (length)
1274 {
1275 *length = 0;
1276 }
1277
1278 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1279 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1280 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001281 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001282 }
1283
1284 if (binary)
1285 {
1286 char *ptr = reinterpret_cast<char*>(binary);
1287
Jamie Madill48ef11b2016-04-27 15:21:52 -04001288 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289 ptr += streamLength;
1290
1291 ASSERT(ptr - streamLength == binary);
1292 }
1293
1294 if (length)
1295 {
1296 *length = streamLength;
1297 }
1298
He Yunchaoacd18982017-01-04 10:46:42 +08001299 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001300}
1301
Jamie Madillffe00c02017-06-27 16:26:55 -04001302GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001303{
1304 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001305 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001306 if (error.isError())
1307 {
1308 return 0;
1309 }
1310
1311 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001312}
1313
Geoff Langc5629752015-12-07 16:29:04 -05001314void Program::setBinaryRetrievableHint(bool retrievable)
1315{
1316 // TODO(jmadill) : replace with dirty bits
1317 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001318 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001319}
1320
1321bool Program::getBinaryRetrievableHint() const
1322{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001323 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001324}
1325
Yunchao He61afff12017-03-14 15:34:03 +08001326void Program::setSeparable(bool separable)
1327{
1328 // TODO(yunchao) : replace with dirty bits
1329 if (mState.mSeparable != separable)
1330 {
1331 mProgram->setSeparable(separable);
1332 mState.mSeparable = separable;
1333 }
1334}
1335
1336bool Program::isSeparable() const
1337{
1338 return mState.mSeparable;
1339}
1340
Jamie Madill6c1f6712017-02-14 19:08:04 -05001341void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001342{
1343 mRefCount--;
1344
1345 if (mRefCount == 0 && mDeleteStatus)
1346 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001347 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001348 }
1349}
1350
1351void Program::addRef()
1352{
1353 mRefCount++;
1354}
1355
1356unsigned int Program::getRefCount() const
1357{
1358 return mRefCount;
1359}
1360
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001361int Program::getInfoLogLength() const
1362{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001363 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001364}
1365
Geoff Lange1a27752015-10-05 13:16:04 -04001366void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001367{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001368 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001369}
1370
Geoff Lange1a27752015-10-05 13:16:04 -04001371void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001372{
1373 int total = 0;
1374
Jiawei Shao016105b2018-04-12 16:38:31 +08001375 for (const Shader *shader : mState.mAttachedShaders)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001376 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001377 if (shader && (total < maxCount))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001378 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001379 shaders[total] = shader->getHandle();
1380 ++total;
Jiawei Shao89be29a2017-11-06 14:36:45 +08001381 }
1382 }
1383
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001384 if (count)
1385 {
1386 *count = total;
1387 }
1388}
1389
Geoff Lange1a27752015-10-05 13:16:04 -04001390GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001391{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001392 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393}
1394
Jamie Madill63805b42015-08-25 13:17:39 -04001395bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001396{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001397 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1398 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399}
1400
jchen10fd7c3b52017-03-21 15:36:03 +08001401void Program::getActiveAttribute(GLuint index,
1402 GLsizei bufsize,
1403 GLsizei *length,
1404 GLint *size,
1405 GLenum *type,
1406 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001407{
Jamie Madillc349ec02015-08-21 16:53:12 -04001408 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001409 {
1410 if (bufsize > 0)
1411 {
1412 name[0] = '\0';
1413 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001414
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001415 if (length)
1416 {
1417 *length = 0;
1418 }
1419
1420 *type = GL_NONE;
1421 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001422 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001423 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001424
jchen1036e120e2017-03-14 14:53:58 +08001425 ASSERT(index < mState.mAttributes.size());
1426 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001427
1428 if (bufsize > 0)
1429 {
jchen10fd7c3b52017-03-21 15:36:03 +08001430 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001431 }
1432
1433 // Always a single 'type' instance
1434 *size = 1;
1435 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001436}
1437
Geoff Lange1a27752015-10-05 13:16:04 -04001438GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001439{
Jamie Madillc349ec02015-08-21 16:53:12 -04001440 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001441 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001442 return 0;
1443 }
1444
jchen1036e120e2017-03-14 14:53:58 +08001445 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001446}
1447
Geoff Lange1a27752015-10-05 13:16:04 -04001448GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001449{
Jamie Madillc349ec02015-08-21 16:53:12 -04001450 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001451 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001452 return 0;
1453 }
1454
1455 size_t maxLength = 0;
1456
Jamie Madill48ef11b2016-04-27 15:21:52 -04001457 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001458 {
jchen1036e120e2017-03-14 14:53:58 +08001459 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001460 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461
Jamie Madillc349ec02015-08-21 16:53:12 -04001462 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001463}
1464
jchen1015015f72017-03-16 13:54:21 +08001465GLuint Program::getInputResourceIndex(const GLchar *name) const
1466{
Olli Etuahod2551232017-10-26 20:03:33 +03001467 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001468}
1469
1470GLuint Program::getOutputResourceIndex(const GLchar *name) const
1471{
1472 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1473}
1474
jchen10fd7c3b52017-03-21 15:36:03 +08001475size_t Program::getOutputResourceCount() const
1476{
1477 return (mLinked ? mState.mOutputVariables.size() : 0);
1478}
1479
jchen10baf5d942017-08-28 20:45:48 +08001480template <typename T>
1481void Program::getResourceName(GLuint index,
1482 const std::vector<T> &resources,
1483 GLsizei bufSize,
1484 GLsizei *length,
1485 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001486{
1487 if (length)
1488 {
1489 *length = 0;
1490 }
1491
1492 if (!mLinked)
1493 {
1494 if (bufSize > 0)
1495 {
1496 name[0] = '\0';
1497 }
1498 return;
1499 }
jchen10baf5d942017-08-28 20:45:48 +08001500 ASSERT(index < resources.size());
1501 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001502
1503 if (bufSize > 0)
1504 {
Olli Etuahod2551232017-10-26 20:03:33 +03001505 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001506 }
1507}
1508
jchen10baf5d942017-08-28 20:45:48 +08001509void Program::getInputResourceName(GLuint index,
1510 GLsizei bufSize,
1511 GLsizei *length,
1512 GLchar *name) const
1513{
1514 getResourceName(index, mState.mAttributes, bufSize, length, name);
1515}
1516
1517void Program::getOutputResourceName(GLuint index,
1518 GLsizei bufSize,
1519 GLsizei *length,
1520 GLchar *name) const
1521{
1522 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1523}
1524
1525void Program::getUniformResourceName(GLuint index,
1526 GLsizei bufSize,
1527 GLsizei *length,
1528 GLchar *name) const
1529{
1530 getResourceName(index, mState.mUniforms, bufSize, length, name);
1531}
1532
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001533void Program::getBufferVariableResourceName(GLuint index,
1534 GLsizei bufSize,
1535 GLsizei *length,
1536 GLchar *name) const
1537{
1538 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1539}
1540
jchen10880683b2017-04-12 16:21:55 +08001541const sh::Attribute &Program::getInputResource(GLuint index) const
1542{
1543 ASSERT(index < mState.mAttributes.size());
1544 return mState.mAttributes[index];
1545}
1546
1547const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1548{
1549 ASSERT(index < mState.mOutputVariables.size());
1550 return mState.mOutputVariables[index];
1551}
1552
Geoff Lang7dd2e102014-11-10 15:19:26 -05001553GLint Program::getFragDataLocation(const std::string &name) const
1554{
Olli Etuahod2551232017-10-26 20:03:33 +03001555 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001556}
1557
Geoff Lange1a27752015-10-05 13:16:04 -04001558void Program::getActiveUniform(GLuint index,
1559 GLsizei bufsize,
1560 GLsizei *length,
1561 GLint *size,
1562 GLenum *type,
1563 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001564{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001565 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001566 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001567 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001568 ASSERT(index < mState.mUniforms.size());
1569 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570
1571 if (bufsize > 0)
1572 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001573 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001574 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001575 }
1576
Olli Etuaho465835d2017-09-26 13:34:10 +03001577 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001578 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001579 }
1580 else
1581 {
1582 if (bufsize > 0)
1583 {
1584 name[0] = '\0';
1585 }
1586
1587 if (length)
1588 {
1589 *length = 0;
1590 }
1591
1592 *size = 0;
1593 *type = GL_NONE;
1594 }
1595}
1596
Geoff Lange1a27752015-10-05 13:16:04 -04001597GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001598{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001599 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001600 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001601 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001602 }
1603 else
1604 {
1605 return 0;
1606 }
1607}
1608
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001609size_t Program::getActiveBufferVariableCount() const
1610{
1611 return mLinked ? mState.mBufferVariables.size() : 0;
1612}
1613
Geoff Lange1a27752015-10-05 13:16:04 -04001614GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001615{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001616 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001617
1618 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001619 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001620 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001621 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001622 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001623 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001624 size_t length = uniform.name.length() + 1u;
1625 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626 {
1627 length += 3; // Counting in "[0]".
1628 }
1629 maxLength = std::max(length, maxLength);
1630 }
1631 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001632 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633
Jamie Madill62d31cb2015-09-11 13:25:51 -04001634 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001635}
1636
Geoff Lang7dd2e102014-11-10 15:19:26 -05001637bool Program::isValidUniformLocation(GLint location) const
1638{
Jamie Madille2e406c2016-06-02 13:04:10 -04001639 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001640 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001641 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001642}
1643
Jamie Madill62d31cb2015-09-11 13:25:51 -04001644const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001645{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001646 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001647 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001648}
1649
Jamie Madillac4e9c32017-01-13 14:07:12 -05001650const VariableLocation &Program::getUniformLocation(GLint location) const
1651{
1652 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1653 return mState.mUniformLocations[location];
1654}
1655
1656const std::vector<VariableLocation> &Program::getUniformLocations() const
1657{
1658 return mState.mUniformLocations;
1659}
1660
1661const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1662{
1663 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1664 return mState.mUniforms[index];
1665}
1666
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001667const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1668{
1669 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1670 return mState.mBufferVariables[index];
1671}
1672
Jamie Madill62d31cb2015-09-11 13:25:51 -04001673GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674{
Olli Etuahod2551232017-10-26 20:03:33 +03001675 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001676}
1677
Jamie Madill62d31cb2015-09-11 13:25:51 -04001678GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001679{
Jamie Madille7d84322017-01-10 18:21:59 -05001680 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001681}
1682
1683void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1684{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001685 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1686 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001687 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001688}
1689
1690void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1691{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001692 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1693 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001694 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001695}
1696
1697void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1698{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001699 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1700 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001701 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001702}
1703
1704void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1705{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001706 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1707 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001708 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001709}
1710
Jamie Madill81c2e252017-09-09 23:32:46 -04001711Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001712{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001713 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1714 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1715
Jamie Madill81c2e252017-09-09 23:32:46 -04001716 mProgram->setUniform1iv(location, clampedCount, v);
1717
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001718 if (mState.isSamplerUniformIndex(locationInfo.index))
1719 {
1720 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001721 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001722 }
1723
Jamie Madill81c2e252017-09-09 23:32:46 -04001724 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001725}
1726
1727void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1728{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001729 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1730 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001731 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001732}
1733
1734void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1735{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001736 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1737 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001738 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001739}
1740
1741void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1742{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001743 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1744 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001745 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001746}
1747
1748void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1749{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001750 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1751 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001752 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001753}
1754
1755void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1756{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001757 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1758 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001759 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001760}
1761
1762void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1763{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001764 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1765 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001766 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001767}
1768
1769void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1770{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001771 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1772 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001773 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001774}
1775
1776void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1777{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001778 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001779 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001780}
1781
1782void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1783{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001784 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001785 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786}
1787
1788void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1789{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001790 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001791 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001792}
1793
1794void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1795{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001796 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001797 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001798}
1799
1800void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1801{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001802 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001803 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001804}
1805
1806void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1807{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001808 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001809 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001810}
1811
1812void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1813{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001814 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001815 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001816}
1817
1818void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1819{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001820 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001821 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001822}
1823
1824void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1825{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001826 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001827 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001828}
1829
Jamie Madill54164b02017-08-28 15:17:37 -04001830void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001831{
Jamie Madill54164b02017-08-28 15:17:37 -04001832 const auto &uniformLocation = mState.getUniformLocations()[location];
1833 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1834
1835 GLenum nativeType = gl::VariableComponentType(uniform.type);
1836 if (nativeType == GL_FLOAT)
1837 {
1838 mProgram->getUniformfv(context, location, v);
1839 }
1840 else
1841 {
1842 getUniformInternal(context, v, location, nativeType,
1843 gl::VariableComponentCount(uniform.type));
1844 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001845}
1846
Jamie Madill54164b02017-08-28 15:17:37 -04001847void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001848{
Jamie Madill54164b02017-08-28 15:17:37 -04001849 const auto &uniformLocation = mState.getUniformLocations()[location];
1850 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1851
1852 GLenum nativeType = gl::VariableComponentType(uniform.type);
1853 if (nativeType == GL_INT || nativeType == GL_BOOL)
1854 {
1855 mProgram->getUniformiv(context, location, v);
1856 }
1857 else
1858 {
1859 getUniformInternal(context, v, location, nativeType,
1860 gl::VariableComponentCount(uniform.type));
1861 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001862}
1863
Jamie Madill54164b02017-08-28 15:17:37 -04001864void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001865{
Jamie Madill54164b02017-08-28 15:17:37 -04001866 const auto &uniformLocation = mState.getUniformLocations()[location];
1867 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1868
1869 GLenum nativeType = gl::VariableComponentType(uniform.type);
1870 if (nativeType == GL_UNSIGNED_INT)
1871 {
1872 mProgram->getUniformuiv(context, location, v);
1873 }
1874 else
1875 {
1876 getUniformInternal(context, v, location, nativeType,
1877 gl::VariableComponentCount(uniform.type));
1878 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001879}
1880
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001881void Program::flagForDeletion()
1882{
1883 mDeleteStatus = true;
1884}
1885
1886bool Program::isFlaggedForDeletion() const
1887{
1888 return mDeleteStatus;
1889}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001890
Brandon Jones43a53e22014-08-28 16:23:22 -07001891void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001892{
1893 mInfoLog.reset();
1894
Geoff Lang7dd2e102014-11-10 15:19:26 -05001895 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001896 {
Geoff Lang92019432017-11-20 13:09:34 -05001897 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001898 }
1899 else
1900 {
Jamie Madillf6113162015-05-07 11:49:21 -04001901 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001902 }
1903}
1904
Geoff Lang7dd2e102014-11-10 15:19:26 -05001905bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1906{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001907 // Skip cache if we're using an infolog, so we get the full error.
1908 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1909 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1910 {
1911 return mCachedValidateSamplersResult.value();
1912 }
1913
1914 if (mTextureUnitTypesCache.empty())
1915 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001916 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, TextureType::InvalidEnum);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001917 }
1918 else
1919 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001920 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(),
1921 TextureType::InvalidEnum);
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001922 }
1923
1924 // if any two active samplers in a program are of different types, but refer to the same
1925 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1926 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001927 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001928 {
Jamie Madill54164b02017-08-28 15:17:37 -04001929 if (samplerBinding.unreferenced)
1930 continue;
1931
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001932 TextureType textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001933
Jamie Madille7d84322017-01-10 18:21:59 -05001934 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001935 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001936 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1937 {
1938 if (infoLog)
1939 {
1940 (*infoLog) << "Sampler uniform (" << textureUnit
1941 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1942 << caps.maxCombinedTextureImageUnits << ")";
1943 }
1944
1945 mCachedValidateSamplersResult = false;
1946 return false;
1947 }
1948
Corentin Wallezf0e89be2017-11-08 14:00:32 -08001949 if (mTextureUnitTypesCache[textureUnit] != TextureType::InvalidEnum)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001950 {
1951 if (textureType != mTextureUnitTypesCache[textureUnit])
1952 {
1953 if (infoLog)
1954 {
1955 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1956 "image unit ("
1957 << textureUnit << ").";
1958 }
1959
1960 mCachedValidateSamplersResult = false;
1961 return false;
1962 }
1963 }
1964 else
1965 {
1966 mTextureUnitTypesCache[textureUnit] = textureType;
1967 }
1968 }
1969 }
1970
1971 mCachedValidateSamplersResult = true;
1972 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001973}
1974
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001975bool Program::isValidated() const
1976{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001977 return mValidated;
1978}
1979
Geoff Lange1a27752015-10-05 13:16:04 -04001980GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001981{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001982 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983}
1984
jchen1058f67be2017-10-27 08:59:27 +08001985GLuint Program::getActiveAtomicCounterBufferCount() const
1986{
1987 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1988}
1989
Jiajia Qin729b2c62017-08-14 09:36:11 +08001990GLuint Program::getActiveShaderStorageBlockCount() const
1991{
1992 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1993}
1994
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001995void Program::getActiveUniformBlockName(const GLuint blockIndex,
1996 GLsizei bufSize,
1997 GLsizei *length,
1998 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001999{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002000 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
2001}
Geoff Lang7dd2e102014-11-10 15:19:26 -05002002
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002003void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
2004 GLsizei bufSize,
2005 GLsizei *length,
2006 GLchar *blockName) const
2007{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002008
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002009 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00002010}
2011
Qin Jiajia9bf55522018-01-29 13:56:23 +08002012template <typename T>
2013GLint Program::getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002014{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002015 int maxLength = 0;
2016
2017 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002018 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002019 for (const T &resource : resources)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002020 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002021 if (!resource.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002022 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002023 int length = static_cast<int>(resource.nameWithArrayIndex().length());
jchen10af713a22017-04-19 09:10:56 +08002024 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002025 }
2026 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002027 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002028
2029 return maxLength;
2030}
2031
Qin Jiajia9bf55522018-01-29 13:56:23 +08002032GLint Program::getActiveUniformBlockMaxNameLength() const
2033{
2034 return getActiveInterfaceBlockMaxNameLength(mState.mUniformBlocks);
2035}
2036
2037GLint Program::getActiveShaderStorageBlockMaxNameLength() const
2038{
2039 return getActiveInterfaceBlockMaxNameLength(mState.mShaderStorageBlocks);
2040}
2041
Geoff Lange1a27752015-10-05 13:16:04 -04002042GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002043{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002044 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
2045}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002046
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002047GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
2048{
2049 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002050}
2051
Jiajia Qin729b2c62017-08-14 09:36:11 +08002052const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002053{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002054 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
2055 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002056}
2057
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002058const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
2059{
2060 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
2061 return mState.mShaderStorageBlocks[index];
2062}
2063
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002064void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2065{
jchen107a20b972017-06-13 14:25:26 +08002066 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05002067 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04002068 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002069}
2070
2071GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
2072{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002073 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002074}
2075
Jiajia Qin729b2c62017-08-14 09:36:11 +08002076GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
2077{
2078 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
2079}
2080
Geoff Lang48dcae72014-02-05 16:28:24 -05002081void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2082{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002083 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05002084 for (GLsizei i = 0; i < count; i++)
2085 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002086 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05002087 }
2088
Jamie Madill48ef11b2016-04-27 15:21:52 -04002089 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05002090}
2091
2092void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2093{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002094 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002095 {
jchen10a9042d32017-03-17 08:50:45 +08002096 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2097 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
2098 std::string varName = var.nameWithArrayIndex();
2099 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05002100 if (length)
2101 {
2102 *length = lastNameIdx;
2103 }
2104 if (size)
2105 {
jchen10a9042d32017-03-17 08:50:45 +08002106 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05002107 }
2108 if (type)
2109 {
jchen10a9042d32017-03-17 08:50:45 +08002110 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05002111 }
2112 if (name)
2113 {
jchen10a9042d32017-03-17 08:50:45 +08002114 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05002115 name[lastNameIdx] = '\0';
2116 }
2117 }
2118}
2119
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002120GLsizei Program::getTransformFeedbackVaryingCount() const
2121{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002122 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002123 {
jchen10a9042d32017-03-17 08:50:45 +08002124 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05002125 }
2126 else
2127 {
2128 return 0;
2129 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002130}
2131
2132GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2133{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002134 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002135 {
2136 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08002137 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05002138 {
jchen10a9042d32017-03-17 08:50:45 +08002139 maxSize =
2140 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05002141 }
2142
2143 return maxSize;
2144 }
2145 else
2146 {
2147 return 0;
2148 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002149}
2150
2151GLenum Program::getTransformFeedbackBufferMode() const
2152{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002153 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002154}
2155
Jiawei Shao73618602017-12-20 15:47:15 +08002156bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
2157{
Jiawei Shao016105b2018-04-12 16:38:31 +08002158 Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
2159 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
2160 Shader *computeShader = mState.mAttachedShaders[ShaderType::Compute];
2161 Shader *geometryShader = mState.mAttachedShaders[ShaderType::Geometry];
Jiawei Shao73618602017-12-20 15:47:15 +08002162
2163 bool isComputeShaderAttached = (computeShader != nullptr);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002164 bool isGraphicsShaderAttached =
2165 (vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +08002166 // Check whether we both have a compute and non-compute shaders attached.
2167 // If there are of both types attached, then linking should fail.
2168 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
2169 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
2170 {
2171 infoLog << "Both compute and graphics shaders are attached to the same program.";
2172 return false;
2173 }
2174
2175 if (computeShader)
2176 {
2177 if (!computeShader->isCompiled(context))
2178 {
2179 infoLog << "Attached compute shader is not compiled.";
2180 return false;
2181 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002182 ASSERT(computeShader->getType() == ShaderType::Compute);
Jiawei Shao73618602017-12-20 15:47:15 +08002183
2184 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
2185
2186 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2187 // If the work group size is not specified, a link time error should occur.
2188 if (!mState.mComputeShaderLocalSize.isDeclared())
2189 {
2190 infoLog << "Work group size is not specified.";
2191 return false;
2192 }
2193 }
2194 else
2195 {
2196 if (!fragmentShader || !fragmentShader->isCompiled(context))
2197 {
2198 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2199 return false;
2200 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002201 ASSERT(fragmentShader->getType() == ShaderType::Fragment);
Jiawei Shao73618602017-12-20 15:47:15 +08002202
2203 if (!vertexShader || !vertexShader->isCompiled(context))
2204 {
2205 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2206 return false;
2207 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002208 ASSERT(vertexShader->getType() == ShaderType::Vertex);
Jiawei Shao73618602017-12-20 15:47:15 +08002209
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002210 int vertexShaderVersion = vertexShader->getShaderVersion(context);
2211 if (fragmentShader->getShaderVersion(context) != vertexShaderVersion)
Jiawei Shao73618602017-12-20 15:47:15 +08002212 {
2213 infoLog << "Fragment shader version does not match vertex shader version.";
2214 return false;
2215 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002216
2217 if (geometryShader)
2218 {
2219 // [GL_EXT_geometry_shader] Chapter 7
2220 // Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
2221 // Language Specification, as well as any of the following reasons:
2222 // * One or more of the shader objects attached to <program> are not compiled
2223 // successfully.
2224 // * The shaders do not use the same shader language version.
2225 // * <program> contains objects to form a geometry shader, and
2226 // - <program> is not separable and contains no objects to form a vertex shader; or
2227 // - the input primitive type, output primitive type, or maximum output vertex count
2228 // is not specified in the compiled geometry shader object.
2229 if (!geometryShader->isCompiled(context))
2230 {
2231 infoLog << "The attached geometry shader isn't compiled.";
2232 return false;
2233 }
2234
2235 if (geometryShader->getShaderVersion(context) != vertexShaderVersion)
2236 {
2237 mInfoLog << "Geometry shader version does not match vertex shader version.";
2238 return false;
2239 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002240 ASSERT(geometryShader->getType() == ShaderType::Geometry);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002241
2242 Optional<GLenum> inputPrimitive =
2243 geometryShader->getGeometryShaderInputPrimitiveType(context);
2244 if (!inputPrimitive.valid())
2245 {
2246 mInfoLog << "Input primitive type is not specified in the geometry shader.";
2247 return false;
2248 }
2249
2250 Optional<GLenum> outputPrimitive =
2251 geometryShader->getGeometryShaderOutputPrimitiveType(context);
2252 if (!outputPrimitive.valid())
2253 {
2254 mInfoLog << "Output primitive type is not specified in the geometry shader.";
2255 return false;
2256 }
2257
2258 Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices(context);
2259 if (!maxVertices.valid())
2260 {
2261 mInfoLog << "'max_vertices' is not specified in the geometry shader.";
2262 return false;
2263 }
2264
2265 mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
2266 mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
2267 mState.mGeometryShaderMaxVertices = maxVertices.value();
2268 mState.mGeometryShaderInvocations =
2269 geometryShader->getGeometryShaderInvocations(context);
2270 }
Jiawei Shao73618602017-12-20 15:47:15 +08002271 }
2272
2273 return true;
2274}
2275
jchen10910a3da2017-11-15 09:40:11 +08002276GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2277{
2278 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2279 {
2280 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2281 if (tf.nameWithArrayIndex() == name)
2282 {
2283 return tfIndex;
2284 }
2285 }
2286 return GL_INVALID_INDEX;
2287}
2288
2289const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2290{
2291 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2292 return mState.mLinkedTransformFeedbackVaryings[index];
2293}
2294
Jamie Madillbd044ed2017-06-05 12:59:21 -04002295bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002296{
Jiawei Shao016105b2018-04-12 16:38:31 +08002297 Shader *previousShader = nullptr;
2298 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Jiawei Shaod063aff2018-02-22 10:19:09 +08002299 {
Jiawei Shao016105b2018-04-12 16:38:31 +08002300 Shader *currentShader = mState.mAttachedShaders[shaderType];
2301 if (!currentShader)
Jiawei Shaod063aff2018-02-22 10:19:09 +08002302 {
Jiawei Shao016105b2018-04-12 16:38:31 +08002303 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002304 }
Jiawei Shao016105b2018-04-12 16:38:31 +08002305
2306 if (previousShader)
2307 {
2308 if (!linkValidateShaderInterfaceMatching(context, previousShader, currentShader,
2309 infoLog))
2310 {
2311 return false;
2312 }
2313 }
2314 previousShader = currentShader;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002315 }
2316
2317 if (!linkValidateBuiltInVaryings(context, infoLog))
2318 {
2319 return false;
2320 }
2321
2322 if (!linkValidateFragmentInputBindings(context, infoLog))
2323 {
2324 return false;
2325 }
2326
2327 return true;
2328}
2329
2330// [OpenGL ES 3.1] Chapter 7.4.1 "Shader Interface Matchining" Page 91
2331// TODO(jiawei.shao@intel.com): add validation on input/output blocks matching
2332bool Program::linkValidateShaderInterfaceMatching(const Context *context,
2333 gl::Shader *generatingShader,
2334 gl::Shader *consumingShader,
2335 gl::InfoLog &infoLog) const
2336{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002337 ASSERT(generatingShader->getShaderVersion(context) ==
2338 consumingShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002339
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002340 const std::vector<sh::Varying> &outputVaryings = generatingShader->getOutputVaryings(context);
2341 const std::vector<sh::Varying> &inputVaryings = consumingShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002342
Jiawei Shao385b3e02018-03-21 09:43:28 +08002343 bool validateGeometryShaderInputs = consumingShader->getType() == ShaderType::Geometry;
Sami Väisänen46eaa942016-06-29 10:26:37 +03002344
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002345 for (const sh::Varying &input : inputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002346 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002347 bool matched = false;
2348
2349 // Built-in varyings obey special rules
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002350 if (input.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002351 {
2352 continue;
2353 }
2354
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002355 for (const sh::Varying &output : outputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002356 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002357 if (input.name == output.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002358 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002359 ASSERT(!output.isBuiltIn());
2360
2361 std::string mismatchedStructFieldName;
2362 LinkMismatchError linkError =
2363 LinkValidateVaryings(output, input, generatingShader->getShaderVersion(context),
Jiawei Shaod063aff2018-02-22 10:19:09 +08002364 validateGeometryShaderInputs, &mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002365 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002366 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002367 LogLinkMismatch(infoLog, input.name, "varying", linkError,
2368 mismatchedStructFieldName, generatingShader->getType(),
2369 consumingShader->getType());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002370 return false;
2371 }
2372
Geoff Lang7dd2e102014-11-10 15:19:26 -05002373 matched = true;
2374 break;
2375 }
2376 }
2377
Olli Etuaho107c7242018-03-20 15:45:35 +02002378 // We permit unmatched, unreferenced varyings. Note that this specifically depends on
2379 // whether the input is statically used - a statically used input should fail this test even
2380 // if it is not active. GLSL ES 3.00.6 section 4.3.10.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002381 if (!matched && input.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002382 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002383 infoLog << GetShaderTypeString(consumingShader->getType()) << " varying " << input.name
2384 << " does not match any " << GetShaderTypeString(generatingShader->getType())
2385 << " varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002386 return false;
2387 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002388 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002389
Jiawei Shaod063aff2018-02-22 10:19:09 +08002390 // TODO(jmadill): verify no unmatched output varyings?
Sami Väisänen46eaa942016-06-29 10:26:37 +03002391
Jiawei Shaod063aff2018-02-22 10:19:09 +08002392 return true;
2393}
2394
2395bool Program::linkValidateFragmentInputBindings(const Context *context, gl::InfoLog &infoLog) const
2396{
Jiawei Shao016105b2018-04-12 16:38:31 +08002397 ASSERT(mState.mAttachedShaders[ShaderType::Fragment]);
Jiawei Shaod063aff2018-02-22 10:19:09 +08002398
2399 std::map<GLuint, std::string> staticFragmentInputLocations;
2400
2401 const std::vector<sh::Varying> &fragmentInputVaryings =
Jiawei Shao016105b2018-04-12 16:38:31 +08002402 mState.mAttachedShaders[ShaderType::Fragment]->getInputVaryings(context);
Jiawei Shaod063aff2018-02-22 10:19:09 +08002403 for (const sh::Varying &input : fragmentInputVaryings)
2404 {
2405 if (input.isBuiltIn() || !input.staticUse)
2406 {
Sami Väisänen46eaa942016-06-29 10:26:37 +03002407 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002408 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002409
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002410 const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
Sami Väisänen46eaa942016-06-29 10:26:37 +03002411 if (inputBinding == -1)
2412 continue;
2413
2414 const auto it = staticFragmentInputLocations.find(inputBinding);
2415 if (it == std::end(staticFragmentInputLocations))
2416 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002417 staticFragmentInputLocations.insert(std::make_pair(inputBinding, input.name));
Sami Väisänen46eaa942016-06-29 10:26:37 +03002418 }
2419 else
2420 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002421 infoLog << "Binding for fragment input " << input.name << " conflicts with "
Sami Väisänen46eaa942016-06-29 10:26:37 +03002422 << it->second;
2423 return false;
2424 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002425 }
2426
2427 return true;
2428}
2429
Jamie Madillbd044ed2017-06-05 12:59:21 -04002430bool Program::linkUniforms(const Context *context,
2431 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002432 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002433{
Olli Etuahob78707c2017-03-09 15:03:11 +00002434 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002435 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002436 {
2437 return false;
2438 }
2439
Olli Etuahob78707c2017-03-09 15:03:11 +00002440 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002441
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002442 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002443
jchen10eaef1e52017-06-13 10:44:11 +08002444 if (!linkAtomicCounterBuffers())
2445 {
2446 return false;
2447 }
2448
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002449 return true;
2450}
2451
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002452void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002453{
Jamie Madill982f6e02017-06-07 14:33:04 -04002454 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2455 unsigned int low = high;
2456
jchen10eaef1e52017-06-13 10:44:11 +08002457 for (auto counterIter = mState.mUniforms.rbegin();
2458 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2459 {
2460 --low;
2461 }
2462
2463 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2464
2465 high = low;
2466
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002467 for (auto imageIter = mState.mUniforms.rbegin();
2468 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2469 {
2470 --low;
2471 }
2472
2473 mState.mImageUniformRange = RangeUI(low, high);
2474
2475 // If uniform is a image type, insert it into the mImageBindings array.
2476 for (unsigned int imageIndex : mState.mImageUniformRange)
2477 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002478 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2479 // cannot load values into a uniform defined as an image. if declare without a
2480 // binding qualifier, any uniform image variable (include all elements of
2481 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002482 auto &imageUniform = mState.mUniforms[imageIndex];
2483 if (imageUniform.binding == -1)
2484 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002485 mState.mImageBindings.emplace_back(
2486 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002487 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002488 else
2489 {
2490 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002491 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002492 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002493 }
2494
2495 high = low;
2496
2497 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002498 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002499 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002500 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002501 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002502
2503 mState.mSamplerUniformRange = RangeUI(low, high);
2504
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002505 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002506 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002507 {
2508 const auto &samplerUniform = mState.mUniforms[samplerIndex];
Corentin Wallezf0e89be2017-11-08 14:00:32 -08002509 TextureType textureType = SamplerTypeToTextureType(samplerUniform.type);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002510 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002511 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002512 }
2513}
2514
jchen10eaef1e52017-06-13 10:44:11 +08002515bool Program::linkAtomicCounterBuffers()
2516{
2517 for (unsigned int index : mState.mAtomicCounterUniformRange)
2518 {
2519 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002520 uniform.blockInfo.offset = uniform.offset;
2521 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2522 uniform.blockInfo.matrixStride = 0;
2523 uniform.blockInfo.isRowMajorMatrix = false;
2524
jchen10eaef1e52017-06-13 10:44:11 +08002525 bool found = false;
2526 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2527 ++bufferIndex)
2528 {
2529 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2530 if (buffer.binding == uniform.binding)
2531 {
2532 buffer.memberIndexes.push_back(index);
2533 uniform.bufferIndex = bufferIndex;
2534 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002535 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002536 break;
2537 }
2538 }
2539 if (!found)
2540 {
2541 AtomicCounterBuffer atomicCounterBuffer;
2542 atomicCounterBuffer.binding = uniform.binding;
2543 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002544 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002545 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2546 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2547 }
2548 }
2549 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
Jiawei Shao0d88ec92018-02-27 16:25:31 +08002550 // gl_Max[Vertex|Fragment|Compute|Geometry|Combined]AtomicCounterBuffers.
jchen10eaef1e52017-06-13 10:44:11 +08002551
2552 return true;
2553}
2554
Jamie Madilleb979bf2016-11-15 12:28:46 -05002555// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002556bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002557{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002558 const ContextState &data = context->getContextState();
Jiawei Shao385b3e02018-03-21 09:43:28 +08002559 Shader *vertexShader = mState.getAttachedShader(ShaderType::Vertex);
Jamie Madilleb979bf2016-11-15 12:28:46 -05002560
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002561 int shaderVersion = vertexShader->getShaderVersion(context);
2562
Geoff Lang7dd2e102014-11-10 15:19:26 -05002563 unsigned int usedLocations = 0;
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002564 if (shaderVersion >= 300)
2565 {
2566 // In GLSL ES 3.00.6, aliasing checks should be done with all declared attributes - see GLSL
2567 // ES 3.00.6 section 12.46. Inactive attributes will be pruned after aliasing checks.
2568 mState.mAttributes = vertexShader->getAllAttributes(context);
2569 }
2570 else
2571 {
2572 // In GLSL ES 1.00.17 we only do aliasing checks for active attributes.
2573 mState.mAttributes = vertexShader->getActiveAttributes(context);
2574 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002575 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002576
2577 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002578 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002579 {
Jamie Madillf6113162015-05-07 11:49:21 -04002580 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002581 return false;
2582 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002583
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002584 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002585
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002586 // Assign locations to attributes that have a binding location and check for attribute aliasing.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002587 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002588 {
Olli Etuahod2551232017-10-26 20:03:33 +03002589 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2590 // structures, so we don't need to worry about adjusting their names or generating entries
2591 // for each member/element (unlike uniforms for example).
2592 ASSERT(!attribute.isArray() && !attribute.isStruct());
2593
Jamie Madilleb979bf2016-11-15 12:28:46 -05002594 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002595 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002596 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002597 attribute.location = bindingLocation;
2598 }
2599
2600 if (attribute.location != -1)
2601 {
2602 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002603 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002604
Jamie Madill63805b42015-08-25 13:17:39 -04002605 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002606 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002607 infoLog << "Attribute (" << attribute.name << ") at location " << attribute.location
2608 << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002609
2610 return false;
2611 }
2612
Jamie Madill63805b42015-08-25 13:17:39 -04002613 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002614 {
Jamie Madill63805b42015-08-25 13:17:39 -04002615 const int regLocation = attribute.location + reg;
2616 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002617
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002618 // In GLSL ES 3.00.6 and in WebGL, attribute aliasing produces a link error.
2619 // In non-WebGL GLSL ES 1.00.17, attribute aliasing is allowed with some
2620 // restrictions - see GLSL ES 1.00.17 section 2.10.4, but ANGLE currently has a bug.
Jamie Madillc349ec02015-08-21 16:53:12 -04002621 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002622 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002623 // TODO(jmadill): fix aliasing on ES2
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002624 // if (shaderVersion >= 300 && !webgl)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002625 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002626 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002627 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002628 return false;
2629 }
2630 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002631 else
2632 {
Jamie Madill63805b42015-08-25 13:17:39 -04002633 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002634 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002635
Jamie Madill63805b42015-08-25 13:17:39 -04002636 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002637 }
2638 }
2639 }
2640
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002641 // Assign locations to attributes that don't have a binding location.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002642 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002643 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002644 // Not set by glBindAttribLocation or by location layout qualifier
2645 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002646 {
Jamie Madill63805b42015-08-25 13:17:39 -04002647 int regs = VariableRegisterCount(attribute.type);
2648 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002649
Jamie Madill63805b42015-08-25 13:17:39 -04002650 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002651 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002652 infoLog << "Too many attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002653 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002654 }
2655
Jamie Madillc349ec02015-08-21 16:53:12 -04002656 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002657 }
2658 }
2659
Brandon Jonesc405ae72017-12-06 14:15:03 -08002660 ASSERT(mState.mAttributesTypeMask.none());
2661 ASSERT(mState.mAttributesMask.none());
2662
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002663 // Prune inactive attributes. This step is only needed on shaderVersion >= 300 since on earlier
2664 // shader versions we're only processing active attributes to begin with.
2665 if (shaderVersion >= 300)
2666 {
2667 for (auto attributeIter = mState.mAttributes.begin();
2668 attributeIter != mState.mAttributes.end();)
2669 {
2670 if (attributeIter->active)
2671 {
2672 ++attributeIter;
2673 }
2674 else
2675 {
2676 attributeIter = mState.mAttributes.erase(attributeIter);
2677 }
2678 }
2679 }
2680
Jamie Madill48ef11b2016-04-27 15:21:52 -04002681 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002682 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002683 ASSERT(attribute.active);
Jamie Madill63805b42015-08-25 13:17:39 -04002684 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002685 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002686
Jamie Madillbd159f02017-10-09 19:39:06 -04002687 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002688 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002689 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2690 mState.mActiveAttribLocationsMask.set(location);
2691 mState.mMaxActiveAttribLocation =
2692 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08002693
2694 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
2695 if (!attribute.isBuiltIn())
2696 {
2697 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
2698 location);
2699 mState.mAttributesMask.set(location);
2700 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002701 }
2702 }
2703
Geoff Lang7dd2e102014-11-10 15:19:26 -05002704 return true;
2705}
2706
Jiajia Qin729b2c62017-08-14 09:36:11 +08002707bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002708{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002709 const auto &caps = context->getCaps();
2710
Jiawei Shao016105b2018-04-12 16:38:31 +08002711 if (mState.mAttachedShaders[ShaderType::Compute])
Martin Radev4c4c8e72016-08-04 12:25:34 +03002712 {
Jiawei Shao016105b2018-04-12 16:38:31 +08002713 Shader &computeShader = *mState.mAttachedShaders[ShaderType::Compute];
Jiajia Qin729b2c62017-08-14 09:36:11 +08002714 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002715
Jiawei Shao427071e2018-03-19 09:21:37 +08002716 if (!ValidateInterfaceBlocksCount(
Jiajia Qin729b2c62017-08-14 09:36:11 +08002717 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002718 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2719 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002720 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002721 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002722 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002723
2724 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
Jiawei Shao427071e2018-03-19 09:21:37 +08002725 if (!ValidateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
Jiajia Qin729b2c62017-08-14 09:36:11 +08002726 computeShaderStorageBlocks,
2727 "Compute shader shader storage block count exceeds "
2728 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2729 infoLog))
2730 {
2731 return false;
2732 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002733 return true;
2734 }
2735
Jiawei Shao016105b2018-04-12 16:38:31 +08002736 Shader &vertexShader = *mState.mAttachedShaders[ShaderType::Vertex];
2737 Shader &fragmentShader = *mState.mAttachedShaders[ShaderType::Fragment];
Martin Radev4c4c8e72016-08-04 12:25:34 +03002738
Jiajia Qin729b2c62017-08-14 09:36:11 +08002739 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2740 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002741
Jiawei Shao427071e2018-03-19 09:21:37 +08002742 if (!ValidateInterfaceBlocksCount(
Jiajia Qin729b2c62017-08-14 09:36:11 +08002743 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002744 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2745 {
2746 return false;
2747 }
Jiawei Shao427071e2018-03-19 09:21:37 +08002748 if (!ValidateInterfaceBlocksCount(
Jiajia Qin729b2c62017-08-14 09:36:11 +08002749 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002750 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2751 infoLog))
2752 {
2753
2754 return false;
2755 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002756
Jiawei Shao016105b2018-04-12 16:38:31 +08002757 Shader *geometryShader = mState.mAttachedShaders[ShaderType::Geometry];
Jiawei Shao427071e2018-03-19 09:21:37 +08002758 if (geometryShader)
2759 {
2760 const auto &geometryUniformBlocks = geometryShader->getUniformBlocks(context);
2761 if (!ValidateInterfaceBlocksCount(
2762 caps.maxGeometryUniformBlocks, geometryUniformBlocks,
2763 "Geometry shader uniform block count exceeds GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT (",
2764 infoLog))
2765 {
2766 return false;
2767 }
2768 }
2769
2770 // TODO(jiawei.shao@intel.com): validate geometry shader uniform blocks.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002771 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiawei Shao73618602017-12-20 15:47:15 +08002772 if (!ValidateGraphicsInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002773 webglCompatibility, sh::BlockType::BLOCK_UNIFORM,
2774 caps.maxCombinedUniformBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002775 {
2776 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002777 }
Jamie Madille473dee2015-08-18 14:49:01 -04002778
Jiajia Qin729b2c62017-08-14 09:36:11 +08002779 if (context->getClientVersion() >= Version(3, 1))
2780 {
2781 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2782 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2783
Jiawei Shao427071e2018-03-19 09:21:37 +08002784 if (!ValidateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
Jiajia Qin729b2c62017-08-14 09:36:11 +08002785 vertexShaderStorageBlocks,
2786 "Vertex shader shader storage block count exceeds "
2787 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2788 infoLog))
2789 {
2790 return false;
2791 }
Jiawei Shao427071e2018-03-19 09:21:37 +08002792 if (!ValidateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
Jiajia Qin729b2c62017-08-14 09:36:11 +08002793 fragmentShaderStorageBlocks,
2794 "Fragment shader shader storage block count exceeds "
2795 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2796 infoLog))
2797 {
2798
2799 return false;
2800 }
2801
Jiawei Shao427071e2018-03-19 09:21:37 +08002802 if (geometryShader)
2803 {
2804 const auto &geometryShaderStorageBlocks =
2805 geometryShader->getShaderStorageBlocks(context);
2806 if (!ValidateInterfaceBlocksCount(caps.maxGeometryShaderStorageBlocks,
2807 geometryShaderStorageBlocks,
2808 "Geometry shader shader storage block count exceeds "
2809 "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT (",
2810 infoLog))
2811 {
2812 return false;
2813 }
2814 }
2815
2816 // TODO(jiawei.shao@intel.com): validate geometry shader shader storage blocks.
Jiajia Qin8efd1262017-12-19 09:32:55 +08002817 if (!ValidateGraphicsInterfaceBlocks(
2818 vertexShaderStorageBlocks, fragmentShaderStorageBlocks, infoLog, webglCompatibility,
2819 sh::BlockType::BLOCK_BUFFER, caps.maxCombinedShaderStorageBlocks))
Jiajia Qin729b2c62017-08-14 09:36:11 +08002820 {
2821 return false;
2822 }
2823 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002824 return true;
2825}
2826
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002827LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &variable1,
2828 const sh::ShaderVariable &variable2,
2829 bool validatePrecision,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002830 bool validateArraySize,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002831 std::string *mismatchedStructOrBlockMemberName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002832{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002833 if (variable1.type != variable2.type)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002834 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002835 return LinkMismatchError::TYPE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002836 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002837 if (validateArraySize && variable1.arraySizes != variable2.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002838 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002839 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002840 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002841 if (validatePrecision && variable1.precision != variable2.precision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002842 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002843 return LinkMismatchError::PRECISION_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002844 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002845 if (variable1.structName != variable2.structName)
Geoff Langbb1e7502017-06-05 16:40:09 -04002846 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002847 return LinkMismatchError::STRUCT_NAME_MISMATCH;
Geoff Langbb1e7502017-06-05 16:40:09 -04002848 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002849
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002850 if (variable1.fields.size() != variable2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002851 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002852 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002853 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002854 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002855 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2856 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002857 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2858 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002859
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002860 if (member1.name != member2.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002861 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002862 return LinkMismatchError::FIELD_NAME_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002863 }
2864
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002865 LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08002866 member1, member2, validatePrecision, true, mismatchedStructOrBlockMemberName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002867 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002868 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002869 AddParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2870 return linkErrorOnField;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002871 }
2872 }
2873
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002874 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002875}
2876
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002877LinkMismatchError Program::LinkValidateVaryings(const sh::Varying &outputVarying,
2878 const sh::Varying &inputVarying,
2879 int shaderVersion,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002880 bool validateGeometryShaderInputVarying,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002881 std::string *mismatchedStructFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002882{
Jiawei Shaod063aff2018-02-22 10:19:09 +08002883 if (validateGeometryShaderInputVarying)
2884 {
2885 // [GL_EXT_geometry_shader] Section 11.1gs.4.3:
2886 // The OpenGL ES Shading Language doesn't support multi-dimensional arrays as shader inputs
2887 // or outputs.
2888 ASSERT(inputVarying.arraySizes.size() == 1u);
2889
2890 // Geometry shader input varyings are not treated as arrays, so a vertex array output
2891 // varying cannot match a geometry shader input varying.
2892 // [GL_EXT_geometry_shader] Section 7.4.1:
2893 // Geometry shader per-vertex input variables and blocks are required to be declared as
2894 // arrays, with each element representing input or output values for a single vertex of a
2895 // multi-vertex primitive. For the purposes of interface matching, such variables and blocks
2896 // are treated as though they were not declared as arrays.
2897 if (outputVarying.isArray())
2898 {
2899 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2900 }
2901 }
2902
2903 // Skip the validation on the array sizes between a vertex output varying and a geometry input
2904 // varying as it has been done before.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002905 LinkMismatchError linkError =
Jiawei Shaod063aff2018-02-22 10:19:09 +08002906 LinkValidateVariablesBase(outputVarying, inputVarying, false,
2907 !validateGeometryShaderInputVarying, mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002908 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002909 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002910 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002911 }
2912
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002913 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002914 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002915 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002916 }
2917
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002918 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002919 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002920 return LinkMismatchError::INVARIANCE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002921 }
2922
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002923 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002924}
2925
Jamie Madillbd044ed2017-06-05 12:59:21 -04002926bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002927{
Jiawei Shao016105b2018-04-12 16:38:31 +08002928 Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
2929 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
Jiawei Shao3d404882017-10-16 13:30:48 +08002930 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2931 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002932 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002933
2934 if (shaderVersion != 100)
2935 {
2936 // Only ESSL 1.0 has restrictions on matching input and output invariance
2937 return true;
2938 }
2939
2940 bool glPositionIsInvariant = false;
2941 bool glPointSizeIsInvariant = false;
2942 bool glFragCoordIsInvariant = false;
2943 bool glPointCoordIsInvariant = false;
2944
2945 for (const sh::Varying &varying : vertexVaryings)
2946 {
2947 if (!varying.isBuiltIn())
2948 {
2949 continue;
2950 }
2951 if (varying.name.compare("gl_Position") == 0)
2952 {
2953 glPositionIsInvariant = varying.isInvariant;
2954 }
2955 else if (varying.name.compare("gl_PointSize") == 0)
2956 {
2957 glPointSizeIsInvariant = varying.isInvariant;
2958 }
2959 }
2960
2961 for (const sh::Varying &varying : fragmentVaryings)
2962 {
2963 if (!varying.isBuiltIn())
2964 {
2965 continue;
2966 }
2967 if (varying.name.compare("gl_FragCoord") == 0)
2968 {
2969 glFragCoordIsInvariant = varying.isInvariant;
2970 }
2971 else if (varying.name.compare("gl_PointCoord") == 0)
2972 {
2973 glPointCoordIsInvariant = varying.isInvariant;
2974 }
2975 }
2976
2977 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2978 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2979 // Not requiring invariance to match is supported by:
2980 // dEQP, WebGL CTS, Nexus 5X GLES
2981 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2982 {
2983 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2984 "declared invariant.";
2985 return false;
2986 }
2987 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2988 {
2989 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2990 "declared invariant.";
2991 return false;
2992 }
2993
2994 return true;
2995}
2996
jchen10a9042d32017-03-17 08:50:45 +08002997bool Program::linkValidateTransformFeedback(const gl::Context *context,
2998 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002999 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04003000 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05003001{
Geoff Lang7dd2e102014-11-10 15:19:26 -05003002
jchen108225e732017-11-14 16:29:03 +08003003 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04003004 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04003005 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003006 {
jchen10a9042d32017-03-17 08:50:45 +08003007 if (context->getClientVersion() < Version(3, 1) &&
3008 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04003009 {
Geoff Lang1a683462015-09-29 15:09:59 -04003010 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04003011 return false;
3012 }
jchen108225e732017-11-14 16:29:03 +08003013 if (context->getClientVersion() >= Version(3, 1))
3014 {
3015 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
3016 {
3017 infoLog << "Two transform feedback varyings include the same array element ("
3018 << tfVaryingName << ").";
3019 return false;
3020 }
3021 }
3022 else
3023 {
3024 if (uniqueNames.count(tfVaryingName) > 0)
3025 {
3026 infoLog << "Two transform feedback varyings specify the same output variable ("
3027 << tfVaryingName << ").";
3028 return false;
3029 }
3030 }
3031 uniqueNames.insert(tfVaryingName);
3032 }
3033
3034 // Validate against program varyings.
3035 size_t totalComponents = 0;
3036 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
3037 {
3038 std::vector<unsigned int> subscripts;
3039 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
3040
3041 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
3042 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08003043 {
3044 infoLog << "Transform feedback varying " << tfVaryingName
3045 << " does not exist in the vertex shader.";
3046 return false;
3047 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003048
jchen108225e732017-11-14 16:29:03 +08003049 // Validate the matching variable.
3050 if (var->isStruct())
3051 {
3052 infoLog << "Struct cannot be captured directly (" << baseName << ").";
3053 return false;
3054 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003055
jchen108225e732017-11-14 16:29:03 +08003056 size_t elementCount = 0;
3057 size_t componentCount = 0;
3058
3059 if (var->isArray())
3060 {
3061 if (context->getClientVersion() < Version(3, 1))
3062 {
3063 infoLog << "Capture of arrays is undefined and not supported.";
3064 return false;
3065 }
3066
3067 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
3068 ASSERT(!var->isArrayOfArrays());
3069
3070 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
3071 {
3072 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
3073 return false;
3074 }
3075 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
3076 }
3077 else
3078 {
3079 if (!subscripts.empty())
3080 {
3081 infoLog << "Varying '" << baseName
3082 << "' is not an array to be captured by element.";
3083 return false;
3084 }
3085 elementCount = 1;
3086 }
3087
3088 // TODO(jmadill): Investigate implementation limits on D3D11
3089 componentCount = VariableComponentCount(var->type) * elementCount;
3090 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
3091 componentCount > caps.maxTransformFeedbackSeparateComponents)
3092 {
3093 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
3094 << componentCount << ") exceed the maximum separate components ("
3095 << caps.maxTransformFeedbackSeparateComponents << ").";
3096 return false;
3097 }
3098
3099 totalComponents += componentCount;
3100 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
3101 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
3102 {
3103 infoLog << "Transform feedback varying total components (" << totalComponents
3104 << ") exceed the maximum interleaved components ("
3105 << caps.maxTransformFeedbackInterleavedComponents << ").";
3106 return false;
3107 }
3108 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003109 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05003110}
3111
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003112bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
3113{
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003114 const std::vector<sh::Attribute> &attributes =
Jiawei Shao016105b2018-04-12 16:38:31 +08003115 mState.mAttachedShaders[ShaderType::Vertex]->getActiveAttributes(context);
3116
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003117 for (const auto &attrib : attributes)
3118 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003119 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003120 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003121 Shader *shader = mState.mAttachedShaders[shaderType];
3122 if (!shader)
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003123 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003124 continue;
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003125 }
Jiawei Shao016105b2018-04-12 16:38:31 +08003126
3127 const std::vector<sh::Uniform> &uniforms = shader->getUniforms(context);
3128 for (const auto &uniform : uniforms)
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003129 {
3130 if (uniform.name == attrib.name)
3131 {
3132 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3133 return false;
3134 }
3135 }
3136 }
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003137 }
Jiawei Shao016105b2018-04-12 16:38:31 +08003138
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003139 return true;
3140}
3141
Jamie Madill3c1da042017-11-27 18:33:40 -05003142void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003143{
3144 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08003145 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04003146 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003147 {
Olli Etuahoc8538042017-09-27 11:20:15 +03003148 std::vector<unsigned int> subscripts;
3149 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08003150 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03003151 if (!subscripts.empty())
3152 {
3153 subscript = subscripts.back();
3154 }
Jamie Madill192745a2016-12-22 15:58:21 -05003155 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003156 {
Jamie Madill192745a2016-12-22 15:58:21 -05003157 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08003158 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003159 {
jchen10a9042d32017-03-17 08:50:45 +08003160 mState.mLinkedTransformFeedbackVaryings.emplace_back(
3161 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04003162 break;
3163 }
jchen108225e732017-11-14 16:29:03 +08003164 else if (varying->isStruct())
3165 {
3166 const auto *field = FindShaderVarField(*varying, tfVaryingName);
3167 if (field != nullptr)
3168 {
3169 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
3170 break;
3171 }
3172 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04003173 }
3174 }
James Darpinian30b604d2018-03-12 17:26:57 -07003175 mState.updateTransformFeedbackStrides();
Jamie Madillccdf74b2015-08-18 10:46:12 -04003176}
3177
Jamie Madill3c1da042017-11-27 18:33:40 -05003178ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04003179{
Jamie Madill3c1da042017-11-27 18:33:40 -05003180 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003181
Jiawei Shao016105b2018-04-12 16:38:31 +08003182 for (const sh::Varying &varying :
3183 mState.mAttachedShaders[ShaderType::Vertex]->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003184 {
Jamie Madill192745a2016-12-22 15:58:21 -05003185 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003186 }
3187
Jiawei Shao016105b2018-04-12 16:38:31 +08003188 for (const sh::Varying &varying :
3189 mState.mAttachedShaders[ShaderType::Fragment]->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003190 {
Jamie Madill192745a2016-12-22 15:58:21 -05003191 merged[varying.name].fragment = &varying;
3192 }
3193
3194 return merged;
3195}
3196
Jamie Madillbd044ed2017-06-05 12:59:21 -04003197void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003198{
Jiawei Shao016105b2018-04-12 16:38:31 +08003199 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003200 ASSERT(fragmentShader != nullptr);
3201
Geoff Lange0cff192017-05-30 13:04:56 -04003202 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04003203 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08003204 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04003205
3206 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04003207 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04003208 {
3209 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
3210 outputVariable.name != "gl_FragData")
3211 {
3212 continue;
3213 }
3214
3215 unsigned int baseLocation =
3216 (outputVariable.location == -1 ? 0u
3217 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03003218
3219 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3220 // structures, so we may use getBasicTypeElementCount().
3221 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3222 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04003223 {
3224 const unsigned int location = baseLocation + elementIndex;
3225 if (location >= mState.mOutputVariableTypes.size())
3226 {
3227 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
3228 }
Corentin Walleze7557742017-06-01 13:09:57 -04003229 ASSERT(location < mState.mActiveOutputVariables.size());
3230 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04003231 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08003232 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04003233 }
3234 }
3235
Jamie Madill80a6fc02015-08-21 16:53:16 -04003236 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04003237 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003238 return;
3239
Jamie Madillbd044ed2017-06-05 12:59:21 -04003240 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04003241 // TODO(jmadill): any caps validation here?
3242
jchen1015015f72017-03-16 13:54:21 +08003243 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04003244 outputVariableIndex++)
3245 {
jchen1015015f72017-03-16 13:54:21 +08003246 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003247
Olli Etuahod2551232017-10-26 20:03:33 +03003248 if (outputVariable.isArray())
3249 {
3250 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
3251 // Resources and including [0] at the end of array variable names.
3252 mState.mOutputVariables[outputVariableIndex].name += "[0]";
3253 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
3254 }
3255
Jamie Madill80a6fc02015-08-21 16:53:16 -04003256 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3257 if (outputVariable.isBuiltIn())
3258 continue;
3259
3260 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03003261 unsigned int baseLocation =
3262 (outputVariable.location == -1 ? 0u
3263 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04003264
Olli Etuaho465835d2017-09-26 13:34:10 +03003265 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3266 // structures, so we may use getBasicTypeElementCount().
3267 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3268 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003269 {
Olli Etuahod2551232017-10-26 20:03:33 +03003270 const unsigned int location = baseLocation + elementIndex;
3271 if (location >= mState.mOutputLocations.size())
3272 {
3273 mState.mOutputLocations.resize(location + 1);
3274 }
3275 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03003276 if (outputVariable.isArray())
3277 {
3278 mState.mOutputLocations[location] =
3279 VariableLocation(elementIndex, outputVariableIndex);
3280 }
3281 else
3282 {
3283 VariableLocation locationInfo;
3284 locationInfo.index = outputVariableIndex;
3285 mState.mOutputLocations[location] = locationInfo;
3286 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003287 }
3288 }
3289}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003290
Olli Etuaho48fed632017-03-16 12:05:30 +00003291void Program::setUniformValuesFromBindingQualifiers()
3292{
Jamie Madill982f6e02017-06-07 14:33:04 -04003293 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003294 {
3295 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3296 if (samplerUniform.binding != -1)
3297 {
Olli Etuahod2551232017-10-26 20:03:33 +03003298 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003299 ASSERT(location != -1);
3300 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003301 for (unsigned int elementIndex = 0;
3302 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003303 {
3304 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3305 }
3306 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3307 boundTextureUnits.data());
3308 }
3309 }
3310}
3311
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003312void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003313{
jchen10af713a22017-04-19 09:10:56 +08003314 // Set initial bindings from shader.
3315 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3316 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003317 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003318 bindUniformBlock(blockIndex, uniformBlock.binding);
3319 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003320}
3321
Jamie Madille7d84322017-01-10 18:21:59 -05003322void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003323 GLsizei clampedCount,
3324 const GLint *v)
3325{
Jamie Madill81c2e252017-09-09 23:32:46 -04003326 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3327 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3328 std::vector<GLuint> *boundTextureUnits =
3329 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003330
Olli Etuaho1734e172017-10-27 15:30:27 +03003331 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04003332
3333 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003334 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003335}
3336
3337template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003338GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3339 GLsizei count,
3340 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003341 const T *v)
3342{
Jamie Madill134f93d2017-08-31 17:11:00 -04003343 if (count == 1)
3344 return 1;
3345
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003346 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003347
Corentin Wallez15ac5342016-11-03 17:06:39 -04003348 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3349 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003350 unsigned int remainingElements =
3351 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003352 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003353 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003354
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003355 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003356 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003357 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003358 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003359
3360 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003361}
3362
3363template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003364GLsizei Program::clampMatrixUniformCount(GLint location,
3365 GLsizei count,
3366 GLboolean transpose,
3367 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003368{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003369 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3370
Jamie Madill62d31cb2015-09-11 13:25:51 -04003371 if (!transpose)
3372 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003373 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003374 }
3375
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003376 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003377
3378 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3379 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003380 unsigned int remainingElements =
3381 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003382 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003383}
3384
Jamie Madill54164b02017-08-28 15:17:37 -04003385// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3386// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003387template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003388void Program::getUniformInternal(const Context *context,
3389 DestT *dataOut,
3390 GLint location,
3391 GLenum nativeType,
3392 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003393{
Jamie Madill54164b02017-08-28 15:17:37 -04003394 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003395 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003396 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003397 {
3398 GLint tempValue[16] = {0};
3399 mProgram->getUniformiv(context, location, tempValue);
3400 UniformStateQueryCastLoop<GLboolean>(
3401 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003402 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003403 }
3404 case GL_INT:
3405 {
3406 GLint tempValue[16] = {0};
3407 mProgram->getUniformiv(context, location, tempValue);
3408 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3409 components);
3410 break;
3411 }
3412 case GL_UNSIGNED_INT:
3413 {
3414 GLuint tempValue[16] = {0};
3415 mProgram->getUniformuiv(context, location, tempValue);
3416 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3417 components);
3418 break;
3419 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003420 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003421 {
3422 GLfloat tempValue[16] = {0};
3423 mProgram->getUniformfv(context, location, tempValue);
3424 UniformStateQueryCastLoop<GLfloat>(
3425 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003426 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003427 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003428 default:
3429 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003430 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003431 }
3432}
Jamie Madilla4595b82017-01-11 17:36:34 -05003433
3434bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3435{
3436 // Must be called after samplers are validated.
3437 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3438
3439 for (const auto &binding : mState.mSamplerBindings)
3440 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08003441 TextureType textureType = binding.textureType;
Jamie Madilla4595b82017-01-11 17:36:34 -05003442 for (const auto &unit : binding.boundTextureUnits)
3443 {
3444 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3445 if (programTextureID == textureID)
3446 {
3447 // TODO(jmadill): Check for appropriate overlap.
3448 return true;
3449 }
3450 }
3451 }
3452
3453 return false;
3454}
3455
Jamie Madilla2c74982016-12-12 11:20:42 -05003456} // namespace gl