blob: 51dd9177dbe7723d6fa969a9e79060459b9797ab [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"
jchen103fd614d2018-08-13 12:21:58 +080026#include "libANGLE/Version.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040027#include "libANGLE/features.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040028#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040029#include "libANGLE/queryconversions.h"
30#include "libANGLE/renderer/GLImplFactory.h"
31#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040032#include "platform/Platform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050033
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000034namespace gl
35{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000036
Geoff Lang7dd2e102014-11-10 15:19:26 -050037namespace
38{
39
Jamie Madill62d31cb2015-09-11 13:25:51 -040040// This simplified cast function doesn't need to worry about advanced concepts like
41// depth range values, or casting to bool.
42template <typename DestT, typename SrcT>
43DestT UniformStateQueryCast(SrcT value);
44
45// From-Float-To-Integer Casts
46template <>
47GLint UniformStateQueryCast(GLfloat value)
48{
49 return clampCast<GLint>(roundf(value));
50}
51
52template <>
53GLuint UniformStateQueryCast(GLfloat value)
54{
55 return clampCast<GLuint>(roundf(value));
56}
57
58// From-Integer-to-Integer Casts
59template <>
60GLint UniformStateQueryCast(GLuint value)
61{
62 return clampCast<GLint>(value);
63}
64
65template <>
66GLuint UniformStateQueryCast(GLint value)
67{
68 return clampCast<GLuint>(value);
69}
70
71// From-Boolean-to-Anything Casts
72template <>
73GLfloat UniformStateQueryCast(GLboolean value)
74{
Geoff Lang92019432017-11-20 13:09:34 -050075 return (ConvertToBool(value) ? 1.0f : 0.0f);
Jamie Madill62d31cb2015-09-11 13:25:51 -040076}
77
78template <>
79GLint UniformStateQueryCast(GLboolean value)
80{
Geoff Lang92019432017-11-20 13:09:34 -050081 return (ConvertToBool(value) ? 1 : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -040082}
83
84template <>
85GLuint UniformStateQueryCast(GLboolean value)
86{
Geoff Lang92019432017-11-20 13:09:34 -050087 return (ConvertToBool(value) ? 1u : 0u);
Jamie Madill62d31cb2015-09-11 13:25:51 -040088}
89
90// Default to static_cast
91template <typename DestT, typename SrcT>
92DestT UniformStateQueryCast(SrcT value)
93{
94 return static_cast<DestT>(value);
95}
96
97template <typename SrcT, typename DestT>
98void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
99{
100 for (int comp = 0; comp < components; ++comp)
101 {
102 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
103 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
104 size_t offset = comp * 4;
105 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
106 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
107 }
108}
109
jchen1015015f72017-03-16 13:54:21 +0800110template <typename VarT>
111GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
112{
Olli Etuahod2551232017-10-26 20:03:33 +0300113 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800114 for (size_t index = 0; index < list.size(); index++)
115 {
116 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300117 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800118 {
Olli Etuahod2551232017-10-26 20:03:33 +0300119 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800120 }
121 }
122
123 return GL_INVALID_INDEX;
124}
125
Olli Etuahod2551232017-10-26 20:03:33 +0300126template <typename VarT>
127GLint GetVariableLocation(const std::vector<VarT> &list,
128 const std::vector<VariableLocation> &locationList,
129 const std::string &name)
130{
131 size_t nameLengthWithoutArrayIndex;
132 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
133
134 for (size_t location = 0u; location < locationList.size(); ++location)
135 {
136 const VariableLocation &variableLocation = locationList[location];
137 if (!variableLocation.used())
138 {
139 continue;
140 }
141
142 const VarT &variable = list[variableLocation.index];
143
144 if (angle::BeginsWith(variable.name, name))
145 {
146 if (name.length() == variable.name.length())
147 {
148 ASSERT(name == variable.name);
149 // GLES 3.1 November 2016 page 87.
150 // The string exactly matches the name of the active variable.
151 return static_cast<GLint>(location);
152 }
153 if (name.length() + 3u == variable.name.length() && variable.isArray())
154 {
155 ASSERT(name + "[0]" == variable.name);
156 // The string identifies the base name of an active array, where the string would
157 // exactly match the name of the variable if the suffix "[0]" were appended to the
158 // string.
159 return static_cast<GLint>(location);
160 }
161 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300162 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300163 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
164 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
165 {
166 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
167 // The string identifies an active element of the array, where the string ends with the
168 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
169 // zeroes, or whitespace) identifying an array element, and the "]" character, the
170 // integer is less than the number of active elements of the array variable, and where
171 // the string would exactly match the enumerated name of the array if the decimal
172 // integer were replaced with zero.
173 return static_cast<GLint>(location);
174 }
175 }
176
177 return -1;
178}
179
jchen10fd7c3b52017-03-21 15:36:03 +0800180void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
181{
182 ASSERT(bufSize > 0);
183 strncpy(buffer, string.c_str(), bufSize);
184 buffer[bufSize - 1] = '\0';
185
186 if (length)
187 {
188 *length = static_cast<GLsizei>(strlen(buffer));
189 }
190}
191
jchen10a9042d32017-03-17 08:50:45 +0800192bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
193{
Olli Etuahoc8538042017-09-27 11:20:15 +0300194 std::vector<unsigned int> subscripts;
195 std::string baseName = ParseResourceName(name, &subscripts);
196 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800197 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300198 std::vector<unsigned int> arrayIndices;
199 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
200 if (baseName == arrayName &&
201 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800202 {
203 return true;
204 }
205 }
206 return false;
207}
208
Jiawei Shao40786bd2018-04-18 13:58:57 +0800209std::string GetInterfaceBlockLimitName(ShaderType shaderType, sh::BlockType blockType)
210{
211 std::ostringstream stream;
212 stream << "GL_MAX_" << GetShaderTypeString(shaderType) << "_";
213
214 switch (blockType)
215 {
216 case sh::BlockType::BLOCK_UNIFORM:
217 stream << "UNIFORM_BUFFERS";
218 break;
219 case sh::BlockType::BLOCK_BUFFER:
220 stream << "SHADER_STORAGE_BLOCKS";
221 break;
222 default:
223 UNREACHABLE();
224 return "";
225 }
226
227 if (shaderType == ShaderType::Geometry)
228 {
229 stream << "_EXT";
230 }
231
232 return stream.str();
233}
234
235const char *GetInterfaceBlockTypeString(sh::BlockType blockType)
236{
237 switch (blockType)
238 {
239 case sh::BlockType::BLOCK_UNIFORM:
240 return "uniform block";
241 case sh::BlockType::BLOCK_BUFFER:
242 return "shader storage block";
243 default:
244 UNREACHABLE();
245 return "";
246 }
247}
248
249void LogInterfaceBlocksExceedLimit(InfoLog &infoLog,
250 ShaderType shaderType,
251 sh::BlockType blockType,
252 GLuint limit)
253{
254 infoLog << GetShaderTypeString(shaderType) << " shader "
255 << GetInterfaceBlockTypeString(blockType) << " count exceeds "
256 << GetInterfaceBlockLimitName(shaderType, blockType) << " (" << limit << ")";
257}
258
Jiawei Shao427071e2018-03-19 09:21:37 +0800259bool ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
Jiajia Qin729b2c62017-08-14 09:36:11 +0800260 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
Jiawei Shao40786bd2018-04-18 13:58:57 +0800261 ShaderType shaderType,
262 sh::BlockType blockType,
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800263 GLuint *combinedInterfaceBlocksCount,
Jiajia Qin729b2c62017-08-14 09:36:11 +0800264 InfoLog &infoLog)
265{
266 GLuint blockCount = 0;
267 for (const sh::InterfaceBlock &block : interfaceBlocks)
268 {
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800269 if (IsActiveInterfaceBlock(block))
Jiajia Qin729b2c62017-08-14 09:36:11 +0800270 {
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800271 blockCount += std::max(block.arraySize, 1u);
Jiajia Qin729b2c62017-08-14 09:36:11 +0800272 if (blockCount > maxInterfaceBlocks)
273 {
Jiawei Shao40786bd2018-04-18 13:58:57 +0800274 LogInterfaceBlocksExceedLimit(infoLog, shaderType, blockType, maxInterfaceBlocks);
Jiajia Qin729b2c62017-08-14 09:36:11 +0800275 return false;
276 }
277 }
278 }
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800279
280 // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
281 // If a uniform block is used by multiple shader stages, each such use counts separately
282 // against this combined limit.
283 // [OpenGL ES 3.1] Chapter 7.8 Page 111:
284 // If a shader storage block in a program is referenced by multiple shaders, each such
285 // reference counts separately against this combined limit.
286 if (combinedInterfaceBlocksCount)
287 {
288 *combinedInterfaceBlocksCount += blockCount;
289 }
290
Jiajia Qin729b2c62017-08-14 09:36:11 +0800291 return true;
292}
293
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800294GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
295{
296 std::vector<unsigned int> subscripts;
297 std::string baseName = ParseResourceName(name, &subscripts);
298
299 unsigned int numBlocks = static_cast<unsigned int>(list.size());
300 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
301 {
302 const auto &block = list[blockIndex];
303 if (block.name == baseName)
304 {
305 const bool arrayElementZero =
306 (subscripts.empty() && (!block.isArray || block.arrayElement == 0));
307 const bool arrayElementMatches =
308 (subscripts.size() == 1 && subscripts[0] == block.arrayElement);
309 if (arrayElementMatches || arrayElementZero)
310 {
311 return blockIndex;
312 }
313 }
314 }
315
316 return GL_INVALID_INDEX;
317}
318
319void GetInterfaceBlockName(const GLuint index,
320 const std::vector<InterfaceBlock> &list,
321 GLsizei bufSize,
322 GLsizei *length,
323 GLchar *name)
324{
325 ASSERT(index < list.size());
326
327 const auto &block = list[index];
328
329 if (bufSize > 0)
330 {
331 std::string blockName = block.name;
332
333 if (block.isArray)
334 {
335 blockName += ArrayString(block.arrayElement);
336 }
337 CopyStringToBuffer(name, blockName, bufSize, length);
338 }
339}
340
jchen103fd614d2018-08-13 12:21:58 +0800341void InitUniformBlockLinker(const ProgramState &state, UniformBlockLinker *blockLinker)
Jamie Madillc9727f32017-11-07 12:37:07 -0500342{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800343 for (ShaderType shaderType : AllShaderTypes())
Jamie Madillc9727f32017-11-07 12:37:07 -0500344 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800345 Shader *shader = state.getAttachedShader(shaderType);
346 if (shader)
347 {
jchen103fd614d2018-08-13 12:21:58 +0800348 blockLinker->addShaderBlocks(shaderType, &shader->getUniformBlocks());
Jiawei Shao385b3e02018-03-21 09:43:28 +0800349 }
Jamie Madillc9727f32017-11-07 12:37:07 -0500350 }
351}
352
jchen103fd614d2018-08-13 12:21:58 +0800353void InitShaderStorageBlockLinker(const ProgramState &state, ShaderStorageBlockLinker *blockLinker)
Jamie Madillc9727f32017-11-07 12:37:07 -0500354{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800355 for (ShaderType shaderType : AllShaderTypes())
Jamie Madillc9727f32017-11-07 12:37:07 -0500356 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800357 Shader *shader = state.getAttachedShader(shaderType);
358 if (shader != nullptr)
359 {
jchen103fd614d2018-08-13 12:21:58 +0800360 blockLinker->addShaderBlocks(shaderType, &shader->getShaderStorageBlocks());
Jiawei Shao385b3e02018-03-21 09:43:28 +0800361 }
Jamie Madillc9727f32017-11-07 12:37:07 -0500362 }
363}
364
jchen108225e732017-11-14 16:29:03 +0800365// Find the matching varying or field by name.
366const sh::ShaderVariable *FindVaryingOrField(const ProgramMergedVaryings &varyings,
367 const std::string &name)
368{
369 const sh::ShaderVariable *var = nullptr;
370 for (const auto &ref : varyings)
371 {
372 const sh::Varying *varying = ref.second.get();
373 if (varying->name == name)
374 {
375 var = varying;
376 break;
377 }
378 var = FindShaderVarField(*varying, name);
379 if (var != nullptr)
380 {
381 break;
382 }
383 }
384 return var;
385}
386
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800387void AddParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
388{
389 ASSERT(mismatchedFieldName);
390 if (mismatchedFieldName->empty())
391 {
392 *mismatchedFieldName = parentName;
393 }
394 else
395 {
396 std::ostringstream stream;
397 stream << parentName << "." << *mismatchedFieldName;
398 *mismatchedFieldName = stream.str();
399 }
400}
401
402const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
403{
404 switch (linkError)
405 {
406 case LinkMismatchError::TYPE_MISMATCH:
407 return "Type";
408 case LinkMismatchError::ARRAY_SIZE_MISMATCH:
409 return "Array size";
410 case LinkMismatchError::PRECISION_MISMATCH:
411 return "Precision";
412 case LinkMismatchError::STRUCT_NAME_MISMATCH:
413 return "Structure name";
414 case LinkMismatchError::FIELD_NUMBER_MISMATCH:
415 return "Field number";
416 case LinkMismatchError::FIELD_NAME_MISMATCH:
417 return "Field name";
418
419 case LinkMismatchError::INTERPOLATION_TYPE_MISMATCH:
420 return "Interpolation type";
421 case LinkMismatchError::INVARIANCE_MISMATCH:
422 return "Invariance";
423
424 case LinkMismatchError::BINDING_MISMATCH:
425 return "Binding layout qualifier";
426 case LinkMismatchError::LOCATION_MISMATCH:
427 return "Location layout qualifier";
428 case LinkMismatchError::OFFSET_MISMATCH:
429 return "Offset layout qualilfier";
430
431 case LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH:
432 return "Layout qualifier";
433 case LinkMismatchError::MATRIX_PACKING_MISMATCH:
434 return "Matrix Packing";
435 default:
436 UNREACHABLE();
437 return "";
438 }
439}
440
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800441LinkMismatchError LinkValidateInterfaceBlockFields(const sh::InterfaceBlockField &blockField1,
442 const sh::InterfaceBlockField &blockField2,
443 bool webglCompatibility,
444 std::string *mismatchedBlockFieldName)
445{
446 if (blockField1.name != blockField2.name)
447 {
448 return LinkMismatchError::FIELD_NAME_MISMATCH;
449 }
450
451 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
452 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
453 blockField1, blockField2, webglCompatibility, true, mismatchedBlockFieldName);
454 if (linkError != LinkMismatchError::NO_MISMATCH)
455 {
456 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
457 return linkError;
458 }
459
460 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
461 {
462 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
463 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
464 }
465
466 return LinkMismatchError::NO_MISMATCH;
467}
468
469LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
470 const sh::InterfaceBlock &interfaceBlock2,
471 bool webglCompatibility,
472 std::string *mismatchedBlockFieldName)
473{
474 // validate blocks for the same member types
475 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
476 {
477 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
478 }
479 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
480 {
481 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
482 }
483 if (interfaceBlock1.layout != interfaceBlock2.layout ||
484 interfaceBlock1.binding != interfaceBlock2.binding)
485 {
486 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
487 }
488 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
489 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
490 {
491 const sh::InterfaceBlockField &member1 = interfaceBlock1.fields[blockMemberIndex];
492 const sh::InterfaceBlockField &member2 = interfaceBlock2.fields[blockMemberIndex];
493
494 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
495 member1, member2, webglCompatibility, mismatchedBlockFieldName);
496 if (linkError != LinkMismatchError::NO_MISMATCH)
497 {
498 return linkError;
499 }
500 }
501 return LinkMismatchError::NO_MISMATCH;
502}
503
Jiawei Shao40786bd2018-04-18 13:58:57 +0800504using ShaderInterfaceBlock = std::pair<ShaderType, const sh::InterfaceBlock *>;
505using InterfaceBlockMap = std::map<std::string, ShaderInterfaceBlock>;
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800506
Jiawei Shao40786bd2018-04-18 13:58:57 +0800507void InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> &interfaceBlocks,
508 ShaderType shaderType,
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800509 InterfaceBlockMap *linkedInterfaceBlocks)
Jiawei Shao40786bd2018-04-18 13:58:57 +0800510{
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800511 ASSERT(linkedInterfaceBlocks);
Jiawei Shao40786bd2018-04-18 13:58:57 +0800512
513 for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800514 {
Jiawei Shao40786bd2018-04-18 13:58:57 +0800515 (*linkedInterfaceBlocks)[interfaceBlock.name] = std::make_pair(shaderType, &interfaceBlock);
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800516 }
Jiawei Shao40786bd2018-04-18 13:58:57 +0800517}
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800518
Jiawei Shao40786bd2018-04-18 13:58:57 +0800519bool ValidateGraphicsInterfaceBlocksPerShader(
520 const std::vector<sh::InterfaceBlock> &interfaceBlocksToLink,
521 ShaderType shaderType,
522 bool webglCompatibility,
523 InterfaceBlockMap *linkedBlocks,
Jiawei Shao40786bd2018-04-18 13:58:57 +0800524 InfoLog &infoLog)
525{
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800526 ASSERT(linkedBlocks);
Jiawei Shao40786bd2018-04-18 13:58:57 +0800527
528 for (const sh::InterfaceBlock &block : interfaceBlocksToLink)
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800529 {
Jiawei Shao40786bd2018-04-18 13:58:57 +0800530 const auto &entry = linkedBlocks->find(block.name);
531 if (entry != linkedBlocks->end())
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800532 {
Jiawei Shao40786bd2018-04-18 13:58:57 +0800533 const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
534 std::string mismatchedStructFieldName;
535 LinkMismatchError linkError = AreMatchingInterfaceBlocks(
536 block, linkedBlock, webglCompatibility, &mismatchedStructFieldName);
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800537 if (linkError != LinkMismatchError::NO_MISMATCH)
538 {
Jiawei Shao40786bd2018-04-18 13:58:57 +0800539 LogLinkMismatch(infoLog, block.name, GetInterfaceBlockTypeString(block.blockType),
540 linkError, mismatchedStructFieldName, entry->second.first,
541 shaderType);
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800542 return false;
543 }
544 }
Jiawei Shao40786bd2018-04-18 13:58:57 +0800545 else
546 {
547 (*linkedBlocks)[block.name] = std::make_pair(shaderType, &block);
548 }
Jiawei Shao40786bd2018-04-18 13:58:57 +0800549 }
550
551 return true;
552}
553
Jiawei Shao54aafe52018-04-27 14:54:57 +0800554bool ValidateInterfaceBlocksMatch(
555 GLuint numShadersHasInterfaceBlocks,
Jiawei Shao40786bd2018-04-18 13:58:57 +0800556 const ShaderMap<const std::vector<sh::InterfaceBlock> *> &shaderInterfaceBlocks,
557 InfoLog &infoLog,
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800558 bool webglCompatibility)
Jiawei Shao40786bd2018-04-18 13:58:57 +0800559{
Jiawei Shao54aafe52018-04-27 14:54:57 +0800560 if (numShadersHasInterfaceBlocks < 2u)
561 {
562 return true;
563 }
564
565 ASSERT(!shaderInterfaceBlocks[ShaderType::Compute]);
566
Jiawei Shao40786bd2018-04-18 13:58:57 +0800567 // Check that interface blocks defined in the graphics shaders are identical
568
569 InterfaceBlockMap linkedInterfaceBlocks;
Jiawei Shao40786bd2018-04-18 13:58:57 +0800570
571 bool interfaceBlockMapInitialized = false;
572 for (ShaderType shaderType : kAllGraphicsShaderTypes)
573 {
574 if (!shaderInterfaceBlocks[shaderType])
575 {
576 continue;
577 }
578
579 if (!interfaceBlockMapInitialized)
580 {
581 InitializeInterfaceBlockMap(*shaderInterfaceBlocks[shaderType], shaderType,
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800582 &linkedInterfaceBlocks);
Jiawei Shao40786bd2018-04-18 13:58:57 +0800583 interfaceBlockMapInitialized = true;
584 }
Jiawei Shaobb3255b2018-04-27 09:45:18 +0800585 else if (!ValidateGraphicsInterfaceBlocksPerShader(*shaderInterfaceBlocks[shaderType],
586 shaderType, webglCompatibility,
587 &linkedInterfaceBlocks, infoLog))
Jiawei Shao40786bd2018-04-18 13:58:57 +0800588 {
589 return false;
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800590 }
591 }
592
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800593 return true;
594}
595
Jamie Madill62d31cb2015-09-11 13:25:51 -0400596} // anonymous namespace
597
jchen107ae70d82018-07-06 13:47:01 +0800598// Saves the linking context for later use in resolveLink().
599struct Program::LinkingState
600{
601 const Context *context;
602 std::unique_ptr<ProgramLinkedResources> resources;
Shahbaz Youssefi9137ade2018-08-27 14:22:37 -0400603 egl::BlobCache::Key programHash;
jchen107ae70d82018-07-06 13:47:01 +0800604 std::unique_ptr<rx::LinkEvent> linkEvent;
605};
606
Jamie Madill4a3c2342015-10-08 12:58:45 -0400607const char *const g_fakepath = "C:\\fakepath";
608
Jamie Madill3c1da042017-11-27 18:33:40 -0500609// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400610InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000611{
612}
613
614InfoLog::~InfoLog()
615{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000616}
617
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400618size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000619{
Jamie Madill23176ce2017-07-31 14:14:33 -0400620 if (!mLazyStream)
621 {
622 return 0;
623 }
624
625 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400626 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000627}
628
Geoff Lange1a27752015-10-05 13:16:04 -0400629void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000630{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400631 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000632
633 if (bufSize > 0)
634 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400635 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400636
Jamie Madill23176ce2017-07-31 14:14:33 -0400637 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000638 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400639 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
640 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000641 }
642
643 infoLog[index] = '\0';
644 }
645
646 if (length)
647 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400648 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000649 }
650}
651
652// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300653// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000654// messages, so lets remove all occurrences of this fake file path from the log.
655void InfoLog::appendSanitized(const char *message)
656{
Jamie Madill23176ce2017-07-31 14:14:33 -0400657 ensureInitialized();
658
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000659 std::string msg(message);
660
661 size_t found;
662 do
663 {
664 found = msg.find(g_fakepath);
665 if (found != std::string::npos)
666 {
667 msg.erase(found, strlen(g_fakepath));
668 }
Jamie Madill493f9572018-05-24 19:52:15 -0400669 } while (found != std::string::npos);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000670
Jamie Madill23176ce2017-07-31 14:14:33 -0400671 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000672}
673
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000674void InfoLog::reset()
675{
Jiawei Shao02f15232017-12-27 10:10:28 +0800676 if (mLazyStream)
677 {
678 mLazyStream.reset(nullptr);
679 }
680}
681
682bool InfoLog::empty() const
683{
684 if (!mLazyStream)
685 {
686 return true;
687 }
688
689 return mLazyStream->rdbuf()->in_avail() == 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000690}
691
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800692void LogLinkMismatch(InfoLog &infoLog,
693 const std::string &variableName,
694 const char *variableType,
695 LinkMismatchError linkError,
696 const std::string &mismatchedStructOrBlockFieldName,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800697 ShaderType shaderType1,
698 ShaderType shaderType2)
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800699{
700 std::ostringstream stream;
701 stream << GetLinkMismatchErrorString(linkError) << "s of " << variableType << " '"
702 << variableName;
703
704 if (!mismatchedStructOrBlockFieldName.empty())
705 {
706 stream << "' member '" << variableName << "." << mismatchedStructOrBlockFieldName;
707 }
708
709 stream << "' differ between " << GetShaderTypeString(shaderType1) << " and "
710 << GetShaderTypeString(shaderType2) << " shaders.";
711
712 infoLog << stream.str();
713}
714
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800715bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock)
716{
717 // Only 'packed' blocks are allowed to be considered inactive.
Olli Etuaho107c7242018-03-20 15:45:35 +0200718 return interfaceBlock.active || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED;
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800719}
720
Jamie Madill3c1da042017-11-27 18:33:40 -0500721// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300722VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000723{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500724}
725
Olli Etuahoc8538042017-09-27 11:20:15 +0300726VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300727 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500728{
Olli Etuahoc8538042017-09-27 11:20:15 +0300729 ASSERT(arrayIndex != GL_INVALID_INDEX);
730}
731
Jamie Madill3c1da042017-11-27 18:33:40 -0500732// SamplerBindings implementation.
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800733SamplerBinding::SamplerBinding(TextureType textureTypeIn, size_t elementCount, bool unreferenced)
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500734 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
735{
736}
737
738SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
739
740SamplerBinding::~SamplerBinding() = default;
741
Jamie Madill3c1da042017-11-27 18:33:40 -0500742// ProgramBindings implementation.
743ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500744{
745}
746
Jamie Madill3c1da042017-11-27 18:33:40 -0500747ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500748{
749}
750
Jamie Madill3c1da042017-11-27 18:33:40 -0500751void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400752{
753 mBindings[name] = index;
754}
755
Jamie Madill3c1da042017-11-27 18:33:40 -0500756int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400757{
758 auto iter = mBindings.find(name);
759 return (iter != mBindings.end()) ? iter->second : -1;
760}
761
Jamie Madill3c1da042017-11-27 18:33:40 -0500762ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400763{
764 return mBindings.begin();
765}
766
Jamie Madill3c1da042017-11-27 18:33:40 -0500767ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400768{
769 return mBindings.end();
770}
771
Jamie Madill3c1da042017-11-27 18:33:40 -0500772// ImageBinding implementation.
Qin Jiajia47f6dd02018-08-10 13:36:32 +0800773ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0), unreferenced(false)
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500774{
775}
Qin Jiajia47f6dd02018-08-10 13:36:32 +0800776ImageBinding::ImageBinding(GLuint imageUnit, size_t count, bool unreferenced)
777 : unreferenced(unreferenced)
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500778{
779 for (size_t index = 0; index < count; ++index)
780 {
781 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
782 }
783}
784
785ImageBinding::ImageBinding(const ImageBinding &other) = default;
786
787ImageBinding::~ImageBinding() = default;
788
Jamie Madill3c1da042017-11-27 18:33:40 -0500789// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400790ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500791 : mLabel(),
Jiawei Shao016105b2018-04-12 16:38:31 +0800792 mAttachedShaders({}),
Geoff Langc5629752015-12-07 16:29:04 -0500793 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400794 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500795 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800796 mImageUniformRange(0, 0),
797 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300798 mBinaryRetrieveableHint(false),
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800799 mNumViews(-1),
800 // [GL_EXT_geometry_shader] Table 20.22
Jamie Madill493f9572018-05-24 19:52:15 -0400801 mGeometryShaderInputPrimitiveType(PrimitiveMode::Triangles),
802 mGeometryShaderOutputPrimitiveType(PrimitiveMode::TriangleStrip),
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800803 mGeometryShaderInvocations(1),
Jamie Madill7e4eff12018-08-08 15:49:26 -0400804 mGeometryShaderMaxVertices(0),
Austin Eng1bf18ce2018-10-19 15:34:02 -0700805 mDrawIDLocation(-1),
Jamie Madill7e4eff12018-08-08 15:49:26 -0400806 mActiveSamplerRefCounts{}
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400807{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300808 mComputeShaderLocalSize.fill(1);
Jamie Madill7e4eff12018-08-08 15:49:26 -0400809 mActiveSamplerTypes.fill(TextureType::InvalidEnum);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400810}
811
Jamie Madill48ef11b2016-04-27 15:21:52 -0400812ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400813{
Jiawei Shao016105b2018-04-12 16:38:31 +0800814 ASSERT(!hasAttachedShader());
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400815}
816
Jamie Madill48ef11b2016-04-27 15:21:52 -0400817const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500818{
819 return mLabel;
820}
821
Jiawei Shao385b3e02018-03-21 09:43:28 +0800822Shader *ProgramState::getAttachedShader(ShaderType shaderType) const
823{
Jiawei Shao016105b2018-04-12 16:38:31 +0800824 ASSERT(shaderType != ShaderType::InvalidEnum);
825 return mAttachedShaders[shaderType];
Jiawei Shao385b3e02018-03-21 09:43:28 +0800826}
827
Jamie Madille7d84322017-01-10 18:21:59 -0500828GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400829{
jchen1015015f72017-03-16 13:54:21 +0800830 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400831}
832
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800833GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
834{
835 return GetResourceIndexFromName(mBufferVariables, name);
836}
837
Jamie Madille7d84322017-01-10 18:21:59 -0500838GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
839{
840 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
841 return mUniformLocations[location].index;
842}
843
844Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
845{
846 GLuint index = getUniformIndexFromLocation(location);
847 if (!isSamplerUniformIndex(index))
848 {
849 return Optional<GLuint>::Invalid();
850 }
851
852 return getSamplerIndexFromUniformIndex(index);
853}
854
855bool ProgramState::isSamplerUniformIndex(GLuint index) const
856{
Jamie Madill982f6e02017-06-07 14:33:04 -0400857 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500858}
859
860GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
861{
862 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400863 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500864}
865
Qin Jiajia47f6dd02018-08-10 13:36:32 +0800866bool ProgramState::isImageUniformIndex(GLuint index) const
867{
868 return mImageUniformRange.contains(index);
869}
870
871GLuint ProgramState::getImageIndexFromUniformIndex(GLuint uniformIndex) const
872{
873 ASSERT(isImageUniformIndex(uniformIndex));
874 return uniformIndex - mImageUniformRange.low();
875}
876
Jamie Madill34ca4f52017-06-13 11:49:39 -0400877GLuint ProgramState::getAttributeLocation(const std::string &name) const
878{
879 for (const sh::Attribute &attribute : mAttributes)
880 {
881 if (attribute.name == name)
882 {
883 return attribute.location;
884 }
885 }
886
887 return static_cast<GLuint>(-1);
888}
889
Jiawei Shao016105b2018-04-12 16:38:31 +0800890bool ProgramState::hasAttachedShader() const
891{
892 for (const Shader *shader : mAttachedShaders)
893 {
894 if (shader)
895 {
896 return true;
897 }
898 }
899 return false;
900}
901
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500902Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400903 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400904 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500905 mLinked(false),
jchen105055fba2018-08-17 09:57:07 +0800906 mLinkResolved(true),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500907 mDeleteStatus(false),
908 mRefCount(0),
909 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500910 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500911{
912 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000913
Geoff Lang7dd2e102014-11-10 15:19:26 -0500914 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915}
916
917Program::~Program()
918{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400919 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920}
921
Jamie Madill4928b7c2017-06-20 12:57:39 -0400922void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500923{
Jamie Madill78bcd2b2018-10-16 15:05:20 -0400924 resolveLink(context);
Jiawei Shao016105b2018-04-12 16:38:31 +0800925 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill6c1f6712017-02-14 19:08:04 -0500926 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800927 if (mState.mAttachedShaders[shaderType])
928 {
929 mState.mAttachedShaders[shaderType]->release(context);
930 mState.mAttachedShaders[shaderType] = nullptr;
931 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800932 }
933
Jamie Madillf4a789f2018-10-18 16:56:20 -0400934 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400935
Jiawei Shao016105b2018-04-12 16:38:31 +0800936 ASSERT(!mState.hasAttachedShader());
Jamie Madill4928b7c2017-06-20 12:57:39 -0400937 SafeDelete(mProgram);
938
939 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500940}
jchen107ae70d82018-07-06 13:47:01 +0800941GLuint Program::id() const
942{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400943 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +0800944 return mHandle;
945}
Jamie Madill6c1f6712017-02-14 19:08:04 -0500946
Geoff Lang70d0f492015-12-10 17:45:46 -0500947void Program::setLabel(const std::string &label)
948{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400949 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400950 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500951}
952
953const std::string &Program::getLabel() const
954{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400955 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -0400956 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500957}
958
Jamie Madillef300b12016-10-07 15:12:09 -0400959void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400961 ASSERT(mLinkResolved);
Jiawei Shao016105b2018-04-12 16:38:31 +0800962 ShaderType shaderType = shader->getType();
963 ASSERT(shaderType != ShaderType::InvalidEnum);
964
965 mState.mAttachedShaders[shaderType] = shader;
966 mState.mAttachedShaders[shaderType]->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000967}
968
Jamie Madillc1d770e2017-04-13 17:31:24 -0400969void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400971 ASSERT(mLinkResolved);
Jiawei Shao016105b2018-04-12 16:38:31 +0800972 ShaderType shaderType = shader->getType();
973 ASSERT(shaderType != ShaderType::InvalidEnum);
974
975 ASSERT(mState.mAttachedShaders[shaderType] == shader);
976 shader->release(context);
977 mState.mAttachedShaders[shaderType] = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978}
979
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000980int Program::getAttachedShadersCount() const
981{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400982 ASSERT(mLinkResolved);
Jiawei Shao016105b2018-04-12 16:38:31 +0800983 int numAttachedShaders = 0;
984 for (const Shader *shader : mState.mAttachedShaders)
985 {
986 if (shader)
987 {
988 ++numAttachedShaders;
989 }
990 }
991
992 return numAttachedShaders;
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000993}
994
Jiawei Shao385b3e02018-03-21 09:43:28 +0800995const Shader *Program::getAttachedShader(ShaderType shaderType) const
996{
Jamie Madill44a6fbf2018-10-02 13:38:56 -0400997 ASSERT(mLinkResolved);
Jiawei Shao385b3e02018-03-21 09:43:28 +0800998 return mState.getAttachedShader(shaderType);
999}
1000
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001001void Program::bindAttributeLocation(GLuint index, const char *name)
1002{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001003 ASSERT(mLinkResolved);
Geoff Langd8605522016-04-13 10:19:12 -04001004 mAttributeBindings.bindLocation(index, name);
1005}
1006
1007void Program::bindUniformLocation(GLuint index, const char *name)
1008{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001009 ASSERT(mLinkResolved);
Olli Etuahod2551232017-10-26 20:03:33 +03001010 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011}
1012
Sami Väisänen46eaa942016-06-29 10:26:37 +03001013void Program::bindFragmentInputLocation(GLint index, const char *name)
1014{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001015 ASSERT(mLinkResolved);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001016 mFragmentInputBindings.bindLocation(index, name);
1017}
1018
Olli Etuaho0ca09752018-09-24 11:00:50 +03001019void Program::bindFragmentOutputLocation(GLuint index, const char *name)
1020{
1021 mFragmentOutputLocations.bindLocation(index, name);
1022}
1023
1024void Program::bindFragmentOutputIndex(GLuint index, const char *name)
1025{
1026 mFragmentOutputIndexes.bindLocation(index, name);
1027}
1028
jchen103fd614d2018-08-13 12:21:58 +08001029BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +03001030{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001031 ASSERT(mLinkResolved);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001032 BindingInfo ret;
1033 ret.type = GL_NONE;
1034 ret.valid = false;
1035
Jiawei Shao385b3e02018-03-21 09:43:28 +08001036 Shader *fragmentShader = mState.getAttachedShader(ShaderType::Fragment);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001037 ASSERT(fragmentShader);
1038
1039 // Find the actual fragment shader varying we're interested in
jchen103fd614d2018-08-13 12:21:58 +08001040 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings();
Sami Väisänen46eaa942016-06-29 10:26:37 +03001041
1042 for (const auto &binding : mFragmentInputBindings)
1043 {
1044 if (binding.second != static_cast<GLuint>(index))
1045 continue;
1046
1047 ret.valid = true;
1048
Olli Etuahod2551232017-10-26 20:03:33 +03001049 size_t nameLengthWithoutArrayIndex;
1050 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001051
1052 for (const auto &in : inputs)
1053 {
Olli Etuahod2551232017-10-26 20:03:33 +03001054 if (in.name.length() == nameLengthWithoutArrayIndex &&
1055 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +03001056 {
1057 if (in.isArray())
1058 {
1059 // The client wants to bind either "name" or "name[0]".
1060 // GL ES 3.1 spec refers to active array names with language such as:
1061 // "if the string identifies the base name of an active array, where the
1062 // string would exactly match the name of the variable if the suffix "[0]"
1063 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -04001064 if (arrayIndex == GL_INVALID_INDEX)
1065 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +03001066
Corentin Wallez054f7ed2016-09-20 17:15:59 -04001067 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +03001068 }
1069 else
1070 {
1071 ret.name = in.mappedName;
1072 }
1073 ret.type = in.type;
1074 return ret;
1075 }
1076 }
1077 }
1078
1079 return ret;
1080}
1081
jchen103fd614d2018-08-13 12:21:58 +08001082void Program::pathFragmentInputGen(GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +03001083 GLenum genMode,
1084 GLint components,
1085 const GLfloat *coeffs)
1086{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001087 ASSERT(mLinkResolved);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001088 // If the location is -1 then the command is silently ignored
1089 if (index == -1)
1090 return;
1091
jchen103fd614d2018-08-13 12:21:58 +08001092 const auto &binding = getFragmentInputBindingInfo(index);
Sami Väisänen46eaa942016-06-29 10:26:37 +03001093
1094 // If the input doesn't exist then then the command is silently ignored
1095 // This could happen through optimization for example, the shader translator
1096 // decides that a variable is not actually being used and optimizes it away.
1097 if (binding.name.empty())
1098 return;
1099
1100 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
1101}
1102
Martin Radev4c4c8e72016-08-04 12:25:34 +03001103// The attached shaders are checked for linking errors by matching up their variables.
1104// Uniform, input and output variables get collected.
1105// The code gets compiled into binaries.
Jamie Madillf4a789f2018-10-18 16:56:20 -04001106angle::Result Program::link(const Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001107{
Jamie Madill8ecf7f92017-01-13 17:29:52 -05001108 const auto &data = context->getContextState();
1109
Jamie Madill6c58b062017-08-01 13:44:25 -04001110 auto *platform = ANGLEPlatformCurrent();
1111 double startTime = platform->currentTime(platform);
1112
Jamie Madill6c1f6712017-02-14 19:08:04 -05001113 unlink();
Jamie Madill6bc264a2018-03-31 15:36:05 -04001114 mInfoLog.reset();
1115
1116 // Validate we have properly attached shaders before checking the cache.
jchen103fd614d2018-08-13 12:21:58 +08001117 if (!linkValidateShaders(mInfoLog))
Jamie Madill6bc264a2018-03-31 15:36:05 -04001118 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001119 return angle::Result::Continue();
Jamie Madill6bc264a2018-03-31 15:36:05 -04001120 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001121
Shahbaz Youssefi9137ade2018-08-27 14:22:37 -04001122 egl::BlobCache::Key programHash = {0};
Jamie Madill6bc264a2018-03-31 15:36:05 -04001123 MemoryProgramCache *cache = context->getMemoryProgramCache();
jchen107ae70d82018-07-06 13:47:01 +08001124
Jamie Madill32447362017-06-28 14:53:52 -04001125 if (cache)
1126 {
Jamie Madill785e8a02018-10-04 17:42:00 -04001127 angle::Result result = cache->getProgram(context, this, &mState, &programHash);
1128 mLinked = (result == angle::Result::Continue());
1129 ANGLE_TRY(result);
Jamie Madill32447362017-06-28 14:53:52 -04001130 }
1131
1132 if (mLinked)
1133 {
Jamie Madill6c58b062017-08-01 13:44:25 -04001134 double delta = platform->currentTime(platform) - startTime;
1135 int us = static_cast<int>(delta * 1000000.0);
1136 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madillf4a789f2018-10-18 16:56:20 -04001137 return angle::Result::Continue();
Jamie Madill32447362017-06-28 14:53:52 -04001138 }
1139
1140 // Cache load failed, fall through to normal linking.
1141 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001142
Jamie Madill6bc264a2018-03-31 15:36:05 -04001143 // Re-link shaders after the unlink call.
jchen103fd614d2018-08-13 12:21:58 +08001144 ASSERT(linkValidateShaders(mInfoLog));
Yuly Novikovcfa48d32016-06-15 22:14:36 -04001145
jchen107ae70d82018-07-06 13:47:01 +08001146 std::unique_ptr<ProgramLinkedResources> resources;
Jiawei Shao016105b2018-04-12 16:38:31 +08001147 if (mState.mAttachedShaders[ShaderType::Compute])
Jamie Madill437d2662014-12-05 14:23:35 -05001148 {
jchen107ae70d82018-07-06 13:47:01 +08001149 resources.reset(
1150 new ProgramLinkedResources{{0, PackMode::ANGLE_RELAXED},
1151 {&mState.mUniformBlocks, &mState.mUniforms},
1152 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1153 {&mState.mAtomicCounterBuffers},
1154 {}});
Luc Ferrone17b5ba2018-06-04 14:28:58 -04001155
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001156 GLuint combinedImageUniforms = 0u;
jchen103fd614d2018-08-13 12:21:58 +08001157 if (!linkUniforms(context->getCaps(), mInfoLog, mUniformLocationBindings,
1158 &combinedImageUniforms, &resources->unusedUniforms))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001159 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001160 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001161 }
1162
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001163 GLuint combinedShaderStorageBlocks = 0u;
jchen103fd614d2018-08-13 12:21:58 +08001164 if (!linkInterfaceBlocks(context->getCaps(), context->getClientVersion(),
1165 context->getExtensions().webglCompatibility, mInfoLog,
1166 &combinedShaderStorageBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001167 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001168 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001169 }
1170
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001171 // [OpenGL ES 3.1] Chapter 8.22 Page 203:
1172 // A link error will be generated if the sum of the number of active image uniforms used in
1173 // all shaders, the number of active shader storage blocks, and the number of active
1174 // fragment shader outputs exceeds the implementation-dependent value of
1175 // MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
1176 if (combinedImageUniforms + combinedShaderStorageBlocks >
1177 context->getCaps().maxCombinedShaderOutputResources)
1178 {
1179 mInfoLog
1180 << "The sum of the number of active image uniforms, active shader storage blocks "
1181 "and active fragment shader outputs exceeds "
1182 "MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
1183 << context->getCaps().maxCombinedShaderOutputResources << ")";
Jamie Madillf4a789f2018-10-18 16:56:20 -04001184 return angle::Result::Continue();
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001185 }
1186
jchen103fd614d2018-08-13 12:21:58 +08001187 InitUniformBlockLinker(mState, &resources->uniformBlockLinker);
1188 InitShaderStorageBlockLinker(mState, &resources->shaderStorageBlockLinker);
Martin Radev4c4c8e72016-08-04 12:25:34 +03001189 }
1190 else
1191 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -04001192 // Map the varyings to the register file
1193 // In WebGL, we use a slightly different handling for packing variables.
1194 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
1195 if (data.getLimitations().noFlexibleVaryingPacking)
1196 {
1197 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
1198 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
1199 }
1200 else if (data.getExtensions().webglCompatibility)
1201 {
1202 packMode = PackMode::WEBGL_STRICT;
1203 }
1204
jchen107ae70d82018-07-06 13:47:01 +08001205 resources.reset(
1206 new ProgramLinkedResources{{data.getCaps().maxVaryingVectors, packMode},
1207 {&mState.mUniformBlocks, &mState.mUniforms},
1208 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1209 {&mState.mAtomicCounterBuffers},
1210 {}});
Luc Ferrone17b5ba2018-06-04 14:28:58 -04001211
jchen103fd614d2018-08-13 12:21:58 +08001212 if (!linkAttributes(context->getCaps(), mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001213 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001214 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001215 }
1216
jchen103fd614d2018-08-13 12:21:58 +08001217 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001218 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001219 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001220 }
1221
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001222 GLuint combinedImageUniforms = 0u;
jchen103fd614d2018-08-13 12:21:58 +08001223 if (!linkUniforms(context->getCaps(), mInfoLog, mUniformLocationBindings,
1224 &combinedImageUniforms, &resources->unusedUniforms))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001225 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001226 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001227 }
1228
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001229 GLuint combinedShaderStorageBlocks = 0u;
jchen103fd614d2018-08-13 12:21:58 +08001230 if (!linkInterfaceBlocks(context->getCaps(), context->getClientVersion(),
1231 context->getExtensions().webglCompatibility, mInfoLog,
1232 &combinedShaderStorageBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001233 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001234 return angle::Result::Continue();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001235 }
1236
jchen103fd614d2018-08-13 12:21:58 +08001237 if (!linkValidateGlobalNames(mInfoLog))
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04001238 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001239 return angle::Result::Continue();
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04001240 }
1241
Olli Etuaho0ca09752018-09-24 11:00:50 +03001242 if (!linkOutputVariables(context->getCaps(), context->getExtensions(),
1243 context->getClientVersion(), combinedImageUniforms,
1244 combinedShaderStorageBlocks))
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001245 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001246 return angle::Result::Continue();
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001247 }
1248
jchen103fd614d2018-08-13 12:21:58 +08001249 const auto &mergedVaryings = getMergedVaryings();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001250
Jiawei Shao016105b2018-04-12 16:38:31 +08001251 ASSERT(mState.mAttachedShaders[ShaderType::Vertex]);
jchen103fd614d2018-08-13 12:21:58 +08001252 mState.mNumViews = mState.mAttachedShaders[ShaderType::Vertex]->getNumViews();
Martin Radev7cf61662017-07-26 17:10:53 +03001253
jchen103fd614d2018-08-13 12:21:58 +08001254 InitUniformBlockLinker(mState, &resources->uniformBlockLinker);
1255 InitShaderStorageBlockLinker(mState, &resources->shaderStorageBlockLinker);
Jamie Madillc9727f32017-11-07 12:37:07 -05001256
jchen103fd614d2018-08-13 12:21:58 +08001257 if (!linkValidateTransformFeedback(context->getClientVersion(), mInfoLog, mergedVaryings,
1258 context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -05001259 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001260 return angle::Result::Continue();
Jamie Madill192745a2016-12-22 15:58:21 -05001261 }
1262
jchen107ae70d82018-07-06 13:47:01 +08001263 if (!resources->varyingPacking.collectAndPackUserVaryings(
jchen1085c93c42017-11-12 15:36:47 +08001264 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +03001265 {
Jamie Madillf4a789f2018-10-18 16:56:20 -04001266 return angle::Result::Continue();
Olli Etuaho39e78122017-08-29 14:34:22 +03001267 }
1268
Martin Radev4c4c8e72016-08-04 12:25:34 +03001269 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -05001270 }
1271
jchen107ae70d82018-07-06 13:47:01 +08001272 mLinkingState.reset(new LinkingState());
1273 mLinkingState->context = context;
1274 mLinkingState->programHash = programHash;
1275 mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
1276 mLinkingState->resources = std::move(resources);
jchen105055fba2018-08-17 09:57:07 +08001277 mLinkResolved = false;
jchen107ae70d82018-07-06 13:47:01 +08001278
Jamie Madillf4a789f2018-10-18 16:56:20 -04001279 return angle::Result::Continue();
jchen107ae70d82018-07-06 13:47:01 +08001280}
1281
1282bool Program::isLinking() const
1283{
1284 return (mLinkingState.get() && mLinkingState->linkEvent->isLinking());
1285}
1286
Jamie Madill785e8a02018-10-04 17:42:00 -04001287void Program::resolveLinkImpl(const Context *context)
jchen107ae70d82018-07-06 13:47:01 +08001288{
1289 ASSERT(mLinkingState.get());
1290
Jamie Madill785e8a02018-10-04 17:42:00 -04001291 angle::Result result = mLinkingState->linkEvent->wait(context);
1292
1293 mLinked = result == angle::Result::Continue();
jchen105055fba2018-08-17 09:57:07 +08001294 mLinkResolved = true;
jchen107ae70d82018-07-06 13:47:01 +08001295 auto linkingState = std::move(mLinkingState);
1296 if (!mLinked)
1297 {
1298 return;
1299 }
1300
Jamie Madill6db1c2e2017-11-08 09:17:40 -05001301 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -04001302
Yunchao Heece12532017-11-21 15:50:21 +08001303 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
1304 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +08001305 ASSERT(mLinked);
1306 updateLinkedShaderStages();
1307
Jamie Madill54164b02017-08-28 15:17:37 -04001308 // Mark implementation-specific unreferenced uniforms as ignored.
Qin Jiajia47f6dd02018-08-10 13:36:32 +08001309 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings,
1310 &mState.mImageBindings);
Jamie Madill54164b02017-08-28 15:17:37 -04001311
Jamie Madill7e4eff12018-08-08 15:49:26 -04001312 // Must be called after markUnusedUniformLocations.
1313 mState.updateActiveSamplers();
Qin Jiajia47f6dd02018-08-10 13:36:32 +08001314 mState.updateActiveImages();
Jamie Madill7e4eff12018-08-08 15:49:26 -04001315
1316 setUniformValuesFromBindingQualifiers();
1317
Austin Eng1bf18ce2018-10-19 15:34:02 -07001318 if (context->getExtensions().multiDraw)
1319 {
1320 mState.mDrawIDLocation = getUniformLocation("gl_DrawID");
1321 }
1322
Jamie Madill32447362017-06-28 14:53:52 -04001323 // Save to the program cache.
jchen107ae70d82018-07-06 13:47:01 +08001324 auto *cache = linkingState->context->getMemoryProgramCache();
1325 if (cache &&
1326 (mState.mLinkedTransformFeedbackVaryings.empty() ||
1327 !linkingState->context->getWorkarounds().disableProgramCachingForTransformFeedback))
Jamie Madill32447362017-06-28 14:53:52 -04001328 {
jchen107ae70d82018-07-06 13:47:01 +08001329 cache->putProgram(linkingState->programHash, linkingState->context, this);
Jamie Madill32447362017-06-28 14:53:52 -04001330 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001331}
1332
Yunchao He85072e82017-11-14 15:43:28 +08001333void Program::updateLinkedShaderStages()
1334{
Yunchao Heece12532017-11-21 15:50:21 +08001335 mState.mLinkedShaderStages.reset();
1336
Jiawei Shao016105b2018-04-12 16:38:31 +08001337 for (const Shader *shader : mState.mAttachedShaders)
Yunchao He85072e82017-11-14 15:43:28 +08001338 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001339 if (shader)
1340 {
1341 mState.mLinkedShaderStages.set(shader->getType());
1342 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001343 }
Yunchao He85072e82017-11-14 15:43:28 +08001344}
1345
James Darpinian30b604d2018-03-12 17:26:57 -07001346void ProgramState::updateTransformFeedbackStrides()
1347{
1348 if (mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS)
1349 {
1350 mTransformFeedbackStrides.resize(1);
1351 size_t totalSize = 0;
1352 for (auto &varying : mLinkedTransformFeedbackVaryings)
1353 {
1354 totalSize += varying.size() * VariableExternalSize(varying.type);
1355 }
1356 mTransformFeedbackStrides[0] = static_cast<GLsizei>(totalSize);
1357 }
1358 else
1359 {
1360 mTransformFeedbackStrides.resize(mLinkedTransformFeedbackVaryings.size());
1361 for (size_t i = 0; i < mLinkedTransformFeedbackVaryings.size(); i++)
1362 {
1363 auto &varying = mLinkedTransformFeedbackVaryings[i];
1364 mTransformFeedbackStrides[i] =
1365 static_cast<GLsizei>(varying.size() * VariableExternalSize(varying.type));
1366 }
1367 }
1368}
1369
Jamie Madill7e4eff12018-08-08 15:49:26 -04001370void ProgramState::updateActiveSamplers()
1371{
1372 for (SamplerBinding &samplerBinding : mSamplerBindings)
1373 {
1374 if (samplerBinding.unreferenced)
1375 continue;
1376
1377 for (GLint textureUnit : samplerBinding.boundTextureUnits)
1378 {
1379 mActiveSamplerRefCounts[textureUnit]++;
1380 mActiveSamplerTypes[textureUnit] = getSamplerUniformTextureType(textureUnit);
1381 mActiveSamplersMask.set(textureUnit);
1382 }
1383 }
1384}
1385
Qin Jiajia47f6dd02018-08-10 13:36:32 +08001386void ProgramState::updateActiveImages()
1387{
1388 for (ImageBinding &imageBinding : mImageBindings)
1389 {
1390 if (imageBinding.unreferenced)
1391 continue;
1392
1393 for (GLint imageUnit : imageBinding.boundImageUnits)
1394 {
1395 mActiveImagesMask.set(imageUnit);
1396 }
1397 }
1398}
1399
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00001400// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -05001401void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001402{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001403 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -08001404 mState.mAttributesTypeMask.reset();
1405 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001406 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001407 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001408 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001409 mState.mUniforms.clear();
1410 mState.mUniformLocations.clear();
1411 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001412 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001413 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001414 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001415 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001416 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001417 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001418 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001419 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001420 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001421 mState.mImageBindings.clear();
Qin Jiajia47f6dd02018-08-10 13:36:32 +08001422 mState.mActiveImagesMask.reset();
Jamie Madill493f9572018-05-24 19:52:15 -04001423 mState.mNumViews = -1;
1424 mState.mGeometryShaderInputPrimitiveType = PrimitiveMode::Triangles;
1425 mState.mGeometryShaderOutputPrimitiveType = PrimitiveMode::TriangleStrip;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001426 mState.mGeometryShaderInvocations = 1;
1427 mState.mGeometryShaderMaxVertices = 0;
Austin Eng1bf18ce2018-10-19 15:34:02 -07001428 mState.mDrawIDLocation = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001429
Geoff Lang7dd2e102014-11-10 15:19:26 -05001430 mValidated = false;
1431
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001432 mLinked = false;
Jamie Madill6bc264a2018-03-31 15:36:05 -04001433 mInfoLog.reset();
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001434}
1435
Jamie Madillf4a789f2018-10-18 16:56:20 -04001436angle::Result Program::loadBinary(const Context *context,
1437 GLenum binaryFormat,
1438 const void *binary,
1439 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001440{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001441 ASSERT(mLinkResolved);
Jamie Madill6c1f6712017-02-14 19:08:04 -05001442 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001443
Geoff Lang7dd2e102014-11-10 15:19:26 -05001444#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
Jamie Madillf4a789f2018-10-18 16:56:20 -04001445 return angle::Result::Continue();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001447 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1448 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001449 {
Jamie Madillf6113162015-05-07 11:49:21 -04001450 mInfoLog << "Invalid program binary format.";
Jamie Madillf4a789f2018-10-18 16:56:20 -04001451 return angle::Result::Continue();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001452 }
1453
Jamie Madill4f86d052017-06-05 12:59:26 -04001454 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
Jamie Madill785e8a02018-10-04 17:42:00 -04001455 angle::Result result =
1456 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog);
1457 mLinked = result == angle::Result::Continue();
1458 ANGLE_TRY(result);
Jamie Madill32447362017-06-28 14:53:52 -04001459
1460 // Currently we require the full shader text to compute the program hash.
Jamie Madill785e8a02018-10-04 17:42:00 -04001461 // We could also store the binary in the internal program cache.
Jamie Madill32447362017-06-28 14:53:52 -04001462
Jamie Madill70aeda42018-08-20 12:17:40 -04001463 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mState.mUniformBlocks.size();
1464 ++uniformBlockIndex)
1465 {
1466 mDirtyBits.set(uniformBlockIndex);
1467 }
1468
Jamie Madillf4a789f2018-10-18 16:56:20 -04001469 return angle::Result::Continue();
Jamie Madilla2c74982016-12-12 11:20:42 -05001470#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471}
1472
Jamie Madillf4a789f2018-10-18 16:56:20 -04001473angle::Result Program::saveBinary(Context *context,
1474 GLenum *binaryFormat,
1475 void *binary,
1476 GLsizei bufSize,
1477 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001479 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001480 if (binaryFormat)
1481 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001482 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001483 }
1484
Jamie Madill4f86d052017-06-05 12:59:26 -04001485 angle::MemoryBuffer memoryBuf;
1486 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001487
Jamie Madill4f86d052017-06-05 12:59:26 -04001488 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1489 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001490
1491 if (streamLength > bufSize)
1492 {
1493 if (length)
1494 {
1495 *length = 0;
1496 }
1497
Jamie Madill493f9572018-05-24 19:52:15 -04001498 // TODO: This should be moved to the validation layer but computing the size of the binary
1499 // before saving it causes the save to happen twice. It may be possible to write the binary
1500 // to a separate buffer, validate sizes and then copy it.
Jamie Madillf4a789f2018-10-18 16:56:20 -04001501 ANGLE_CHECK(context, false, "Insufficient buffer size", GL_INVALID_OPERATION);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001502 }
1503
1504 if (binary)
1505 {
Jamie Madill493f9572018-05-24 19:52:15 -04001506 char *ptr = reinterpret_cast<char *>(binary);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001507
Jamie Madill48ef11b2016-04-27 15:21:52 -04001508 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509 ptr += streamLength;
1510
1511 ASSERT(ptr - streamLength == binary);
1512 }
1513
1514 if (length)
1515 {
1516 *length = streamLength;
1517 }
1518
Jamie Madillf4a789f2018-10-18 16:56:20 -04001519 return angle::Result::Continue();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001520}
1521
Jamie Madillf4a789f2018-10-18 16:56:20 -04001522GLint Program::getBinaryLength(Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001524 ASSERT(mLinkResolved);
Geoff Langb26ab822018-05-29 11:19:00 -04001525 if (!mLinked)
1526 {
1527 return 0;
1528 }
1529
Geoff Lang7dd2e102014-11-10 15:19:26 -05001530 GLint length;
Jamie Madillf4a789f2018-10-18 16:56:20 -04001531 angle::Result result =
1532 saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
1533 if (result != angle::Result::Continue())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001534 {
1535 return 0;
1536 }
1537
1538 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001539}
1540
Geoff Langc5629752015-12-07 16:29:04 -05001541void Program::setBinaryRetrievableHint(bool retrievable)
1542{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001543 ASSERT(mLinkResolved);
Geoff Langc5629752015-12-07 16:29:04 -05001544 // TODO(jmadill) : replace with dirty bits
1545 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001546 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001547}
1548
1549bool Program::getBinaryRetrievableHint() const
1550{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001551 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001552 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001553}
1554
Yunchao He61afff12017-03-14 15:34:03 +08001555void Program::setSeparable(bool separable)
1556{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001557 ASSERT(mLinkResolved);
Yunchao He61afff12017-03-14 15:34:03 +08001558 // TODO(yunchao) : replace with dirty bits
1559 if (mState.mSeparable != separable)
1560 {
1561 mProgram->setSeparable(separable);
1562 mState.mSeparable = separable;
1563 }
1564}
1565
1566bool Program::isSeparable() const
1567{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001568 ASSERT(mLinkResolved);
Yunchao He61afff12017-03-14 15:34:03 +08001569 return mState.mSeparable;
1570}
1571
Jamie Madill956ab4d2018-10-10 16:13:03 -04001572void Program::deleteSelf(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001573{
Jamie Madill956ab4d2018-10-10 16:13:03 -04001574 ASSERT(mRefCount == 0 && mDeleteStatus);
1575 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001576}
1577
1578unsigned int Program::getRefCount() const
1579{
1580 return mRefCount;
1581}
1582
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001583int Program::getInfoLogLength() const
1584{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001585 ASSERT(mLinkResolved);
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001586 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001587}
1588
Geoff Lange1a27752015-10-05 13:16:04 -04001589void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001590{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001591 ASSERT(mLinkResolved);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001592 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001593}
1594
Geoff Lange1a27752015-10-05 13:16:04 -04001595void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001596{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001597 ASSERT(mLinkResolved);
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001598 int total = 0;
1599
Jiawei Shao016105b2018-04-12 16:38:31 +08001600 for (const Shader *shader : mState.mAttachedShaders)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001601 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001602 if (shader && (total < maxCount))
Martin Radev4c4c8e72016-08-04 12:25:34 +03001603 {
Jiawei Shao016105b2018-04-12 16:38:31 +08001604 shaders[total] = shader->getHandle();
1605 ++total;
Jiawei Shao89be29a2017-11-06 14:36:45 +08001606 }
1607 }
1608
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001609 if (count)
1610 {
1611 *count = total;
1612 }
1613}
1614
Geoff Lange1a27752015-10-05 13:16:04 -04001615GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001616{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001617 ASSERT(mLinkResolved);
Jamie Madill34ca4f52017-06-13 11:49:39 -04001618 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001619}
1620
Jamie Madill63805b42015-08-25 13:17:39 -04001621bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001622{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001623 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001624 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1625 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626}
1627
jchen10fd7c3b52017-03-21 15:36:03 +08001628void Program::getActiveAttribute(GLuint index,
1629 GLsizei bufsize,
1630 GLsizei *length,
1631 GLint *size,
1632 GLenum *type,
1633 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001634{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001635 ASSERT(mLinkResolved);
Jamie Madillc349ec02015-08-21 16:53:12 -04001636 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001637 {
1638 if (bufsize > 0)
1639 {
1640 name[0] = '\0';
1641 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001642
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001643 if (length)
1644 {
1645 *length = 0;
1646 }
1647
1648 *type = GL_NONE;
1649 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001650 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001651 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001652
jchen1036e120e2017-03-14 14:53:58 +08001653 ASSERT(index < mState.mAttributes.size());
1654 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001655
1656 if (bufsize > 0)
1657 {
jchen10fd7c3b52017-03-21 15:36:03 +08001658 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001659 }
1660
1661 // Always a single 'type' instance
1662 *size = 1;
1663 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001664}
1665
Geoff Lange1a27752015-10-05 13:16:04 -04001666GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001667{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001668 ASSERT(mLinkResolved);
Jamie Madillc349ec02015-08-21 16:53:12 -04001669 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001670 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001671 return 0;
1672 }
1673
jchen1036e120e2017-03-14 14:53:58 +08001674 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001675}
1676
Geoff Lange1a27752015-10-05 13:16:04 -04001677GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001678{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001679 ASSERT(mLinkResolved);
Jamie Madillc349ec02015-08-21 16:53:12 -04001680 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001681 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001682 return 0;
1683 }
1684
1685 size_t maxLength = 0;
1686
Jamie Madill48ef11b2016-04-27 15:21:52 -04001687 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001688 {
jchen1036e120e2017-03-14 14:53:58 +08001689 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001690 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691
Jamie Madillc349ec02015-08-21 16:53:12 -04001692 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693}
1694
jchen107ae70d82018-07-06 13:47:01 +08001695const std::vector<sh::Attribute> &Program::getAttributes() const
1696{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001697 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001698 return mState.mAttributes;
1699}
1700
jchen107ae70d82018-07-06 13:47:01 +08001701const std::vector<SamplerBinding> &Program::getSamplerBindings() const
1702{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001703 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001704 return mState.mSamplerBindings;
1705}
1706
jchen107ae70d82018-07-06 13:47:01 +08001707const sh::WorkGroupSize &Program::getComputeShaderLocalSize() const
1708{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001709 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001710 return mState.mComputeShaderLocalSize;
1711}
1712
1713PrimitiveMode Program::getGeometryShaderInputPrimitiveType() const
1714{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001715 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001716 return mState.mGeometryShaderInputPrimitiveType;
1717}
1718PrimitiveMode Program::getGeometryShaderOutputPrimitiveType() const
1719{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001720 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001721 return mState.mGeometryShaderOutputPrimitiveType;
1722}
1723GLint Program::getGeometryShaderInvocations() const
1724{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001725 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001726 return mState.mGeometryShaderInvocations;
1727}
1728GLint Program::getGeometryShaderMaxVertices() const
1729{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001730 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001731 return mState.mGeometryShaderMaxVertices;
1732}
1733
jchen1015015f72017-03-16 13:54:21 +08001734GLuint Program::getInputResourceIndex(const GLchar *name) const
1735{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001736 ASSERT(mLinkResolved);
Olli Etuahod2551232017-10-26 20:03:33 +03001737 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001738}
1739
1740GLuint Program::getOutputResourceIndex(const GLchar *name) const
1741{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001742 ASSERT(mLinkResolved);
jchen1015015f72017-03-16 13:54:21 +08001743 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1744}
1745
jchen10fd7c3b52017-03-21 15:36:03 +08001746size_t Program::getOutputResourceCount() const
1747{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001748 ASSERT(mLinkResolved);
jchen10fd7c3b52017-03-21 15:36:03 +08001749 return (mLinked ? mState.mOutputVariables.size() : 0);
1750}
1751
jchen107ae70d82018-07-06 13:47:01 +08001752const std::vector<GLenum> &Program::getOutputVariableTypes() const
1753{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001754 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001755 return mState.mOutputVariableTypes;
1756}
1757DrawBufferMask Program::getActiveOutputVariables() const
1758{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001759 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001760 return mState.mActiveOutputVariables;
1761}
1762
jchen10baf5d942017-08-28 20:45:48 +08001763template <typename T>
1764void Program::getResourceName(GLuint index,
1765 const std::vector<T> &resources,
1766 GLsizei bufSize,
1767 GLsizei *length,
1768 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001769{
1770 if (length)
1771 {
1772 *length = 0;
1773 }
1774
1775 if (!mLinked)
1776 {
1777 if (bufSize > 0)
1778 {
1779 name[0] = '\0';
1780 }
1781 return;
1782 }
jchen10baf5d942017-08-28 20:45:48 +08001783 ASSERT(index < resources.size());
1784 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001785
1786 if (bufSize > 0)
1787 {
Olli Etuahod2551232017-10-26 20:03:33 +03001788 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001789 }
1790}
1791
jchen10baf5d942017-08-28 20:45:48 +08001792void Program::getInputResourceName(GLuint index,
1793 GLsizei bufSize,
1794 GLsizei *length,
1795 GLchar *name) const
1796{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001797 ASSERT(mLinkResolved);
jchen10baf5d942017-08-28 20:45:48 +08001798 getResourceName(index, mState.mAttributes, bufSize, length, name);
1799}
1800
1801void Program::getOutputResourceName(GLuint index,
1802 GLsizei bufSize,
1803 GLsizei *length,
1804 GLchar *name) const
1805{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001806 ASSERT(mLinkResolved);
jchen10baf5d942017-08-28 20:45:48 +08001807 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1808}
1809
1810void Program::getUniformResourceName(GLuint index,
1811 GLsizei bufSize,
1812 GLsizei *length,
1813 GLchar *name) const
1814{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001815 ASSERT(mLinkResolved);
jchen10baf5d942017-08-28 20:45:48 +08001816 getResourceName(index, mState.mUniforms, bufSize, length, name);
1817}
1818
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001819void Program::getBufferVariableResourceName(GLuint index,
1820 GLsizei bufSize,
1821 GLsizei *length,
1822 GLchar *name) const
1823{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001824 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001825 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1826}
1827
jchen10880683b2017-04-12 16:21:55 +08001828const sh::Attribute &Program::getInputResource(GLuint index) const
1829{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001830 ASSERT(mLinkResolved);
jchen10880683b2017-04-12 16:21:55 +08001831 ASSERT(index < mState.mAttributes.size());
1832 return mState.mAttributes[index];
1833}
1834
1835const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1836{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001837 ASSERT(mLinkResolved);
jchen10880683b2017-04-12 16:21:55 +08001838 ASSERT(index < mState.mOutputVariables.size());
1839 return mState.mOutputVariables[index];
1840}
1841
jchen107ae70d82018-07-06 13:47:01 +08001842const ProgramBindings &Program::getAttributeBindings() const
1843{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001844 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001845 return mAttributeBindings;
1846}
1847const ProgramBindings &Program::getUniformLocationBindings() const
1848{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001849 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001850 return mUniformLocationBindings;
1851}
1852const ProgramBindings &Program::getFragmentInputBindings() const
1853{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001854 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001855 return mFragmentInputBindings;
1856}
1857
1858int Program::getNumViews() const
1859{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001860 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001861 return mState.getNumViews();
1862}
jchen107ae70d82018-07-06 13:47:01 +08001863
1864ComponentTypeMask Program::getDrawBufferTypeMask() const
1865{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001866 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001867 return mState.mDrawBufferTypeMask;
1868}
1869ComponentTypeMask Program::getAttributesTypeMask() const
1870{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001871 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001872 return mState.mAttributesTypeMask;
1873}
1874AttributesMask Program::getAttributesMask() const
1875{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001876 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001877 return mState.mAttributesMask;
1878}
1879
1880const std::vector<GLsizei> &Program::getTransformFeedbackStrides() const
1881{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001882 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08001883 return mState.mTransformFeedbackStrides;
1884}
1885
Geoff Lang7dd2e102014-11-10 15:19:26 -05001886GLint Program::getFragDataLocation(const std::string &name) const
1887{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001888 ASSERT(mLinkResolved);
Olli Etuaho0ca09752018-09-24 11:00:50 +03001889 GLint primaryLocation =
1890 GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
1891 if (primaryLocation != -1)
1892 {
1893 return primaryLocation;
1894 }
1895 return GetVariableLocation(mState.mOutputVariables, mState.mSecondaryOutputLocations, name);
1896}
1897
1898GLint Program::getFragDataIndex(const std::string &name) const
1899{
1900 ASSERT(mLinkResolved);
1901 if (GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name) != -1)
1902 {
1903 return 0;
1904 }
1905 if (GetVariableLocation(mState.mOutputVariables, mState.mSecondaryOutputLocations, name) != -1)
1906 {
1907 return 1;
1908 }
1909 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001910}
1911
Geoff Lange1a27752015-10-05 13:16:04 -04001912void Program::getActiveUniform(GLuint index,
1913 GLsizei bufsize,
1914 GLsizei *length,
1915 GLint *size,
1916 GLenum *type,
1917 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001918{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001919 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001920 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001921 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001922 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001923 ASSERT(index < mState.mUniforms.size());
1924 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001925
1926 if (bufsize > 0)
1927 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001928 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001929 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001930 }
1931
Olli Etuaho465835d2017-09-26 13:34:10 +03001932 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001933 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001934 }
1935 else
1936 {
1937 if (bufsize > 0)
1938 {
1939 name[0] = '\0';
1940 }
1941
1942 if (length)
1943 {
1944 *length = 0;
1945 }
1946
1947 *size = 0;
1948 *type = GL_NONE;
1949 }
1950}
1951
Geoff Lange1a27752015-10-05 13:16:04 -04001952GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001953{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001954 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001955 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001956 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001957 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001958 }
1959 else
1960 {
1961 return 0;
1962 }
1963}
1964
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001965size_t Program::getActiveBufferVariableCount() const
1966{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001967 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001968 return mLinked ? mState.mBufferVariables.size() : 0;
1969}
1970
Geoff Lange1a27752015-10-05 13:16:04 -04001971GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001972{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001973 ASSERT(mLinkResolved);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001974 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001975
1976 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001977 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001978 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001979 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001980 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001981 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001982 size_t length = uniform.name.length() + 1u;
1983 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001984 {
1985 length += 3; // Counting in "[0]".
1986 }
1987 maxLength = std::max(length, maxLength);
1988 }
1989 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001990 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001991
Jamie Madill62d31cb2015-09-11 13:25:51 -04001992 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001993}
1994
Geoff Lang7dd2e102014-11-10 15:19:26 -05001995bool Program::isValidUniformLocation(GLint location) const
1996{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04001997 ASSERT(mLinkResolved);
Jamie Madille2e406c2016-06-02 13:04:10 -04001998 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001999 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04002000 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04002001}
2002
Jamie Madill62d31cb2015-09-11 13:25:51 -04002003const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002004{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002005 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002006 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05002007 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002008}
2009
Jamie Madillac4e9c32017-01-13 14:07:12 -05002010const VariableLocation &Program::getUniformLocation(GLint location) const
2011{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002012 ASSERT(mLinkResolved);
Jamie Madillac4e9c32017-01-13 14:07:12 -05002013 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
2014 return mState.mUniformLocations[location];
2015}
2016
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002017const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
2018{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002019 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002020 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
2021 return mState.mBufferVariables[index];
2022}
2023
Jamie Madill62d31cb2015-09-11 13:25:51 -04002024GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002025{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002026 ASSERT(mLinkResolved);
Olli Etuahod2551232017-10-26 20:03:33 +03002027 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002028}
2029
Jamie Madill62d31cb2015-09-11 13:25:51 -04002030GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002031{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002032 ASSERT(mLinkResolved);
Jamie Madille7d84322017-01-10 18:21:59 -05002033 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002034}
2035
2036void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2037{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002038 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002039 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2040 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002041 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002042}
2043
2044void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2045{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002046 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002047 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2048 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002049 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002050}
2051
2052void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2053{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002054 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002055 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2056 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002057 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002058}
2059
2060void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2061{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002062 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002063 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2064 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002065 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002066}
2067
Jamie Madill81c2e252017-09-09 23:32:46 -04002068Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002069{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002070 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002071 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2072 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
2073
Jamie Madill81c2e252017-09-09 23:32:46 -04002074 mProgram->setUniform1iv(location, clampedCount, v);
2075
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002076 if (mState.isSamplerUniformIndex(locationInfo.index))
2077 {
2078 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04002079 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002080 }
2081
Jamie Madill81c2e252017-09-09 23:32:46 -04002082 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002083}
2084
2085void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
2086{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002087 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002088 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2089 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002090 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002091}
2092
2093void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
2094{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002095 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002096 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2097 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002098 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002099}
2100
2101void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
2102{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002103 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002104 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2105 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002106 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002107}
2108
2109void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
2110{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002111 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002112 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2113 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002114 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002115}
2116
2117void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
2118{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002119 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002120 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2121 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002122 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002123}
2124
2125void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
2126{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002127 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002128 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2129 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002130 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002131}
2132
2133void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
2134{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002135 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002136 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2137 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002138 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002139}
2140
Jamie Madill493f9572018-05-24 19:52:15 -04002141void Program::setUniformMatrix2fv(GLint location,
2142 GLsizei count,
2143 GLboolean transpose,
2144 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002145{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002146 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002147 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002148 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002149}
2150
Jamie Madill493f9572018-05-24 19:52:15 -04002151void Program::setUniformMatrix3fv(GLint location,
2152 GLsizei count,
2153 GLboolean transpose,
2154 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002155{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002156 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002157 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002158 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159}
2160
Jamie Madill493f9572018-05-24 19:52:15 -04002161void Program::setUniformMatrix4fv(GLint location,
2162 GLsizei count,
2163 GLboolean transpose,
2164 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002165{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002166 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002167 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002168 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002169}
2170
Jamie Madill493f9572018-05-24 19:52:15 -04002171void Program::setUniformMatrix2x3fv(GLint location,
2172 GLsizei count,
2173 GLboolean transpose,
2174 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002175{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002176 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002177 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002178 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002179}
2180
Jamie Madill493f9572018-05-24 19:52:15 -04002181void Program::setUniformMatrix2x4fv(GLint location,
2182 GLsizei count,
2183 GLboolean transpose,
2184 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002185{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002186 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002187 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002188 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189}
2190
Jamie Madill493f9572018-05-24 19:52:15 -04002191void Program::setUniformMatrix3x2fv(GLint location,
2192 GLsizei count,
2193 GLboolean transpose,
2194 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002196 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002197 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002198 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002199}
2200
Jamie Madill493f9572018-05-24 19:52:15 -04002201void Program::setUniformMatrix3x4fv(GLint location,
2202 GLsizei count,
2203 GLboolean transpose,
2204 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002206 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002207 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002208 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002209}
2210
Jamie Madill493f9572018-05-24 19:52:15 -04002211void Program::setUniformMatrix4x2fv(GLint location,
2212 GLsizei count,
2213 GLboolean transpose,
2214 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002215{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002216 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002217 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002218 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002219}
2220
Jamie Madill493f9572018-05-24 19:52:15 -04002221void Program::setUniformMatrix4x3fv(GLint location,
2222 GLsizei count,
2223 GLboolean transpose,
2224 const GLfloat *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002225{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002226 ASSERT(mLinkResolved);
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04002227 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002228 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002229}
2230
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002231GLuint Program::getSamplerUniformBinding(const VariableLocation &uniformLocation) const
2232{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002233 ASSERT(mLinkResolved);
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002234 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(uniformLocation.index);
2235 const std::vector<GLuint> &boundTextureUnits =
2236 mState.mSamplerBindings[samplerIndex].boundTextureUnits;
2237 return boundTextureUnits[uniformLocation.arrayIndex];
2238}
2239
Jamie Madill54164b02017-08-28 15:17:37 -04002240void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002241{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002242 ASSERT(mLinkResolved);
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002243 const VariableLocation &uniformLocation = mState.getUniformLocations()[location];
2244 const LinkedUniform &uniform = mState.getUniforms()[uniformLocation.index];
Jamie Madill54164b02017-08-28 15:17:37 -04002245
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002246 if (uniform.isSampler())
2247 {
2248 *v = static_cast<GLfloat>(getSamplerUniformBinding(uniformLocation));
2249 return;
2250 }
2251
2252 const GLenum nativeType = gl::VariableComponentType(uniform.type);
Jamie Madill54164b02017-08-28 15:17:37 -04002253 if (nativeType == GL_FLOAT)
2254 {
2255 mProgram->getUniformfv(context, location, v);
2256 }
2257 else
2258 {
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002259 getUniformInternal(context, v, location, nativeType, VariableComponentCount(uniform.type));
Jamie Madill54164b02017-08-28 15:17:37 -04002260 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002261}
2262
Jamie Madill54164b02017-08-28 15:17:37 -04002263void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002264{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002265 ASSERT(mLinkResolved);
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002266 const VariableLocation &uniformLocation = mState.getUniformLocations()[location];
2267 const LinkedUniform &uniform = mState.getUniforms()[uniformLocation.index];
Jamie Madill54164b02017-08-28 15:17:37 -04002268
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002269 if (uniform.isSampler())
2270 {
2271 *v = static_cast<GLint>(getSamplerUniformBinding(uniformLocation));
2272 return;
2273 }
2274
2275 const GLenum nativeType = gl::VariableComponentType(uniform.type);
Jamie Madill54164b02017-08-28 15:17:37 -04002276 if (nativeType == GL_INT || nativeType == GL_BOOL)
2277 {
2278 mProgram->getUniformiv(context, location, v);
2279 }
2280 else
2281 {
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002282 getUniformInternal(context, v, location, nativeType, VariableComponentCount(uniform.type));
Jamie Madill54164b02017-08-28 15:17:37 -04002283 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002284}
2285
Jamie Madill54164b02017-08-28 15:17:37 -04002286void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002287{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002288 ASSERT(mLinkResolved);
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002289 const VariableLocation &uniformLocation = mState.getUniformLocations()[location];
2290 const LinkedUniform &uniform = mState.getUniforms()[uniformLocation.index];
Jamie Madill54164b02017-08-28 15:17:37 -04002291
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002292 if (uniform.isSampler())
2293 {
2294 *v = getSamplerUniformBinding(uniformLocation);
2295 return;
2296 }
2297
2298 const GLenum nativeType = VariableComponentType(uniform.type);
Jamie Madill54164b02017-08-28 15:17:37 -04002299 if (nativeType == GL_UNSIGNED_INT)
2300 {
2301 mProgram->getUniformuiv(context, location, v);
2302 }
2303 else
2304 {
Jamie Madill3bb2bbe2018-06-15 09:47:03 -04002305 getUniformInternal(context, v, location, nativeType, VariableComponentCount(uniform.type));
Jamie Madill54164b02017-08-28 15:17:37 -04002306 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002307}
2308
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002309void Program::flagForDeletion()
2310{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002311 ASSERT(mLinkResolved);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002312 mDeleteStatus = true;
2313}
2314
2315bool Program::isFlaggedForDeletion() const
2316{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002317 ASSERT(mLinkResolved);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002318 return mDeleteStatus;
2319}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002320
Brandon Jones43a53e22014-08-28 16:23:22 -07002321void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002322{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002323 ASSERT(mLinkResolved);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002324 mInfoLog.reset();
2325
Geoff Lang7dd2e102014-11-10 15:19:26 -05002326 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002327 {
Geoff Lang92019432017-11-20 13:09:34 -05002328 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002329 }
2330 else
2331 {
Jamie Madillf6113162015-05-07 11:49:21 -04002332 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002333 }
2334}
2335
Jamie Madillcc73f242018-08-01 11:34:48 -04002336bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002337{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002338 ASSERT(mLinkResolved);
jchen107ae70d82018-07-06 13:47:01 +08002339
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002340 // if any two active samplers in a program are of different types, but refer to the same
2341 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2342 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madill7e4eff12018-08-08 15:49:26 -04002343 for (size_t textureUnit : mState.mActiveSamplersMask)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002344 {
Jamie Madill7e4eff12018-08-08 15:49:26 -04002345 if (mState.mActiveSamplerTypes[textureUnit] == TextureType::InvalidEnum)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002346 {
Jamie Madill7e4eff12018-08-08 15:49:26 -04002347 if (infoLog)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002348 {
Jamie Madill7e4eff12018-08-08 15:49:26 -04002349 (*infoLog) << "Samplers of conflicting types refer to the same texture "
2350 "image unit ("
2351 << textureUnit << ").";
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002352 }
2353
Jamie Madill7e4eff12018-08-08 15:49:26 -04002354 mCachedValidateSamplersResult = false;
2355 return false;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002356 }
2357 }
2358
2359 mCachedValidateSamplersResult = true;
2360 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002361}
2362
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00002363bool Program::isValidated() const
2364{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002365 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002366 return mValidated;
2367}
2368
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002369void Program::getActiveUniformBlockName(const GLuint blockIndex,
2370 GLsizei bufSize,
2371 GLsizei *length,
2372 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002373{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002374 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002375 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
2376}
Geoff Lang7dd2e102014-11-10 15:19:26 -05002377
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002378void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
2379 GLsizei bufSize,
2380 GLsizei *length,
2381 GLchar *blockName) const
2382{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002383 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002384 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00002385}
2386
Qin Jiajia9bf55522018-01-29 13:56:23 +08002387template <typename T>
2388GLint Program::getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002389{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002390 int maxLength = 0;
2391
2392 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002393 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002394 for (const T &resource : resources)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002395 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002396 if (!resource.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002397 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08002398 int length = static_cast<int>(resource.nameWithArrayIndex().length());
jchen10af713a22017-04-19 09:10:56 +08002399 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002400 }
2401 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002402 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002403
2404 return maxLength;
2405}
2406
Qin Jiajia9bf55522018-01-29 13:56:23 +08002407GLint Program::getActiveUniformBlockMaxNameLength() const
2408{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002409 ASSERT(mLinkResolved);
Qin Jiajia9bf55522018-01-29 13:56:23 +08002410 return getActiveInterfaceBlockMaxNameLength(mState.mUniformBlocks);
2411}
2412
2413GLint Program::getActiveShaderStorageBlockMaxNameLength() const
2414{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002415 ASSERT(mLinkResolved);
Qin Jiajia9bf55522018-01-29 13:56:23 +08002416 return getActiveInterfaceBlockMaxNameLength(mState.mShaderStorageBlocks);
2417}
2418
Geoff Lange1a27752015-10-05 13:16:04 -04002419GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002420{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002421 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002422 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
2423}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002424
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002425GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
2426{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002427 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002428 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002429}
2430
Jiajia Qin729b2c62017-08-14 09:36:11 +08002431const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002432{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002433 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002434 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
2435 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002436}
2437
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002438const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
2439{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002440 ASSERT(mLinkResolved);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08002441 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
2442 return mState.mShaderStorageBlocks[index];
2443}
2444
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002445void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2446{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002447 ASSERT(mLinkResolved);
jchen107a20b972017-06-13 14:25:26 +08002448 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05002449 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Jamie Madill70aeda42018-08-20 12:17:40 -04002450 mDirtyBits.set(DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002451}
2452
2453GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
2454{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002455 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002456 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002457}
2458
Jiajia Qin729b2c62017-08-14 09:36:11 +08002459GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
2460{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002461 ASSERT(mLinkResolved);
Jiajia Qin729b2c62017-08-14 09:36:11 +08002462 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
2463}
2464
Jamie Madill493f9572018-05-24 19:52:15 -04002465void Program::setTransformFeedbackVaryings(GLsizei count,
2466 const GLchar *const *varyings,
2467 GLenum bufferMode)
Geoff Lang48dcae72014-02-05 16:28:24 -05002468{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002469 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002470 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05002471 for (GLsizei i = 0; i < count; i++)
2472 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002473 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05002474 }
2475
Jamie Madill48ef11b2016-04-27 15:21:52 -04002476 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05002477}
2478
Jamie Madill493f9572018-05-24 19:52:15 -04002479void Program::getTransformFeedbackVarying(GLuint index,
2480 GLsizei bufSize,
2481 GLsizei *length,
2482 GLsizei *size,
2483 GLenum *type,
2484 GLchar *name) const
Geoff Lang48dcae72014-02-05 16:28:24 -05002485{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002486 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002487 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002488 {
jchen10a9042d32017-03-17 08:50:45 +08002489 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2490 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
2491 std::string varName = var.nameWithArrayIndex();
2492 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05002493 if (length)
2494 {
2495 *length = lastNameIdx;
2496 }
2497 if (size)
2498 {
jchen10a9042d32017-03-17 08:50:45 +08002499 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05002500 }
2501 if (type)
2502 {
jchen10a9042d32017-03-17 08:50:45 +08002503 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05002504 }
2505 if (name)
2506 {
jchen10a9042d32017-03-17 08:50:45 +08002507 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05002508 name[lastNameIdx] = '\0';
2509 }
2510 }
2511}
2512
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002513GLsizei Program::getTransformFeedbackVaryingCount() const
2514{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002515 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002516 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002517 {
jchen10a9042d32017-03-17 08:50:45 +08002518 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05002519 }
2520 else
2521 {
2522 return 0;
2523 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002524}
2525
2526GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2527{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002528 ASSERT(mLinkResolved);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002529 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002530 {
2531 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08002532 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05002533 {
jchen10a9042d32017-03-17 08:50:45 +08002534 maxSize =
2535 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05002536 }
2537
2538 return maxSize;
2539 }
2540 else
2541 {
2542 return 0;
2543 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002544}
2545
2546GLenum Program::getTransformFeedbackBufferMode() const
2547{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002548 ASSERT(mLinkResolved);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002549 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002550}
2551
jchen103fd614d2018-08-13 12:21:58 +08002552bool Program::linkValidateShaders(InfoLog &infoLog)
Jiawei Shao73618602017-12-20 15:47:15 +08002553{
Jiawei Shao016105b2018-04-12 16:38:31 +08002554 Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
2555 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
2556 Shader *computeShader = mState.mAttachedShaders[ShaderType::Compute];
2557 Shader *geometryShader = mState.mAttachedShaders[ShaderType::Geometry];
Jiawei Shao73618602017-12-20 15:47:15 +08002558
Jamie Madill493f9572018-05-24 19:52:15 -04002559 bool isComputeShaderAttached = (computeShader != nullptr);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002560 bool isGraphicsShaderAttached =
2561 (vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +08002562 // Check whether we both have a compute and non-compute shaders attached.
2563 // If there are of both types attached, then linking should fail.
2564 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
2565 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
2566 {
2567 infoLog << "Both compute and graphics shaders are attached to the same program.";
2568 return false;
2569 }
2570
2571 if (computeShader)
2572 {
jchen103fd614d2018-08-13 12:21:58 +08002573 if (!computeShader->isCompiled())
Jiawei Shao73618602017-12-20 15:47:15 +08002574 {
2575 infoLog << "Attached compute shader is not compiled.";
2576 return false;
2577 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002578 ASSERT(computeShader->getType() == ShaderType::Compute);
Jiawei Shao73618602017-12-20 15:47:15 +08002579
jchen103fd614d2018-08-13 12:21:58 +08002580 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Jiawei Shao73618602017-12-20 15:47:15 +08002581
2582 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2583 // If the work group size is not specified, a link time error should occur.
2584 if (!mState.mComputeShaderLocalSize.isDeclared())
2585 {
2586 infoLog << "Work group size is not specified.";
2587 return false;
2588 }
2589 }
2590 else
2591 {
jchen103fd614d2018-08-13 12:21:58 +08002592 if (!fragmentShader || !fragmentShader->isCompiled())
Jiawei Shao73618602017-12-20 15:47:15 +08002593 {
2594 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2595 return false;
2596 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002597 ASSERT(fragmentShader->getType() == ShaderType::Fragment);
Jiawei Shao73618602017-12-20 15:47:15 +08002598
jchen103fd614d2018-08-13 12:21:58 +08002599 if (!vertexShader || !vertexShader->isCompiled())
Jiawei Shao73618602017-12-20 15:47:15 +08002600 {
2601 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2602 return false;
2603 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002604 ASSERT(vertexShader->getType() == ShaderType::Vertex);
Jiawei Shao73618602017-12-20 15:47:15 +08002605
jchen103fd614d2018-08-13 12:21:58 +08002606 int vertexShaderVersion = vertexShader->getShaderVersion();
2607 if (fragmentShader->getShaderVersion() != vertexShaderVersion)
Jiawei Shao73618602017-12-20 15:47:15 +08002608 {
2609 infoLog << "Fragment shader version does not match vertex shader version.";
2610 return false;
2611 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002612
2613 if (geometryShader)
2614 {
2615 // [GL_EXT_geometry_shader] Chapter 7
2616 // Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
2617 // Language Specification, as well as any of the following reasons:
2618 // * One or more of the shader objects attached to <program> are not compiled
2619 // successfully.
2620 // * The shaders do not use the same shader language version.
2621 // * <program> contains objects to form a geometry shader, and
2622 // - <program> is not separable and contains no objects to form a vertex shader; or
2623 // - the input primitive type, output primitive type, or maximum output vertex count
2624 // is not specified in the compiled geometry shader object.
jchen103fd614d2018-08-13 12:21:58 +08002625 if (!geometryShader->isCompiled())
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002626 {
2627 infoLog << "The attached geometry shader isn't compiled.";
2628 return false;
2629 }
2630
jchen103fd614d2018-08-13 12:21:58 +08002631 if (geometryShader->getShaderVersion() != vertexShaderVersion)
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002632 {
2633 mInfoLog << "Geometry shader version does not match vertex shader version.";
2634 return false;
2635 }
Jiawei Shao385b3e02018-03-21 09:43:28 +08002636 ASSERT(geometryShader->getType() == ShaderType::Geometry);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002637
Jamie Madill493f9572018-05-24 19:52:15 -04002638 Optional<PrimitiveMode> inputPrimitive =
jchen103fd614d2018-08-13 12:21:58 +08002639 geometryShader->getGeometryShaderInputPrimitiveType();
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002640 if (!inputPrimitive.valid())
2641 {
2642 mInfoLog << "Input primitive type is not specified in the geometry shader.";
2643 return false;
2644 }
2645
Jamie Madill493f9572018-05-24 19:52:15 -04002646 Optional<PrimitiveMode> outputPrimitive =
jchen103fd614d2018-08-13 12:21:58 +08002647 geometryShader->getGeometryShaderOutputPrimitiveType();
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002648 if (!outputPrimitive.valid())
2649 {
2650 mInfoLog << "Output primitive type is not specified in the geometry shader.";
2651 return false;
2652 }
2653
jchen103fd614d2018-08-13 12:21:58 +08002654 Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices();
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002655 if (!maxVertices.valid())
2656 {
2657 mInfoLog << "'max_vertices' is not specified in the geometry shader.";
2658 return false;
2659 }
2660
2661 mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
2662 mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
2663 mState.mGeometryShaderMaxVertices = maxVertices.value();
jchen103fd614d2018-08-13 12:21:58 +08002664 mState.mGeometryShaderInvocations = geometryShader->getGeometryShaderInvocations();
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002665 }
Jiawei Shao73618602017-12-20 15:47:15 +08002666 }
2667
2668 return true;
2669}
2670
jchen10910a3da2017-11-15 09:40:11 +08002671GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2672{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002673 ASSERT(mLinkResolved);
jchen10910a3da2017-11-15 09:40:11 +08002674 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2675 {
2676 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2677 if (tf.nameWithArrayIndex() == name)
2678 {
2679 return tfIndex;
2680 }
2681 }
2682 return GL_INVALID_INDEX;
2683}
2684
2685const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2686{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04002687 ASSERT(mLinkResolved);
jchen10910a3da2017-11-15 09:40:11 +08002688 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2689 return mState.mLinkedTransformFeedbackVaryings[index];
2690}
2691
Austin Eng1bf18ce2018-10-19 15:34:02 -07002692bool Program::hasDrawIDUniform() const
2693{
2694 ASSERT(mLinkResolved);
2695 return mState.mDrawIDLocation >= 0;
2696}
2697
2698void Program::setDrawIDUniform(GLint drawid)
2699{
2700 ASSERT(mLinkResolved);
2701 ASSERT(mState.mDrawIDLocation >= 0);
2702 mProgram->setUniform1iv(mState.mDrawIDLocation, 1, &drawid);
2703}
2704
jchen103fd614d2018-08-13 12:21:58 +08002705bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002706{
Jiawei Shao016105b2018-04-12 16:38:31 +08002707 Shader *previousShader = nullptr;
2708 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Jiawei Shaod063aff2018-02-22 10:19:09 +08002709 {
Jiawei Shao016105b2018-04-12 16:38:31 +08002710 Shader *currentShader = mState.mAttachedShaders[shaderType];
2711 if (!currentShader)
Jiawei Shaod063aff2018-02-22 10:19:09 +08002712 {
Jiawei Shao016105b2018-04-12 16:38:31 +08002713 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002714 }
Jiawei Shao016105b2018-04-12 16:38:31 +08002715
2716 if (previousShader)
2717 {
jchen103fd614d2018-08-13 12:21:58 +08002718 if (!linkValidateShaderInterfaceMatching(previousShader, currentShader, infoLog))
Jiawei Shao016105b2018-04-12 16:38:31 +08002719 {
2720 return false;
2721 }
2722 }
2723 previousShader = currentShader;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002724 }
2725
jchen103fd614d2018-08-13 12:21:58 +08002726 if (!linkValidateBuiltInVaryings(infoLog))
Jiawei Shaod063aff2018-02-22 10:19:09 +08002727 {
2728 return false;
2729 }
2730
jchen103fd614d2018-08-13 12:21:58 +08002731 if (!linkValidateFragmentInputBindings(infoLog))
Jiawei Shaod063aff2018-02-22 10:19:09 +08002732 {
2733 return false;
2734 }
2735
2736 return true;
2737}
2738
2739// [OpenGL ES 3.1] Chapter 7.4.1 "Shader Interface Matchining" Page 91
2740// TODO(jiawei.shao@intel.com): add validation on input/output blocks matching
jchen103fd614d2018-08-13 12:21:58 +08002741bool Program::linkValidateShaderInterfaceMatching(gl::Shader *generatingShader,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002742 gl::Shader *consumingShader,
2743 gl::InfoLog &infoLog) const
2744{
jchen103fd614d2018-08-13 12:21:58 +08002745 ASSERT(generatingShader->getShaderVersion() == consumingShader->getShaderVersion());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002746
jchen103fd614d2018-08-13 12:21:58 +08002747 const std::vector<sh::Varying> &outputVaryings = generatingShader->getOutputVaryings();
2748 const std::vector<sh::Varying> &inputVaryings = consumingShader->getInputVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05002749
Jiawei Shao385b3e02018-03-21 09:43:28 +08002750 bool validateGeometryShaderInputs = consumingShader->getType() == ShaderType::Geometry;
Sami Väisänen46eaa942016-06-29 10:26:37 +03002751
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002752 for (const sh::Varying &input : inputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002753 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002754 bool matched = false;
2755
2756 // Built-in varyings obey special rules
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002757 if (input.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002758 {
2759 continue;
2760 }
2761
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002762 for (const sh::Varying &output : outputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002763 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002764 if (input.name == output.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002765 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002766 ASSERT(!output.isBuiltIn());
2767
2768 std::string mismatchedStructFieldName;
2769 LinkMismatchError linkError =
jchen103fd614d2018-08-13 12:21:58 +08002770 LinkValidateVaryings(output, input, generatingShader->getShaderVersion(),
Jiawei Shaod063aff2018-02-22 10:19:09 +08002771 validateGeometryShaderInputs, &mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002772 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002773 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002774 LogLinkMismatch(infoLog, input.name, "varying", linkError,
2775 mismatchedStructFieldName, generatingShader->getType(),
2776 consumingShader->getType());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002777 return false;
2778 }
2779
Geoff Lang7dd2e102014-11-10 15:19:26 -05002780 matched = true;
2781 break;
2782 }
2783 }
2784
Olli Etuaho107c7242018-03-20 15:45:35 +02002785 // We permit unmatched, unreferenced varyings. Note that this specifically depends on
2786 // whether the input is statically used - a statically used input should fail this test even
2787 // if it is not active. GLSL ES 3.00.6 section 4.3.10.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002788 if (!matched && input.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002789 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002790 infoLog << GetShaderTypeString(consumingShader->getType()) << " varying " << input.name
2791 << " does not match any " << GetShaderTypeString(generatingShader->getType())
2792 << " varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002793 return false;
2794 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002795 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002796
Jiawei Shaod063aff2018-02-22 10:19:09 +08002797 // TODO(jmadill): verify no unmatched output varyings?
Sami Väisänen46eaa942016-06-29 10:26:37 +03002798
Jiawei Shaod063aff2018-02-22 10:19:09 +08002799 return true;
2800}
2801
jchen103fd614d2018-08-13 12:21:58 +08002802bool Program::linkValidateFragmentInputBindings(gl::InfoLog &infoLog) const
Jiawei Shaod063aff2018-02-22 10:19:09 +08002803{
Jiawei Shao016105b2018-04-12 16:38:31 +08002804 ASSERT(mState.mAttachedShaders[ShaderType::Fragment]);
Jiawei Shaod063aff2018-02-22 10:19:09 +08002805
2806 std::map<GLuint, std::string> staticFragmentInputLocations;
2807
2808 const std::vector<sh::Varying> &fragmentInputVaryings =
jchen103fd614d2018-08-13 12:21:58 +08002809 mState.mAttachedShaders[ShaderType::Fragment]->getInputVaryings();
Jiawei Shaod063aff2018-02-22 10:19:09 +08002810 for (const sh::Varying &input : fragmentInputVaryings)
2811 {
2812 if (input.isBuiltIn() || !input.staticUse)
2813 {
Sami Väisänen46eaa942016-06-29 10:26:37 +03002814 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002815 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002816
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002817 const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
Sami Väisänen46eaa942016-06-29 10:26:37 +03002818 if (inputBinding == -1)
2819 continue;
2820
2821 const auto it = staticFragmentInputLocations.find(inputBinding);
2822 if (it == std::end(staticFragmentInputLocations))
2823 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002824 staticFragmentInputLocations.insert(std::make_pair(inputBinding, input.name));
Sami Väisänen46eaa942016-06-29 10:26:37 +03002825 }
2826 else
2827 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002828 infoLog << "Binding for fragment input " << input.name << " conflicts with "
Sami Väisänen46eaa942016-06-29 10:26:37 +03002829 << it->second;
2830 return false;
2831 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002832 }
2833
2834 return true;
2835}
2836
jchen103fd614d2018-08-13 12:21:58 +08002837bool Program::linkUniforms(const Caps &caps,
Jamie Madillbd044ed2017-06-05 12:59:21 -04002838 InfoLog &infoLog,
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002839 const ProgramBindings &uniformLocationBindings,
Luc Ferrone17b5ba2018-06-04 14:28:58 -04002840 GLuint *combinedImageUniformsCount,
2841 std::vector<UnusedUniform> *unusedUniforms)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002842{
Olli Etuahob78707c2017-03-09 15:03:11 +00002843 UniformLinker linker(mState);
jchen103fd614d2018-08-13 12:21:58 +08002844 if (!linker.link(caps, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002845 {
2846 return false;
2847 }
2848
Luc Ferrone17b5ba2018-06-04 14:28:58 -04002849 linker.getResults(&mState.mUniforms, unusedUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002850
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002851 linkSamplerAndImageBindings(combinedImageUniformsCount);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002852
jchen10eaef1e52017-06-13 10:44:11 +08002853 if (!linkAtomicCounterBuffers())
2854 {
2855 return false;
2856 }
2857
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002858 return true;
2859}
2860
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002861void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002862{
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002863 ASSERT(combinedImageUniforms);
2864
Jamie Madill982f6e02017-06-07 14:33:04 -04002865 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2866 unsigned int low = high;
2867
jchen10eaef1e52017-06-13 10:44:11 +08002868 for (auto counterIter = mState.mUniforms.rbegin();
2869 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2870 {
2871 --low;
2872 }
2873
2874 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2875
2876 high = low;
2877
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002878 for (auto imageIter = mState.mUniforms.rbegin();
2879 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2880 {
2881 --low;
2882 }
2883
2884 mState.mImageUniformRange = RangeUI(low, high);
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002885 *combinedImageUniforms = 0u;
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002886 // If uniform is a image type, insert it into the mImageBindings array.
2887 for (unsigned int imageIndex : mState.mImageUniformRange)
2888 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002889 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2890 // cannot load values into a uniform defined as an image. if declare without a
2891 // binding qualifier, any uniform image variable (include all elements of
2892 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002893 auto &imageUniform = mState.mUniforms[imageIndex];
2894 if (imageUniform.binding == -1)
2895 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002896 mState.mImageBindings.emplace_back(
2897 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002898 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002899 else
2900 {
2901 mState.mImageBindings.emplace_back(
Qin Jiajia47f6dd02018-08-10 13:36:32 +08002902 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount(), false));
Xinghua Cao0328b572017-06-26 15:51:36 +08002903 }
Jiawei Shao7a8fe152018-04-28 12:59:58 +08002904
2905 GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u;
2906 *combinedImageUniforms += imageUniform.activeShaderCount() * arraySize;
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002907 }
2908
2909 high = low;
2910
2911 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002912 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002913 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002914 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002915 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002916
2917 mState.mSamplerUniformRange = RangeUI(low, high);
2918
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002919 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002920 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002921 {
2922 const auto &samplerUniform = mState.mUniforms[samplerIndex];
Corentin Wallezf0e89be2017-11-08 14:00:32 -08002923 TextureType textureType = SamplerTypeToTextureType(samplerUniform.type);
Jamie Madill7e4eff12018-08-08 15:49:26 -04002924 unsigned int elementCount = samplerUniform.getBasicTypeElementCount();
2925 mState.mSamplerBindings.emplace_back(textureType, elementCount, false);
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002926 }
2927}
2928
jchen10eaef1e52017-06-13 10:44:11 +08002929bool Program::linkAtomicCounterBuffers()
2930{
2931 for (unsigned int index : mState.mAtomicCounterUniformRange)
2932 {
Jamie Madill493f9572018-05-24 19:52:15 -04002933 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002934 uniform.blockInfo.offset = uniform.offset;
2935 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2936 uniform.blockInfo.matrixStride = 0;
2937 uniform.blockInfo.isRowMajorMatrix = false;
2938
Jamie Madill493f9572018-05-24 19:52:15 -04002939 bool found = false;
jchen10eaef1e52017-06-13 10:44:11 +08002940 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2941 ++bufferIndex)
2942 {
2943 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2944 if (buffer.binding == uniform.binding)
2945 {
2946 buffer.memberIndexes.push_back(index);
2947 uniform.bufferIndex = bufferIndex;
2948 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002949 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002950 break;
2951 }
2952 }
2953 if (!found)
2954 {
2955 AtomicCounterBuffer atomicCounterBuffer;
2956 atomicCounterBuffer.binding = uniform.binding;
2957 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002958 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002959 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2960 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2961 }
2962 }
2963 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
Jiawei Shao0d88ec92018-02-27 16:25:31 +08002964 // gl_Max[Vertex|Fragment|Compute|Geometry|Combined]AtomicCounterBuffers.
jchen10eaef1e52017-06-13 10:44:11 +08002965
2966 return true;
2967}
2968
Jamie Madilleb979bf2016-11-15 12:28:46 -05002969// Assigns locations to all attributes from the bindings and program locations.
jchen103fd614d2018-08-13 12:21:58 +08002970bool Program::linkAttributes(const Caps &caps, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002971{
Jiawei Shao385b3e02018-03-21 09:43:28 +08002972 Shader *vertexShader = mState.getAttachedShader(ShaderType::Vertex);
Jamie Madilleb979bf2016-11-15 12:28:46 -05002973
jchen103fd614d2018-08-13 12:21:58 +08002974 int shaderVersion = vertexShader->getShaderVersion();
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002975
Geoff Lang7dd2e102014-11-10 15:19:26 -05002976 unsigned int usedLocations = 0;
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002977 if (shaderVersion >= 300)
2978 {
2979 // In GLSL ES 3.00.6, aliasing checks should be done with all declared attributes - see GLSL
2980 // ES 3.00.6 section 12.46. Inactive attributes will be pruned after aliasing checks.
jchen103fd614d2018-08-13 12:21:58 +08002981 mState.mAttributes = vertexShader->getAllAttributes();
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002982 }
2983 else
2984 {
2985 // In GLSL ES 1.00.17 we only do aliasing checks for active attributes.
jchen103fd614d2018-08-13 12:21:58 +08002986 mState.mAttributes = vertexShader->getActiveAttributes();
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002987 }
jchen103fd614d2018-08-13 12:21:58 +08002988 GLuint maxAttribs = caps.maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002989
2990 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002991 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002992 {
Jamie Madillf6113162015-05-07 11:49:21 -04002993 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002994 return false;
2995 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002996
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002997 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002998
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02002999 // Assign locations to attributes that have a binding location and check for attribute aliasing.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003000 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04003001 {
Olli Etuahod2551232017-10-26 20:03:33 +03003002 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
3003 // structures, so we don't need to worry about adjusting their names or generating entries
3004 // for each member/element (unlike uniforms for example).
3005 ASSERT(!attribute.isArray() && !attribute.isStruct());
3006
Jamie Madilleb979bf2016-11-15 12:28:46 -05003007 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04003008 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04003009 {
Jamie Madillc349ec02015-08-21 16:53:12 -04003010 attribute.location = bindingLocation;
3011 }
3012
3013 if (attribute.location != -1)
3014 {
3015 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04003016 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05003017
Jamie Madill63805b42015-08-25 13:17:39 -04003018 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003019 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003020 infoLog << "Attribute (" << attribute.name << ") at location " << attribute.location
3021 << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05003022
3023 return false;
3024 }
3025
Jamie Madill63805b42015-08-25 13:17:39 -04003026 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003027 {
Jamie Madill63805b42015-08-25 13:17:39 -04003028 const int regLocation = attribute.location + reg;
3029 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05003030
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003031 // In GLSL ES 3.00.6 and in WebGL, attribute aliasing produces a link error.
3032 // In non-WebGL GLSL ES 1.00.17, attribute aliasing is allowed with some
3033 // restrictions - see GLSL ES 1.00.17 section 2.10.4, but ANGLE currently has a bug.
Jamie Madillc349ec02015-08-21 16:53:12 -04003034 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003035 {
Jamie Madillc349ec02015-08-21 16:53:12 -04003036 // TODO(jmadill): fix aliasing on ES2
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003037 // if (shaderVersion >= 300 && !webgl)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003038 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04003039 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04003040 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003041 return false;
3042 }
3043 }
Jamie Madillc349ec02015-08-21 16:53:12 -04003044 else
3045 {
Jamie Madill63805b42015-08-25 13:17:39 -04003046 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04003047 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003048
Jamie Madill63805b42015-08-25 13:17:39 -04003049 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003050 }
3051 }
3052 }
3053
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003054 // Assign locations to attributes that don't have a binding location.
Jamie Madill48ef11b2016-04-27 15:21:52 -04003055 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003056 {
Jamie Madillc349ec02015-08-21 16:53:12 -04003057 // Not set by glBindAttribLocation or by location layout qualifier
3058 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003059 {
Jamie Madill63805b42015-08-25 13:17:39 -04003060 int regs = VariableRegisterCount(attribute.type);
3061 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05003062
Jamie Madill63805b42015-08-25 13:17:39 -04003063 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003064 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003065 infoLog << "Too many attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04003066 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003067 }
3068
Jamie Madillc349ec02015-08-21 16:53:12 -04003069 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003070 }
3071 }
3072
Brandon Jonesc405ae72017-12-06 14:15:03 -08003073 ASSERT(mState.mAttributesTypeMask.none());
3074 ASSERT(mState.mAttributesMask.none());
3075
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003076 // Prune inactive attributes. This step is only needed on shaderVersion >= 300 since on earlier
3077 // shader versions we're only processing active attributes to begin with.
3078 if (shaderVersion >= 300)
3079 {
3080 for (auto attributeIter = mState.mAttributes.begin();
3081 attributeIter != mState.mAttributes.end();)
3082 {
3083 if (attributeIter->active)
3084 {
3085 ++attributeIter;
3086 }
3087 else
3088 {
3089 attributeIter = mState.mAttributes.erase(attributeIter);
3090 }
3091 }
3092 }
3093
Jamie Madill48ef11b2016-04-27 15:21:52 -04003094 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003095 {
Olli Etuahoebd6e2d2018-03-23 17:07:55 +02003096 ASSERT(attribute.active);
Jamie Madill63805b42015-08-25 13:17:39 -04003097 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04003098 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04003099
Jamie Madillbd159f02017-10-09 19:39:06 -04003100 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003101 {
Jamie Madillbd159f02017-10-09 19:39:06 -04003102 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
3103 mState.mActiveAttribLocationsMask.set(location);
3104 mState.mMaxActiveAttribLocation =
3105 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08003106
3107 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
3108 if (!attribute.isBuiltIn())
3109 {
3110 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
3111 location);
3112 mState.mAttributesMask.set(location);
3113 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003114 }
3115 }
3116
Geoff Lang7dd2e102014-11-10 15:19:26 -05003117 return true;
3118}
3119
jchen103fd614d2018-08-13 12:21:58 +08003120bool Program::linkInterfaceBlocks(const Caps &caps,
3121 const Version &version,
3122 bool webglCompatibility,
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003123 InfoLog &infoLog,
3124 GLuint *combinedShaderStorageBlocksCount)
Martin Radev4c4c8e72016-08-04 12:25:34 +03003125{
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003126 ASSERT(combinedShaderStorageBlocksCount);
3127
Jiawei Shao54aafe52018-04-27 14:54:57 +08003128 GLuint combinedUniformBlocksCount = 0u;
3129 GLuint numShadersHasUniformBlocks = 0u;
3130 ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderUniformBlocks = {};
3131 for (ShaderType shaderType : AllShaderTypes())
Martin Radev4c4c8e72016-08-04 12:25:34 +03003132 {
Jiawei Shao40786bd2018-04-18 13:58:57 +08003133 Shader *shader = mState.mAttachedShaders[shaderType];
3134 if (!shader)
3135 {
3136 continue;
3137 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03003138
jchen103fd614d2018-08-13 12:21:58 +08003139 const auto &uniformBlocks = shader->getUniformBlocks();
Jiawei Shao54aafe52018-04-27 14:54:57 +08003140 if (!uniformBlocks.empty())
Jiawei Shao427071e2018-03-19 09:21:37 +08003141 {
Jiawei Shao54aafe52018-04-27 14:54:57 +08003142 if (!ValidateInterfaceBlocksCount(
3143 caps.maxShaderUniformBlocks[shaderType], uniformBlocks, shaderType,
3144 sh::BlockType::BLOCK_UNIFORM, &combinedUniformBlocksCount, infoLog))
3145 {
3146 return false;
3147 }
Jiawei Shao40786bd2018-04-18 13:58:57 +08003148
Jiawei Shao54aafe52018-04-27 14:54:57 +08003149 allShaderUniformBlocks[shaderType] = &uniformBlocks;
3150 ++numShadersHasUniformBlocks;
3151 }
Jiawei Shao427071e2018-03-19 09:21:37 +08003152 }
3153
Jiawei Shaobb3255b2018-04-27 09:45:18 +08003154 if (combinedUniformBlocksCount > caps.maxCombinedUniformBlocks)
3155 {
3156 infoLog << "The sum of the number of active uniform blocks exceeds "
3157 "MAX_COMBINED_UNIFORM_BLOCKS ("
3158 << caps.maxCombinedUniformBlocks << ").";
3159 return false;
3160 }
3161
Jiawei Shao54aafe52018-04-27 14:54:57 +08003162 if (!ValidateInterfaceBlocksMatch(numShadersHasUniformBlocks, allShaderUniformBlocks, infoLog,
3163 webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03003164 {
3165 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003166 }
Jamie Madille473dee2015-08-18 14:49:01 -04003167
jchen103fd614d2018-08-13 12:21:58 +08003168 if (version >= Version(3, 1))
Jiajia Qin729b2c62017-08-14 09:36:11 +08003169 {
Jiawei Shao54aafe52018-04-27 14:54:57 +08003170 *combinedShaderStorageBlocksCount = 0u;
3171 GLuint numShadersHasShaderStorageBlocks = 0u;
3172 ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderStorageBlocks = {};
3173 for (ShaderType shaderType : AllShaderTypes())
Jiajia Qin729b2c62017-08-14 09:36:11 +08003174 {
Jiawei Shao40786bd2018-04-18 13:58:57 +08003175 Shader *shader = mState.mAttachedShaders[shaderType];
3176 if (!shader)
3177 {
3178 continue;
3179 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08003180
jchen103fd614d2018-08-13 12:21:58 +08003181 const auto &shaderStorageBlocks = shader->getShaderStorageBlocks();
Jiawei Shao54aafe52018-04-27 14:54:57 +08003182 if (!shaderStorageBlocks.empty())
Jiawei Shao427071e2018-03-19 09:21:37 +08003183 {
Jiawei Shao54aafe52018-04-27 14:54:57 +08003184 if (!ValidateInterfaceBlocksCount(
3185 caps.maxShaderStorageBlocks[shaderType], shaderStorageBlocks, shaderType,
3186 sh::BlockType::BLOCK_BUFFER, combinedShaderStorageBlocksCount, infoLog))
3187 {
3188 return false;
3189 }
Jiawei Shao40786bd2018-04-18 13:58:57 +08003190
Jiawei Shao54aafe52018-04-27 14:54:57 +08003191 allShaderStorageBlocks[shaderType] = &shaderStorageBlocks;
3192 ++numShadersHasShaderStorageBlocks;
3193 }
Jiawei Shao427071e2018-03-19 09:21:37 +08003194 }
3195
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003196 if (*combinedShaderStorageBlocksCount > caps.maxCombinedShaderStorageBlocks)
Jiawei Shaobb3255b2018-04-27 09:45:18 +08003197 {
3198 infoLog << "The sum of the number of active shader storage blocks exceeds "
3199 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
3200 << caps.maxCombinedShaderStorageBlocks << ").";
3201 return false;
3202 }
3203
Jiawei Shao54aafe52018-04-27 14:54:57 +08003204 if (!ValidateInterfaceBlocksMatch(numShadersHasShaderStorageBlocks, allShaderStorageBlocks,
3205 infoLog, webglCompatibility))
Jiajia Qin729b2c62017-08-14 09:36:11 +08003206 {
3207 return false;
3208 }
3209 }
Jiawei Shao54aafe52018-04-27 14:54:57 +08003210
Geoff Lang7dd2e102014-11-10 15:19:26 -05003211 return true;
3212}
3213
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003214LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &variable1,
3215 const sh::ShaderVariable &variable2,
3216 bool validatePrecision,
Jiawei Shaod063aff2018-02-22 10:19:09 +08003217 bool validateArraySize,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003218 std::string *mismatchedStructOrBlockMemberName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003219{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003220 if (variable1.type != variable2.type)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003221 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003222 return LinkMismatchError::TYPE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003223 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08003224 if (validateArraySize && variable1.arraySizes != variable2.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003225 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003226 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003227 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003228 if (validatePrecision && variable1.precision != variable2.precision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003229 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003230 return LinkMismatchError::PRECISION_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003231 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003232 if (variable1.structName != variable2.structName)
Geoff Langbb1e7502017-06-05 16:40:09 -04003233 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003234 return LinkMismatchError::STRUCT_NAME_MISMATCH;
Geoff Langbb1e7502017-06-05 16:40:09 -04003235 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003236
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003237 if (variable1.fields.size() != variable2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05003238 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003239 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003240 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003241 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05003242 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
3243 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003244 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
3245 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05003246
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003247 if (member1.name != member2.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003248 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003249 return LinkMismatchError::FIELD_NAME_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003250 }
3251
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003252 LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08003253 member1, member2, validatePrecision, true, mismatchedStructOrBlockMemberName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003254 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003255 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003256 AddParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
3257 return linkErrorOnField;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003258 }
3259 }
3260
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003261 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003262}
3263
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003264LinkMismatchError Program::LinkValidateVaryings(const sh::Varying &outputVarying,
3265 const sh::Varying &inputVarying,
3266 int shaderVersion,
Jiawei Shaod063aff2018-02-22 10:19:09 +08003267 bool validateGeometryShaderInputVarying,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003268 std::string *mismatchedStructFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003269{
Jiawei Shaod063aff2018-02-22 10:19:09 +08003270 if (validateGeometryShaderInputVarying)
3271 {
3272 // [GL_EXT_geometry_shader] Section 11.1gs.4.3:
3273 // The OpenGL ES Shading Language doesn't support multi-dimensional arrays as shader inputs
3274 // or outputs.
3275 ASSERT(inputVarying.arraySizes.size() == 1u);
3276
3277 // Geometry shader input varyings are not treated as arrays, so a vertex array output
3278 // varying cannot match a geometry shader input varying.
3279 // [GL_EXT_geometry_shader] Section 7.4.1:
3280 // Geometry shader per-vertex input variables and blocks are required to be declared as
3281 // arrays, with each element representing input or output values for a single vertex of a
3282 // multi-vertex primitive. For the purposes of interface matching, such variables and blocks
3283 // are treated as though they were not declared as arrays.
3284 if (outputVarying.isArray())
3285 {
3286 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
3287 }
3288 }
3289
3290 // Skip the validation on the array sizes between a vertex output varying and a geometry input
3291 // varying as it has been done before.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003292 LinkMismatchError linkError =
Jiawei Shaod063aff2018-02-22 10:19:09 +08003293 LinkValidateVariablesBase(outputVarying, inputVarying, false,
3294 !validateGeometryShaderInputVarying, mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003295 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003296 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003297 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003298 }
3299
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003300 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05003301 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003302 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
Yuly Novikova1f6dc92016-06-15 23:27:04 -04003303 }
3304
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003305 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
Yuly Novikova1f6dc92016-06-15 23:27:04 -04003306 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003307 return LinkMismatchError::INVARIANCE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003308 }
3309
Jiawei Shao881b7bf2017-12-25 11:18:37 +08003310 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05003311}
3312
jchen103fd614d2018-08-13 12:21:58 +08003313bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05003314{
Jiawei Shao016105b2018-04-12 16:38:31 +08003315 Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
3316 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
jchen103fd614d2018-08-13 12:21:58 +08003317 const auto &vertexVaryings = vertexShader->getOutputVaryings();
3318 const auto &fragmentVaryings = fragmentShader->getInputVaryings();
3319 int shaderVersion = vertexShader->getShaderVersion();
Yuly Novikov817232e2017-02-22 18:36:10 -05003320
3321 if (shaderVersion != 100)
3322 {
3323 // Only ESSL 1.0 has restrictions on matching input and output invariance
3324 return true;
3325 }
3326
3327 bool glPositionIsInvariant = false;
3328 bool glPointSizeIsInvariant = false;
3329 bool glFragCoordIsInvariant = false;
3330 bool glPointCoordIsInvariant = false;
3331
3332 for (const sh::Varying &varying : vertexVaryings)
3333 {
3334 if (!varying.isBuiltIn())
3335 {
3336 continue;
3337 }
3338 if (varying.name.compare("gl_Position") == 0)
3339 {
3340 glPositionIsInvariant = varying.isInvariant;
3341 }
3342 else if (varying.name.compare("gl_PointSize") == 0)
3343 {
3344 glPointSizeIsInvariant = varying.isInvariant;
3345 }
3346 }
3347
3348 for (const sh::Varying &varying : fragmentVaryings)
3349 {
3350 if (!varying.isBuiltIn())
3351 {
3352 continue;
3353 }
3354 if (varying.name.compare("gl_FragCoord") == 0)
3355 {
3356 glFragCoordIsInvariant = varying.isInvariant;
3357 }
3358 else if (varying.name.compare("gl_PointCoord") == 0)
3359 {
3360 glPointCoordIsInvariant = varying.isInvariant;
3361 }
3362 }
3363
3364 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
3365 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
3366 // Not requiring invariance to match is supported by:
3367 // dEQP, WebGL CTS, Nexus 5X GLES
3368 if (glFragCoordIsInvariant && !glPositionIsInvariant)
3369 {
3370 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
3371 "declared invariant.";
3372 return false;
3373 }
3374 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
3375 {
3376 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
3377 "declared invariant.";
3378 return false;
3379 }
3380
3381 return true;
3382}
3383
jchen103fd614d2018-08-13 12:21:58 +08003384bool Program::linkValidateTransformFeedback(const Version &version,
jchen10a9042d32017-03-17 08:50:45 +08003385 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05003386 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04003387 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05003388{
Geoff Lang7dd2e102014-11-10 15:19:26 -05003389
jchen108225e732017-11-14 16:29:03 +08003390 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04003391 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04003392 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05003393 {
jchen103fd614d2018-08-13 12:21:58 +08003394 if (version < Version(3, 1) && tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04003395 {
Geoff Lang1a683462015-09-29 15:09:59 -04003396 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04003397 return false;
3398 }
jchen103fd614d2018-08-13 12:21:58 +08003399 if (version >= Version(3, 1))
jchen108225e732017-11-14 16:29:03 +08003400 {
3401 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
3402 {
3403 infoLog << "Two transform feedback varyings include the same array element ("
3404 << tfVaryingName << ").";
3405 return false;
3406 }
3407 }
3408 else
3409 {
3410 if (uniqueNames.count(tfVaryingName) > 0)
3411 {
3412 infoLog << "Two transform feedback varyings specify the same output variable ("
3413 << tfVaryingName << ").";
3414 return false;
3415 }
3416 }
3417 uniqueNames.insert(tfVaryingName);
3418 }
3419
3420 // Validate against program varyings.
3421 size_t totalComponents = 0;
3422 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
3423 {
3424 std::vector<unsigned int> subscripts;
3425 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
3426
3427 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
3428 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08003429 {
3430 infoLog << "Transform feedback varying " << tfVaryingName
3431 << " does not exist in the vertex shader.";
3432 return false;
3433 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003434
jchen108225e732017-11-14 16:29:03 +08003435 // Validate the matching variable.
3436 if (var->isStruct())
3437 {
3438 infoLog << "Struct cannot be captured directly (" << baseName << ").";
3439 return false;
3440 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003441
jchen108225e732017-11-14 16:29:03 +08003442 size_t elementCount = 0;
3443 size_t componentCount = 0;
3444
3445 if (var->isArray())
3446 {
jchen103fd614d2018-08-13 12:21:58 +08003447 if (version < Version(3, 1))
jchen108225e732017-11-14 16:29:03 +08003448 {
3449 infoLog << "Capture of arrays is undefined and not supported.";
3450 return false;
3451 }
3452
3453 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
3454 ASSERT(!var->isArrayOfArrays());
3455
3456 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
3457 {
3458 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
3459 return false;
3460 }
3461 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
3462 }
3463 else
3464 {
3465 if (!subscripts.empty())
3466 {
3467 infoLog << "Varying '" << baseName
3468 << "' is not an array to be captured by element.";
3469 return false;
3470 }
3471 elementCount = 1;
3472 }
3473
3474 // TODO(jmadill): Investigate implementation limits on D3D11
3475 componentCount = VariableComponentCount(var->type) * elementCount;
3476 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
3477 componentCount > caps.maxTransformFeedbackSeparateComponents)
3478 {
3479 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
3480 << componentCount << ") exceed the maximum separate components ("
3481 << caps.maxTransformFeedbackSeparateComponents << ").";
3482 return false;
3483 }
3484
3485 totalComponents += componentCount;
3486 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
3487 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
3488 {
3489 infoLog << "Transform feedback varying total components (" << totalComponents
3490 << ") exceed the maximum interleaved components ("
3491 << caps.maxTransformFeedbackInterleavedComponents << ").";
3492 return false;
3493 }
3494 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003495 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05003496}
3497
jchen103fd614d2018-08-13 12:21:58 +08003498bool Program::linkValidateGlobalNames(InfoLog &infoLog) const
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003499{
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003500 const std::vector<sh::Attribute> &attributes =
jchen103fd614d2018-08-13 12:21:58 +08003501 mState.mAttachedShaders[ShaderType::Vertex]->getActiveAttributes();
Jiawei Shao016105b2018-04-12 16:38:31 +08003502
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003503 for (const auto &attrib : attributes)
3504 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003505 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003506 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003507 Shader *shader = mState.mAttachedShaders[shaderType];
3508 if (!shader)
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003509 {
Jiawei Shao016105b2018-04-12 16:38:31 +08003510 continue;
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003511 }
Jiawei Shao016105b2018-04-12 16:38:31 +08003512
jchen103fd614d2018-08-13 12:21:58 +08003513 const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
Jiawei Shao016105b2018-04-12 16:38:31 +08003514 for (const auto &uniform : uniforms)
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003515 {
3516 if (uniform.name == attrib.name)
3517 {
3518 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3519 return false;
3520 }
3521 }
3522 }
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003523 }
Jiawei Shao016105b2018-04-12 16:38:31 +08003524
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003525 return true;
3526}
3527
Jamie Madill3c1da042017-11-27 18:33:40 -05003528void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003529{
3530 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08003531 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04003532 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003533 {
Olli Etuahoc8538042017-09-27 11:20:15 +03003534 std::vector<unsigned int> subscripts;
3535 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08003536 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03003537 if (!subscripts.empty())
3538 {
3539 subscript = subscripts.back();
3540 }
Jamie Madill192745a2016-12-22 15:58:21 -05003541 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003542 {
Jamie Madill192745a2016-12-22 15:58:21 -05003543 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08003544 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003545 {
jchen10a9042d32017-03-17 08:50:45 +08003546 mState.mLinkedTransformFeedbackVaryings.emplace_back(
3547 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04003548 break;
3549 }
jchen108225e732017-11-14 16:29:03 +08003550 else if (varying->isStruct())
3551 {
3552 const auto *field = FindShaderVarField(*varying, tfVaryingName);
3553 if (field != nullptr)
3554 {
3555 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
3556 break;
3557 }
3558 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04003559 }
3560 }
James Darpinian30b604d2018-03-12 17:26:57 -07003561 mState.updateTransformFeedbackStrides();
Jamie Madillccdf74b2015-08-18 10:46:12 -04003562}
3563
jchen103fd614d2018-08-13 12:21:58 +08003564ProgramMergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04003565{
Jamie Madill3c1da042017-11-27 18:33:40 -05003566 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003567
Jiawei Shao016105b2018-04-12 16:38:31 +08003568 for (const sh::Varying &varying :
jchen103fd614d2018-08-13 12:21:58 +08003569 mState.mAttachedShaders[ShaderType::Vertex]->getOutputVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04003570 {
Jamie Madill192745a2016-12-22 15:58:21 -05003571 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003572 }
3573
Jiawei Shao016105b2018-04-12 16:38:31 +08003574 for (const sh::Varying &varying :
jchen103fd614d2018-08-13 12:21:58 +08003575 mState.mAttachedShaders[ShaderType::Fragment]->getInputVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04003576 {
Jamie Madill192745a2016-12-22 15:58:21 -05003577 merged[varying.name].fragment = &varying;
3578 }
3579
3580 return merged;
3581}
3582
Olli Etuaho0ca09752018-09-24 11:00:50 +03003583bool CompareOutputVariable(const sh::OutputVariable &a, const sh::OutputVariable &b)
3584{
3585 return a.getArraySizeProduct() > b.getArraySizeProduct();
3586}
3587
3588int Program::getOutputLocationForLink(const sh::OutputVariable &outputVariable) const
3589{
3590 if (outputVariable.location != -1)
3591 {
3592 return outputVariable.location;
3593 }
3594 int apiLocation = mFragmentOutputLocations.getBinding(outputVariable.name);
3595 if (apiLocation != -1)
3596 {
3597 return apiLocation;
3598 }
3599 return -1;
3600}
3601
3602bool Program::isOutputSecondaryForLink(const sh::OutputVariable &outputVariable) const
3603{
3604 if (outputVariable.index != -1)
3605 {
3606 ASSERT(outputVariable.index == 0 || outputVariable.index == 1);
3607 return (outputVariable.index == 1);
3608 }
3609 int apiIndex = mFragmentOutputIndexes.getBinding(outputVariable.name);
3610 if (apiIndex != -1)
3611 {
3612 // Index layout qualifier from the shader takes precedence, so the index from the API is
3613 // checked only if the index was not set in the shader. This is not specified in the EXT
3614 // spec, but is specified in desktop OpenGL specs.
3615 return (apiIndex == 1);
3616 }
3617 // EXT_blend_func_extended: Outputs get index 0 by default.
3618 return false;
3619}
3620
jchen103fd614d2018-08-13 12:21:58 +08003621bool Program::linkOutputVariables(const Caps &caps,
Olli Etuaho0ca09752018-09-24 11:00:50 +03003622 const Extensions &extensions,
jchen103fd614d2018-08-13 12:21:58 +08003623 const Version &version,
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003624 GLuint combinedImageUniformsCount,
3625 GLuint combinedShaderStorageBlocksCount)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003626{
Jiawei Shao016105b2018-04-12 16:38:31 +08003627 Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003628 ASSERT(fragmentShader != nullptr);
3629
Geoff Lange0cff192017-05-30 13:04:56 -04003630 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04003631 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08003632 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04003633
jchen103fd614d2018-08-13 12:21:58 +08003634 const auto &outputVariables = fragmentShader->getActiveOutputVariables();
Geoff Lange0cff192017-05-30 13:04:56 -04003635 // Gather output variable types
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003636 for (const auto &outputVariable : outputVariables)
Geoff Lange0cff192017-05-30 13:04:56 -04003637 {
3638 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
3639 outputVariable.name != "gl_FragData")
3640 {
3641 continue;
3642 }
3643
3644 unsigned int baseLocation =
3645 (outputVariable.location == -1 ? 0u
3646 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03003647
3648 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3649 // structures, so we may use getBasicTypeElementCount().
3650 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3651 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04003652 {
3653 const unsigned int location = baseLocation + elementIndex;
3654 if (location >= mState.mOutputVariableTypes.size())
3655 {
3656 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
3657 }
Corentin Walleze7557742017-06-01 13:09:57 -04003658 ASSERT(location < mState.mActiveOutputVariables.size());
3659 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04003660 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08003661 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04003662 }
3663 }
3664
jchen103fd614d2018-08-13 12:21:58 +08003665 if (version >= ES_3_1)
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003666 {
3667 // [OpenGL ES 3.1] Chapter 8.22 Page 203:
3668 // A link error will be generated if the sum of the number of active image uniforms used in
3669 // all shaders, the number of active shader storage blocks, and the number of active
3670 // fragment shader outputs exceeds the implementation-dependent value of
3671 // MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
3672 if (combinedImageUniformsCount + combinedShaderStorageBlocksCount +
3673 mState.mActiveOutputVariables.count() >
jchen103fd614d2018-08-13 12:21:58 +08003674 caps.maxCombinedShaderOutputResources)
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003675 {
3676 mInfoLog
3677 << "The sum of the number of active image uniforms, active shader storage blocks "
3678 "and active fragment shader outputs exceeds "
3679 "MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
jchen103fd614d2018-08-13 12:21:58 +08003680 << caps.maxCombinedShaderOutputResources << ")";
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003681 return false;
3682 }
3683 }
3684
Jamie Madill80a6fc02015-08-21 16:53:16 -04003685 // Skip this step for GLES2 shaders.
jchen103fd614d2018-08-13 12:21:58 +08003686 if (fragmentShader->getShaderVersion() == 100)
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003687 return true;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003688
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003689 mState.mOutputVariables = outputVariables;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003690 // TODO(jmadill): any caps validation here?
3691
Olli Etuaho0ca09752018-09-24 11:00:50 +03003692 for (sh::OutputVariable &outputVariable : mState.mOutputVariables)
3693 {
3694 if (outputVariable.isArray())
3695 {
3696 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
3697 // Resources and including [0] at the end of array variable names.
3698 outputVariable.name += "[0]";
3699 outputVariable.mappedName += "[0]";
3700 }
3701 }
3702
3703 bool hasSecondaryOutputs = false;
3704
3705 // Reserve locations for output variables whose location is fixed in the shader or through the
3706 // API.
jchen1015015f72017-03-16 13:54:21 +08003707 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04003708 outputVariableIndex++)
3709 {
jchen1015015f72017-03-16 13:54:21 +08003710 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003711
3712 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3713 if (outputVariable.isBuiltIn())
3714 continue;
3715
Olli Etuaho0ca09752018-09-24 11:00:50 +03003716 int baseLocation = getOutputLocationForLink(outputVariable);
3717 if (baseLocation == -1)
3718 {
3719 // Here we're only reserving locations for variables whose location is fixed.
3720 continue;
3721 }
3722
3723 auto *outputLocations = &mState.mOutputLocations;
3724 if (isOutputSecondaryForLink(outputVariable))
3725 {
3726 outputLocations = &mState.mSecondaryOutputLocations;
3727 // Note that this check doesn't need to be before checking baseLocation == -1 above. If
3728 // an output has an index specified it will always also have the location specified.
3729 hasSecondaryOutputs = true;
3730 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003731
Olli Etuaho465835d2017-09-26 13:34:10 +03003732 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3733 // structures, so we may use getBasicTypeElementCount().
3734 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
Olli Etuaho0ca09752018-09-24 11:00:50 +03003735 unsigned int outputLocationsNeeded = static_cast<unsigned int>(baseLocation) + elementCount;
3736 if (outputLocationsNeeded > outputLocations->size())
3737 {
3738 outputLocations->resize(outputLocationsNeeded);
3739 }
Olli Etuaho465835d2017-09-26 13:34:10 +03003740 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003741 {
Olli Etuaho0ca09752018-09-24 11:00:50 +03003742 const unsigned int location = static_cast<unsigned int>(baseLocation) + elementIndex;
3743 ASSERT(location < outputLocations->size());
3744 if (outputLocations->at(location).used())
Olli Etuahod2551232017-10-26 20:03:33 +03003745 {
Olli Etuaho0ca09752018-09-24 11:00:50 +03003746 mInfoLog << "Location of variable " << outputVariable.name
3747 << " conflicts with another variable.";
3748 return false;
Olli Etuahod2551232017-10-26 20:03:33 +03003749 }
Olli Etuahoc8538042017-09-27 11:20:15 +03003750 if (outputVariable.isArray())
3751 {
Olli Etuaho0ca09752018-09-24 11:00:50 +03003752 (*outputLocations)[location] = VariableLocation(elementIndex, outputVariableIndex);
Olli Etuahoc8538042017-09-27 11:20:15 +03003753 }
3754 else
3755 {
3756 VariableLocation locationInfo;
3757 locationInfo.index = outputVariableIndex;
Olli Etuaho0ca09752018-09-24 11:00:50 +03003758 (*outputLocations)[location] = locationInfo;
3759 }
3760 }
3761 }
3762
3763 // Here we assign locations for the output variables that don't yet have them. Note that we're
3764 // not necessarily able to fit the variables optimally, since then we might have to try
3765 // different arrangements of output arrays. Now we just assign the locations in the order that
3766 // we got the output variables. The spec isn't clear on what kind of algorithm is required for
3767 // finding locations for the output variables, so this should be acceptable at least for now.
3768 GLuint maxLocation = caps.maxDrawBuffers;
3769 if (hasSecondaryOutputs)
3770 {
3771 // EXT_blend_func_extended: Program outputs will be validated against
3772 // MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT if there's even one output with index one.
3773 maxLocation = extensions.maxDualSourceDrawBuffers;
3774 }
3775
3776 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
3777 outputVariableIndex++)
3778 {
3779 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
3780
3781 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3782 if (outputVariable.isBuiltIn())
3783 continue;
3784
3785 if (getOutputLocationForLink(outputVariable) != -1)
3786 {
3787 continue;
3788 }
3789
3790 auto *outputLocations = &mState.mOutputLocations;
3791 if (isOutputSecondaryForLink(outputVariable))
3792 {
3793 outputLocations = &mState.mSecondaryOutputLocations;
3794 }
3795
3796 int baseLocation = 0;
3797 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3798 bool elementsFit = false;
3799 while (!elementsFit)
3800 {
3801 // Try baseLocations starting from 0 one at a time and see if the variable fits.
3802 elementsFit = true;
3803 if (baseLocation + elementCount > maxLocation)
3804 {
3805 // EXT_blend_func_extended: Linking can fail:
3806 // "if the explicit binding assignments do not leave enough space for the linker to
3807 // automatically assign a location for a varying out array, which requires multiple
3808 // contiguous locations."
3809 mInfoLog << "Could not fit output variable into available locations: "
3810 << outputVariable.name;
3811 return false;
3812 }
3813 unsigned int outputLocationsNeeded =
3814 static_cast<unsigned int>(baseLocation) + elementCount;
3815 if (outputLocationsNeeded > outputLocations->size())
3816 {
3817 outputLocations->resize(outputLocationsNeeded);
3818 }
3819 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
3820 {
3821 const unsigned int location =
3822 static_cast<unsigned int>(baseLocation) + elementIndex;
3823 ASSERT(location < outputLocations->size());
3824 if (outputLocations->at(location).used())
3825 {
3826 elementsFit = false;
3827 break;
3828 }
3829 }
3830 if (elementsFit)
3831 {
3832 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
3833 {
3834 const unsigned int location =
3835 static_cast<unsigned int>(baseLocation) + elementIndex;
3836 if (outputVariable.isArray())
3837 {
3838 (*outputLocations)[location] =
3839 VariableLocation(elementIndex, outputVariableIndex);
3840 }
3841 else
3842 {
3843 VariableLocation locationInfo;
3844 locationInfo.index = outputVariableIndex;
3845 (*outputLocations)[location] = locationInfo;
3846 }
3847 }
3848 }
3849 else
3850 {
3851 ++baseLocation;
Olli Etuahoc8538042017-09-27 11:20:15 +03003852 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003853 }
3854 }
Jiawei Shao7a8fe152018-04-28 12:59:58 +08003855
3856 return true;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003857}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003858
Olli Etuaho48fed632017-03-16 12:05:30 +00003859void Program::setUniformValuesFromBindingQualifiers()
3860{
Jamie Madill982f6e02017-06-07 14:33:04 -04003861 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003862 {
3863 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3864 if (samplerUniform.binding != -1)
3865 {
Olli Etuahod2551232017-10-26 20:03:33 +03003866 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003867 ASSERT(location != -1);
3868 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003869 for (unsigned int elementIndex = 0;
3870 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003871 {
3872 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3873 }
3874 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3875 boundTextureUnits.data());
3876 }
3877 }
3878}
3879
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003880void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003881{
jchen10af713a22017-04-19 09:10:56 +08003882 // Set initial bindings from shader.
3883 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3884 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003885 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003886 bindUniformBlock(blockIndex, uniformBlock.binding);
3887 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003888}
3889
Jamie Madille7d84322017-01-10 18:21:59 -05003890void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003891 GLsizei clampedCount,
3892 const GLint *v)
3893{
Jamie Madill81c2e252017-09-09 23:32:46 -04003894 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3895 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
Jamie Madill7e4eff12018-08-08 15:49:26 -04003896 SamplerBinding &samplerBinding = mState.mSamplerBindings[samplerIndex];
3897 std::vector<GLuint> &boundTextureUnits = samplerBinding.boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003898
Jamie Madill7e4eff12018-08-08 15:49:26 -04003899 if (samplerBinding.unreferenced)
3900 return;
3901
3902 // Update the sampler uniforms.
3903 for (GLsizei arrayIndex = 0; arrayIndex < clampedCount; ++arrayIndex)
3904 {
3905 GLint oldSamplerIndex = boundTextureUnits[arrayIndex + locationInfo.arrayIndex];
3906 GLint newSamplerIndex = v[arrayIndex];
3907
3908 if (oldSamplerIndex == newSamplerIndex)
3909 continue;
3910
3911 boundTextureUnits[arrayIndex + locationInfo.arrayIndex] = newSamplerIndex;
3912
3913 // Update the reference counts.
3914 uint32_t &oldRefCount = mState.mActiveSamplerRefCounts[oldSamplerIndex];
3915 uint32_t &newRefCount = mState.mActiveSamplerRefCounts[newSamplerIndex];
3916 ASSERT(oldRefCount > 0);
3917 ASSERT(newRefCount < std::numeric_limits<uint32_t>::max());
3918 oldRefCount--;
3919 newRefCount++;
3920
3921 // Check for binding type change.
3922 TextureType &newSamplerType = mState.mActiveSamplerTypes[newSamplerIndex];
3923 TextureType &oldSamplerType = mState.mActiveSamplerTypes[oldSamplerIndex];
3924
3925 if (newRefCount == 1)
3926 {
3927 newSamplerType = samplerBinding.textureType;
3928 mState.mActiveSamplersMask.set(newSamplerIndex);
3929 }
3930 else if (newSamplerType != samplerBinding.textureType)
3931 {
3932 // Conflict detected. Ensure we reset it properly.
3933 newSamplerType = TextureType::InvalidEnum;
3934 }
3935
3936 // Unset previously active sampler.
3937 if (oldRefCount == 0)
3938 {
3939 oldSamplerType = TextureType::InvalidEnum;
3940 mState.mActiveSamplersMask.reset(oldSamplerIndex);
3941 }
3942 else if (oldSamplerType == TextureType::InvalidEnum)
3943 {
3944 // Previous conflict. Check if this new change fixed the conflict.
3945 oldSamplerType = mState.getSamplerUniformTextureType(oldSamplerIndex);
3946 }
3947 }
Jamie Madilld68248b2017-09-11 14:34:14 -04003948
3949 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003950 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003951}
3952
Jamie Madill7e4eff12018-08-08 15:49:26 -04003953TextureType ProgramState::getSamplerUniformTextureType(size_t textureUnitIndex) const
3954{
3955 TextureType foundType = TextureType::InvalidEnum;
3956
3957 for (const SamplerBinding &binding : mSamplerBindings)
3958 {
3959 if (binding.unreferenced)
3960 continue;
3961
3962 // A conflict exists if samplers of different types are sourced by the same texture unit.
3963 // We need to check all bound textures to detect this error case.
3964 for (GLuint textureUnit : binding.boundTextureUnits)
3965 {
3966 if (textureUnit == textureUnitIndex)
3967 {
3968 if (foundType == TextureType::InvalidEnum)
3969 {
3970 foundType = binding.textureType;
3971 }
3972 else if (foundType != binding.textureType)
3973 {
3974 return TextureType::InvalidEnum;
3975 }
3976 }
3977 }
3978 }
3979
3980 return foundType;
3981}
3982
Jamie Madille7d84322017-01-10 18:21:59 -05003983template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003984GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3985 GLsizei count,
3986 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003987 const T *v)
3988{
Jamie Madill134f93d2017-08-31 17:11:00 -04003989 if (count == 1)
3990 return 1;
3991
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003992 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003993
Corentin Wallez15ac5342016-11-03 17:06:39 -04003994 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3995 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003996 unsigned int remainingElements =
3997 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003998 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003999 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05004000
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004001 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05004002 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004003 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04004004 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05004005
4006 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04004007}
4008
4009template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004010GLsizei Program::clampMatrixUniformCount(GLint location,
4011 GLsizei count,
4012 GLboolean transpose,
4013 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04004014{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004015 const VariableLocation &locationInfo = mState.mUniformLocations[location];
4016
Jamie Madill62d31cb2015-09-11 13:25:51 -04004017 if (!transpose)
4018 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004019 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04004020 }
4021
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004022 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04004023
4024 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
4025 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03004026 unsigned int remainingElements =
4027 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04004028 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04004029}
4030
Jamie Madill54164b02017-08-28 15:17:37 -04004031// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
4032// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04004033template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04004034void Program::getUniformInternal(const Context *context,
4035 DestT *dataOut,
4036 GLint location,
4037 GLenum nativeType,
4038 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04004039{
Jamie Madill54164b02017-08-28 15:17:37 -04004040 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04004041 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04004042 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04004043 {
4044 GLint tempValue[16] = {0};
4045 mProgram->getUniformiv(context, location, tempValue);
4046 UniformStateQueryCastLoop<GLboolean>(
4047 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04004048 break;
Jamie Madill54164b02017-08-28 15:17:37 -04004049 }
4050 case GL_INT:
4051 {
4052 GLint tempValue[16] = {0};
4053 mProgram->getUniformiv(context, location, tempValue);
4054 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
4055 components);
4056 break;
4057 }
4058 case GL_UNSIGNED_INT:
4059 {
4060 GLuint tempValue[16] = {0};
4061 mProgram->getUniformuiv(context, location, tempValue);
4062 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
4063 components);
4064 break;
4065 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04004066 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04004067 {
4068 GLfloat tempValue[16] = {0};
4069 mProgram->getUniformfv(context, location, tempValue);
4070 UniformStateQueryCastLoop<GLfloat>(
4071 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04004072 break;
Jamie Madill54164b02017-08-28 15:17:37 -04004073 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04004074 default:
4075 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04004076 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04004077 }
4078}
Jamie Madilla4595b82017-01-11 17:36:34 -05004079
4080bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
4081{
Jamie Madill44a6fbf2018-10-02 13:38:56 -04004082 ASSERT(mLinkResolved);
Jamie Madilla4595b82017-01-11 17:36:34 -05004083 // Must be called after samplers are validated.
4084 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
4085
4086 for (const auto &binding : mState.mSamplerBindings)
4087 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -08004088 TextureType textureType = binding.textureType;
Jamie Madilla4595b82017-01-11 17:36:34 -05004089 for (const auto &unit : binding.boundTextureUnits)
4090 {
4091 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
4092 if (programTextureID == textureID)
4093 {
4094 // TODO(jmadill): Check for appropriate overlap.
4095 return true;
4096 }
4097 }
4098 }
4099
4100 return false;
4101}
4102
Jamie Madill6f755b22018-10-09 12:48:54 -04004103angle::Result Program::syncState(const Context *context)
Jamie Madill70aeda42018-08-20 12:17:40 -04004104{
4105 if (mDirtyBits.any())
4106 {
Jamie Madill44a6fbf2018-10-02 13:38:56 -04004107 ASSERT(mLinkResolved);
Jamie Madill70aeda42018-08-20 12:17:40 -04004108 ANGLE_TRY(mProgram->syncState(context, mDirtyBits));
4109 mDirtyBits.reset();
4110 }
4111
Jamie Madill6f755b22018-10-09 12:48:54 -04004112 return angle::Result::Continue();
Jamie Madill70aeda42018-08-20 12:17:40 -04004113}
Jamie Madilla2c74982016-12-12 11:20:42 -05004114} // namespace gl