blob: 2b290021fef137f2ae9326f9729adccba205ff0a [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill20e005b2017-04-07 14:19:22 -040014#include "common/bitset_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
Olli Etuahod2551232017-10-26 20:03:33 +030017#include "common/string_utils.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050018#include "common/utilities.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050019#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021#include "libANGLE/MemoryProgramCache.h"
Jamie Madill7af0de52017-11-06 17:09:33 -050022#include "libANGLE/ProgramLinkedResources.h"
Jamie Madill437d2662014-12-05 14:23:35 -050023#include "libANGLE/ResourceManager.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040024#include "libANGLE/Uniform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040025#include "libANGLE/VaryingPacking.h"
26#include "libANGLE/features.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040027#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040028#include "libANGLE/queryconversions.h"
29#include "libANGLE/renderer/GLImplFactory.h"
30#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040031#include "platform/Platform.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050032
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033namespace gl
34{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000035
Geoff Lang7dd2e102014-11-10 15:19:26 -050036namespace
37{
38
Jamie Madill62d31cb2015-09-11 13:25:51 -040039// This simplified cast function doesn't need to worry about advanced concepts like
40// depth range values, or casting to bool.
41template <typename DestT, typename SrcT>
42DestT UniformStateQueryCast(SrcT value);
43
44// From-Float-To-Integer Casts
45template <>
46GLint UniformStateQueryCast(GLfloat value)
47{
48 return clampCast<GLint>(roundf(value));
49}
50
51template <>
52GLuint UniformStateQueryCast(GLfloat value)
53{
54 return clampCast<GLuint>(roundf(value));
55}
56
57// From-Integer-to-Integer Casts
58template <>
59GLint UniformStateQueryCast(GLuint value)
60{
61 return clampCast<GLint>(value);
62}
63
64template <>
65GLuint UniformStateQueryCast(GLint value)
66{
67 return clampCast<GLuint>(value);
68}
69
70// From-Boolean-to-Anything Casts
71template <>
72GLfloat UniformStateQueryCast(GLboolean value)
73{
Geoff Lang92019432017-11-20 13:09:34 -050074 return (ConvertToBool(value) ? 1.0f : 0.0f);
Jamie Madill62d31cb2015-09-11 13:25:51 -040075}
76
77template <>
78GLint UniformStateQueryCast(GLboolean value)
79{
Geoff Lang92019432017-11-20 13:09:34 -050080 return (ConvertToBool(value) ? 1 : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -040081}
82
83template <>
84GLuint UniformStateQueryCast(GLboolean value)
85{
Geoff Lang92019432017-11-20 13:09:34 -050086 return (ConvertToBool(value) ? 1u : 0u);
Jamie Madill62d31cb2015-09-11 13:25:51 -040087}
88
89// Default to static_cast
90template <typename DestT, typename SrcT>
91DestT UniformStateQueryCast(SrcT value)
92{
93 return static_cast<DestT>(value);
94}
95
96template <typename SrcT, typename DestT>
97void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
98{
99 for (int comp = 0; comp < components; ++comp)
100 {
101 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
102 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
103 size_t offset = comp * 4;
104 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
105 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
106 }
107}
108
jchen1015015f72017-03-16 13:54:21 +0800109template <typename VarT>
110GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
111{
Olli Etuahod2551232017-10-26 20:03:33 +0300112 std::string nameAsArrayName = name + "[0]";
jchen1015015f72017-03-16 13:54:21 +0800113 for (size_t index = 0; index < list.size(); index++)
114 {
115 const VarT &resource = list[index];
Olli Etuahod2551232017-10-26 20:03:33 +0300116 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
jchen1015015f72017-03-16 13:54:21 +0800117 {
Olli Etuahod2551232017-10-26 20:03:33 +0300118 return static_cast<GLuint>(index);
jchen1015015f72017-03-16 13:54:21 +0800119 }
120 }
121
122 return GL_INVALID_INDEX;
123}
124
Olli Etuahod2551232017-10-26 20:03:33 +0300125template <typename VarT>
126GLint GetVariableLocation(const std::vector<VarT> &list,
127 const std::vector<VariableLocation> &locationList,
128 const std::string &name)
129{
130 size_t nameLengthWithoutArrayIndex;
131 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
132
133 for (size_t location = 0u; location < locationList.size(); ++location)
134 {
135 const VariableLocation &variableLocation = locationList[location];
136 if (!variableLocation.used())
137 {
138 continue;
139 }
140
141 const VarT &variable = list[variableLocation.index];
142
143 if (angle::BeginsWith(variable.name, name))
144 {
145 if (name.length() == variable.name.length())
146 {
147 ASSERT(name == variable.name);
148 // GLES 3.1 November 2016 page 87.
149 // The string exactly matches the name of the active variable.
150 return static_cast<GLint>(location);
151 }
152 if (name.length() + 3u == variable.name.length() && variable.isArray())
153 {
154 ASSERT(name + "[0]" == variable.name);
155 // The string identifies the base name of an active array, where the string would
156 // exactly match the name of the variable if the suffix "[0]" were appended to the
157 // string.
158 return static_cast<GLint>(location);
159 }
160 }
Olli Etuaho1734e172017-10-27 15:30:27 +0300161 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
Olli Etuahod2551232017-10-26 20:03:33 +0300162 nameLengthWithoutArrayIndex + 3u == variable.name.length() &&
163 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
164 {
165 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name);
166 // The string identifies an active element of the array, where the string ends with the
167 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
168 // zeroes, or whitespace) identifying an array element, and the "]" character, the
169 // integer is less than the number of active elements of the array variable, and where
170 // the string would exactly match the enumerated name of the array if the decimal
171 // integer were replaced with zero.
172 return static_cast<GLint>(location);
173 }
174 }
175
176 return -1;
177}
178
jchen10fd7c3b52017-03-21 15:36:03 +0800179void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length)
180{
181 ASSERT(bufSize > 0);
182 strncpy(buffer, string.c_str(), bufSize);
183 buffer[bufSize - 1] = '\0';
184
185 if (length)
186 {
187 *length = static_cast<GLsizei>(strlen(buffer));
188 }
189}
190
jchen10a9042d32017-03-17 08:50:45 +0800191bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
192{
Olli Etuahoc8538042017-09-27 11:20:15 +0300193 std::vector<unsigned int> subscripts;
194 std::string baseName = ParseResourceName(name, &subscripts);
195 for (auto nameInSet : nameSet)
jchen10a9042d32017-03-17 08:50:45 +0800196 {
Olli Etuahoc8538042017-09-27 11:20:15 +0300197 std::vector<unsigned int> arrayIndices;
198 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
199 if (baseName == arrayName &&
200 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
jchen10a9042d32017-03-17 08:50:45 +0800201 {
202 return true;
203 }
204 }
205 return false;
206}
207
Jiajia Qin729b2c62017-08-14 09:36:11 +0800208bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
209 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
210 const std::string &errorMessage,
211 InfoLog &infoLog)
212{
213 GLuint blockCount = 0;
214 for (const sh::InterfaceBlock &block : interfaceBlocks)
215 {
216 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
217 {
218 blockCount += (block.arraySize ? block.arraySize : 1);
219 if (blockCount > maxInterfaceBlocks)
220 {
221 infoLog << errorMessage << maxInterfaceBlocks << ")";
222 return false;
223 }
224 }
225 }
226 return true;
227}
228
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800229GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
230{
231 std::vector<unsigned int> subscripts;
232 std::string baseName = ParseResourceName(name, &subscripts);
233
234 unsigned int numBlocks = static_cast<unsigned int>(list.size());
235 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
236 {
237 const auto &block = list[blockIndex];
238 if (block.name == baseName)
239 {
240 const bool arrayElementZero =
241 (subscripts.empty() && (!block.isArray || block.arrayElement == 0));
242 const bool arrayElementMatches =
243 (subscripts.size() == 1 && subscripts[0] == block.arrayElement);
244 if (arrayElementMatches || arrayElementZero)
245 {
246 return blockIndex;
247 }
248 }
249 }
250
251 return GL_INVALID_INDEX;
252}
253
254void GetInterfaceBlockName(const GLuint index,
255 const std::vector<InterfaceBlock> &list,
256 GLsizei bufSize,
257 GLsizei *length,
258 GLchar *name)
259{
260 ASSERT(index < list.size());
261
262 const auto &block = list[index];
263
264 if (bufSize > 0)
265 {
266 std::string blockName = block.name;
267
268 if (block.isArray)
269 {
270 blockName += ArrayString(block.arrayElement);
271 }
272 CopyStringToBuffer(name, blockName, bufSize, length);
273 }
274}
275
Jamie Madillc9727f32017-11-07 12:37:07 -0500276void InitUniformBlockLinker(const gl::Context *context,
277 const ProgramState &state,
278 UniformBlockLinker *blockLinker)
279{
280 if (state.getAttachedVertexShader())
281 {
282 blockLinker->addShaderBlocks(GL_VERTEX_SHADER,
283 &state.getAttachedVertexShader()->getUniformBlocks(context));
284 }
285
286 if (state.getAttachedFragmentShader())
287 {
288 blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER,
289 &state.getAttachedFragmentShader()->getUniformBlocks(context));
290 }
291
292 if (state.getAttachedComputeShader())
293 {
294 blockLinker->addShaderBlocks(GL_COMPUTE_SHADER,
295 &state.getAttachedComputeShader()->getUniformBlocks(context));
296 }
297}
298
299void InitShaderStorageBlockLinker(const gl::Context *context,
300 const ProgramState &state,
301 ShaderStorageBlockLinker *blockLinker)
302{
303 if (state.getAttachedVertexShader())
304 {
305 blockLinker->addShaderBlocks(
306 GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context));
307 }
308
309 if (state.getAttachedFragmentShader())
310 {
311 blockLinker->addShaderBlocks(
312 GL_FRAGMENT_SHADER,
313 &state.getAttachedFragmentShader()->getShaderStorageBlocks(context));
314 }
315
316 if (state.getAttachedComputeShader())
317 {
318 blockLinker->addShaderBlocks(
319 GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context));
320 }
321}
322
jchen108225e732017-11-14 16:29:03 +0800323// Find the matching varying or field by name.
324const sh::ShaderVariable *FindVaryingOrField(const ProgramMergedVaryings &varyings,
325 const std::string &name)
326{
327 const sh::ShaderVariable *var = nullptr;
328 for (const auto &ref : varyings)
329 {
330 const sh::Varying *varying = ref.second.get();
331 if (varying->name == name)
332 {
333 var = varying;
334 break;
335 }
336 var = FindShaderVarField(*varying, name);
337 if (var != nullptr)
338 {
339 break;
340 }
341 }
342 return var;
343}
344
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800345void AddParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
346{
347 ASSERT(mismatchedFieldName);
348 if (mismatchedFieldName->empty())
349 {
350 *mismatchedFieldName = parentName;
351 }
352 else
353 {
354 std::ostringstream stream;
355 stream << parentName << "." << *mismatchedFieldName;
356 *mismatchedFieldName = stream.str();
357 }
358}
359
360const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
361{
362 switch (linkError)
363 {
364 case LinkMismatchError::TYPE_MISMATCH:
365 return "Type";
366 case LinkMismatchError::ARRAY_SIZE_MISMATCH:
367 return "Array size";
368 case LinkMismatchError::PRECISION_MISMATCH:
369 return "Precision";
370 case LinkMismatchError::STRUCT_NAME_MISMATCH:
371 return "Structure name";
372 case LinkMismatchError::FIELD_NUMBER_MISMATCH:
373 return "Field number";
374 case LinkMismatchError::FIELD_NAME_MISMATCH:
375 return "Field name";
376
377 case LinkMismatchError::INTERPOLATION_TYPE_MISMATCH:
378 return "Interpolation type";
379 case LinkMismatchError::INVARIANCE_MISMATCH:
380 return "Invariance";
381
382 case LinkMismatchError::BINDING_MISMATCH:
383 return "Binding layout qualifier";
384 case LinkMismatchError::LOCATION_MISMATCH:
385 return "Location layout qualifier";
386 case LinkMismatchError::OFFSET_MISMATCH:
387 return "Offset layout qualilfier";
388
389 case LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH:
390 return "Layout qualifier";
391 case LinkMismatchError::MATRIX_PACKING_MISMATCH:
392 return "Matrix Packing";
393 default:
394 UNREACHABLE();
395 return "";
396 }
397}
398
Jamie Madill62d31cb2015-09-11 13:25:51 -0400399} // anonymous namespace
400
Jamie Madill4a3c2342015-10-08 12:58:45 -0400401const char *const g_fakepath = "C:\\fakepath";
402
Jamie Madill3c1da042017-11-27 18:33:40 -0500403// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400404InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000405{
406}
407
408InfoLog::~InfoLog()
409{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000410}
411
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400412size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000413{
Jamie Madill23176ce2017-07-31 14:14:33 -0400414 if (!mLazyStream)
415 {
416 return 0;
417 }
418
419 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400420 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000421}
422
Geoff Lange1a27752015-10-05 13:16:04 -0400423void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000424{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400425 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000426
427 if (bufSize > 0)
428 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400429 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400430
Jamie Madill23176ce2017-07-31 14:14:33 -0400431 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000432 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400433 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
434 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000435 }
436
437 infoLog[index] = '\0';
438 }
439
440 if (length)
441 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400442 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000443 }
444}
445
446// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300447// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000448// messages, so lets remove all occurrences of this fake file path from the log.
449void InfoLog::appendSanitized(const char *message)
450{
Jamie Madill23176ce2017-07-31 14:14:33 -0400451 ensureInitialized();
452
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000453 std::string msg(message);
454
455 size_t found;
456 do
457 {
458 found = msg.find(g_fakepath);
459 if (found != std::string::npos)
460 {
461 msg.erase(found, strlen(g_fakepath));
462 }
463 }
464 while (found != std::string::npos);
465
Jamie Madill23176ce2017-07-31 14:14:33 -0400466 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000467}
468
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000469void InfoLog::reset()
470{
Jiawei Shao02f15232017-12-27 10:10:28 +0800471 if (mLazyStream)
472 {
473 mLazyStream.reset(nullptr);
474 }
475}
476
477bool InfoLog::empty() const
478{
479 if (!mLazyStream)
480 {
481 return true;
482 }
483
484 return mLazyStream->rdbuf()->in_avail() == 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000485}
486
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800487void LogLinkMismatch(InfoLog &infoLog,
488 const std::string &variableName,
489 const char *variableType,
490 LinkMismatchError linkError,
491 const std::string &mismatchedStructOrBlockFieldName,
492 GLenum shaderType1,
493 GLenum shaderType2)
494{
495 std::ostringstream stream;
496 stream << GetLinkMismatchErrorString(linkError) << "s of " << variableType << " '"
497 << variableName;
498
499 if (!mismatchedStructOrBlockFieldName.empty())
500 {
501 stream << "' member '" << variableName << "." << mismatchedStructOrBlockFieldName;
502 }
503
504 stream << "' differ between " << GetShaderTypeString(shaderType1) << " and "
505 << GetShaderTypeString(shaderType2) << " shaders.";
506
507 infoLog << stream.str();
508}
509
Jamie Madill3c1da042017-11-27 18:33:40 -0500510// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300511VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000512{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500513}
514
Olli Etuahoc8538042017-09-27 11:20:15 +0300515VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300516 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500517{
Olli Etuahoc8538042017-09-27 11:20:15 +0300518 ASSERT(arrayIndex != GL_INVALID_INDEX);
519}
520
Jamie Madill3c1da042017-11-27 18:33:40 -0500521// SamplerBindings implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500522SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced)
523 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
524{
525}
526
527SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
528
529SamplerBinding::~SamplerBinding() = default;
530
Jamie Madill3c1da042017-11-27 18:33:40 -0500531// ProgramBindings implementation.
532ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500533{
534}
535
Jamie Madill3c1da042017-11-27 18:33:40 -0500536ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500537{
538}
539
Jamie Madill3c1da042017-11-27 18:33:40 -0500540void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400541{
542 mBindings[name] = index;
543}
544
Jamie Madill3c1da042017-11-27 18:33:40 -0500545int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400546{
547 auto iter = mBindings.find(name);
548 return (iter != mBindings.end()) ? iter->second : -1;
549}
550
Jamie Madill3c1da042017-11-27 18:33:40 -0500551ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400552{
553 return mBindings.begin();
554}
555
Jamie Madill3c1da042017-11-27 18:33:40 -0500556ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400557{
558 return mBindings.end();
559}
560
Jamie Madill3c1da042017-11-27 18:33:40 -0500561// ImageBinding implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500562ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
563{
564}
565ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
566{
567 for (size_t index = 0; index < count; ++index)
568 {
569 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
570 }
571}
572
573ImageBinding::ImageBinding(const ImageBinding &other) = default;
574
575ImageBinding::~ImageBinding() = default;
576
Jamie Madill3c1da042017-11-27 18:33:40 -0500577// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400578ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500579 : mLabel(),
580 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400581 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300582 mAttachedComputeShader(nullptr),
Jiawei Shao89be29a2017-11-06 14:36:45 +0800583 mAttachedGeometryShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500584 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400585 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500586 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800587 mImageUniformRange(0, 0),
588 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300589 mBinaryRetrieveableHint(false),
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800590 mNumViews(-1),
591 // [GL_EXT_geometry_shader] Table 20.22
592 mGeometryShaderInputPrimitiveType(GL_TRIANGLES),
593 mGeometryShaderOutputPrimitiveType(GL_TRIANGLE_STRIP),
594 mGeometryShaderInvocations(1),
595 mGeometryShaderMaxVertices(0)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400596{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300597 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400598}
599
Jamie Madill48ef11b2016-04-27 15:21:52 -0400600ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400601{
Jiawei Shao89be29a2017-11-06 14:36:45 +0800602 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader &&
603 !mAttachedGeometryShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400604}
605
Jamie Madill48ef11b2016-04-27 15:21:52 -0400606const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500607{
608 return mLabel;
609}
610
Jamie Madille7d84322017-01-10 18:21:59 -0500611GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400612{
jchen1015015f72017-03-16 13:54:21 +0800613 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400614}
615
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800616GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
617{
618 return GetResourceIndexFromName(mBufferVariables, name);
619}
620
Jamie Madille7d84322017-01-10 18:21:59 -0500621GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
622{
623 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
624 return mUniformLocations[location].index;
625}
626
627Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
628{
629 GLuint index = getUniformIndexFromLocation(location);
630 if (!isSamplerUniformIndex(index))
631 {
632 return Optional<GLuint>::Invalid();
633 }
634
635 return getSamplerIndexFromUniformIndex(index);
636}
637
638bool ProgramState::isSamplerUniformIndex(GLuint index) const
639{
Jamie Madill982f6e02017-06-07 14:33:04 -0400640 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500641}
642
643GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
644{
645 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400646 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500647}
648
Jamie Madill34ca4f52017-06-13 11:49:39 -0400649GLuint ProgramState::getAttributeLocation(const std::string &name) const
650{
651 for (const sh::Attribute &attribute : mAttributes)
652 {
653 if (attribute.name == name)
654 {
655 return attribute.location;
656 }
657 }
658
659 return static_cast<GLuint>(-1);
660}
661
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500662Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400663 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400664 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500665 mLinked(false),
666 mDeleteStatus(false),
667 mRefCount(0),
668 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500669 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500670{
671 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000672
Geoff Lang7dd2e102014-11-10 15:19:26 -0500673 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000674}
675
676Program::~Program()
677{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400678 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679}
680
Jamie Madill4928b7c2017-06-20 12:57:39 -0400681void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500682{
683 if (mState.mAttachedVertexShader != nullptr)
684 {
685 mState.mAttachedVertexShader->release(context);
686 mState.mAttachedVertexShader = nullptr;
687 }
688
689 if (mState.mAttachedFragmentShader != nullptr)
690 {
691 mState.mAttachedFragmentShader->release(context);
692 mState.mAttachedFragmentShader = nullptr;
693 }
694
695 if (mState.mAttachedComputeShader != nullptr)
696 {
697 mState.mAttachedComputeShader->release(context);
698 mState.mAttachedComputeShader = nullptr;
699 }
700
Jiawei Shao89be29a2017-11-06 14:36:45 +0800701 if (mState.mAttachedGeometryShader != nullptr)
702 {
703 mState.mAttachedGeometryShader->release(context);
704 mState.mAttachedGeometryShader = nullptr;
705 }
706
Jamie Madillc564c072017-06-01 12:45:42 -0400707 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400708
709 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800710 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400711 SafeDelete(mProgram);
712
713 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500714}
715
Geoff Lang70d0f492015-12-10 17:45:46 -0500716void Program::setLabel(const std::string &label)
717{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400718 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500719}
720
721const std::string &Program::getLabel() const
722{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400723 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500724}
725
Jamie Madillef300b12016-10-07 15:12:09 -0400726void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300728 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000729 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300730 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731 {
Jamie Madillef300b12016-10-07 15:12:09 -0400732 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300733 mState.mAttachedVertexShader = shader;
734 mState.mAttachedVertexShader->addRef();
735 break;
736 }
737 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738 {
Jamie Madillef300b12016-10-07 15:12:09 -0400739 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300740 mState.mAttachedFragmentShader = shader;
741 mState.mAttachedFragmentShader->addRef();
742 break;
743 }
744 case GL_COMPUTE_SHADER:
745 {
Jamie Madillef300b12016-10-07 15:12:09 -0400746 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300747 mState.mAttachedComputeShader = shader;
748 mState.mAttachedComputeShader->addRef();
749 break;
750 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800751 case GL_GEOMETRY_SHADER_EXT:
752 {
753 ASSERT(!mState.mAttachedGeometryShader);
754 mState.mAttachedGeometryShader = shader;
755 mState.mAttachedGeometryShader->addRef();
756 break;
757 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300758 default:
759 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000760 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761}
762
Jamie Madillc1d770e2017-04-13 17:31:24 -0400763void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300765 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300767 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400769 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500770 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300771 mState.mAttachedVertexShader = nullptr;
772 break;
773 }
774 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000775 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400776 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500777 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300778 mState.mAttachedFragmentShader = nullptr;
779 break;
780 }
781 case GL_COMPUTE_SHADER:
782 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400783 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500784 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300785 mState.mAttachedComputeShader = nullptr;
786 break;
787 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800788 case GL_GEOMETRY_SHADER_EXT:
789 {
790 ASSERT(mState.mAttachedGeometryShader == shader);
791 shader->release(context);
792 mState.mAttachedGeometryShader = nullptr;
793 break;
794 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300795 default:
796 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798}
799
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000800int Program::getAttachedShadersCount() const
801{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300802 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800803 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000804}
805
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806void Program::bindAttributeLocation(GLuint index, const char *name)
807{
Geoff Langd8605522016-04-13 10:19:12 -0400808 mAttributeBindings.bindLocation(index, name);
809}
810
811void Program::bindUniformLocation(GLuint index, const char *name)
812{
Olli Etuahod2551232017-10-26 20:03:33 +0300813 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814}
815
Sami Väisänen46eaa942016-06-29 10:26:37 +0300816void Program::bindFragmentInputLocation(GLint index, const char *name)
817{
818 mFragmentInputBindings.bindLocation(index, name);
819}
820
Jamie Madillbd044ed2017-06-05 12:59:21 -0400821BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300822{
823 BindingInfo ret;
824 ret.type = GL_NONE;
825 ret.valid = false;
826
Jamie Madillbd044ed2017-06-05 12:59:21 -0400827 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300828 ASSERT(fragmentShader);
829
830 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800831 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300832
833 for (const auto &binding : mFragmentInputBindings)
834 {
835 if (binding.second != static_cast<GLuint>(index))
836 continue;
837
838 ret.valid = true;
839
Olli Etuahod2551232017-10-26 20:03:33 +0300840 size_t nameLengthWithoutArrayIndex;
841 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300842
843 for (const auto &in : inputs)
844 {
Olli Etuahod2551232017-10-26 20:03:33 +0300845 if (in.name.length() == nameLengthWithoutArrayIndex &&
846 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300847 {
848 if (in.isArray())
849 {
850 // The client wants to bind either "name" or "name[0]".
851 // GL ES 3.1 spec refers to active array names with language such as:
852 // "if the string identifies the base name of an active array, where the
853 // string would exactly match the name of the variable if the suffix "[0]"
854 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400855 if (arrayIndex == GL_INVALID_INDEX)
856 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300857
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400858 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300859 }
860 else
861 {
862 ret.name = in.mappedName;
863 }
864 ret.type = in.type;
865 return ret;
866 }
867 }
868 }
869
870 return ret;
871}
872
Jamie Madillbd044ed2017-06-05 12:59:21 -0400873void Program::pathFragmentInputGen(const Context *context,
874 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300875 GLenum genMode,
876 GLint components,
877 const GLfloat *coeffs)
878{
879 // If the location is -1 then the command is silently ignored
880 if (index == -1)
881 return;
882
Jamie Madillbd044ed2017-06-05 12:59:21 -0400883 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300884
885 // If the input doesn't exist then then the command is silently ignored
886 // This could happen through optimization for example, the shader translator
887 // decides that a variable is not actually being used and optimizes it away.
888 if (binding.name.empty())
889 return;
890
891 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
892}
893
Martin Radev4c4c8e72016-08-04 12:25:34 +0300894// The attached shaders are checked for linking errors by matching up their variables.
895// Uniform, input and output variables get collected.
896// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500897Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000898{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500899 const auto &data = context->getContextState();
900
Jamie Madill6c58b062017-08-01 13:44:25 -0400901 auto *platform = ANGLEPlatformCurrent();
902 double startTime = platform->currentTime(platform);
903
Jamie Madill6c1f6712017-02-14 19:08:04 -0500904 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000905
Jamie Madill32447362017-06-28 14:53:52 -0400906 ProgramHash programHash;
907 auto *cache = context->getMemoryProgramCache();
908 if (cache)
909 {
910 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400911 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400912 }
913
914 if (mLinked)
915 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400916 double delta = platform->currentTime(platform) - startTime;
917 int us = static_cast<int>(delta * 1000000.0);
918 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400919 return NoError();
920 }
921
922 // Cache load failed, fall through to normal linking.
923 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000924 mInfoLog.reset();
925
Jiawei Shao73618602017-12-20 15:47:15 +0800926 if (!linkValidateShaders(context, mInfoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500927 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300928 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400929 }
930
Jiawei Shao73618602017-12-20 15:47:15 +0800931 if (mState.mAttachedComputeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500932 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400933 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300934 {
935 return NoError();
936 }
937
Jiajia Qin729b2c62017-08-14 09:36:11 +0800938 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300939 {
940 return NoError();
941 }
942
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800943 ProgramLinkedResources resources = {
944 {0, PackMode::ANGLE_RELAXED},
945 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +0800946 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
947 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500948
949 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
950 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
951
952 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500953 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300954 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500955 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300956 }
957 }
958 else
959 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400960 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300961 {
962 return NoError();
963 }
964
Jamie Madillbd044ed2017-06-05 12:59:21 -0400965 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300966 {
967 return NoError();
968 }
969
Jamie Madillbd044ed2017-06-05 12:59:21 -0400970 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300971 {
972 return NoError();
973 }
974
Jiajia Qin729b2c62017-08-14 09:36:11 +0800975 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300976 {
977 return NoError();
978 }
979
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400980 if (!linkValidateGlobalNames(context, mInfoLog))
981 {
982 return NoError();
983 }
984
Jamie Madillbd044ed2017-06-05 12:59:21 -0400985 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300986
Jiawei Shao73618602017-12-20 15:47:15 +0800987 ASSERT(mState.mAttachedVertexShader);
988 mState.mNumViews = mState.mAttachedVertexShader->getNumViews(context);
Martin Radev7cf61662017-07-26 17:10:53 +0300989
Jamie Madillbd044ed2017-06-05 12:59:21 -0400990 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300991
Jamie Madill192745a2016-12-22 15:58:21 -0500992 // Map the varyings to the register file
993 // In WebGL, we use a slightly different handling for packing variables.
Jamie Madill61d53252018-01-31 14:49:24 -0500994 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
995 if (data.getLimitations().noFlexibleVaryingPacking)
996 {
997 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
998 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
999 }
1000 else if (data.getExtensions().webglCompatibility)
1001 {
1002 packMode = PackMode::WEBGL_STRICT;
1003 }
Jamie Madillc9727f32017-11-07 12:37:07 -05001004
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001005 ProgramLinkedResources resources = {
1006 {data.getCaps().maxVaryingVectors, packMode},
1007 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +08001008 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
1009 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -05001010
1011 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
1012 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
1013
Jiawei Shao73618602017-12-20 15:47:15 +08001014 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -05001015 {
1016 return NoError();
1017 }
1018
jchen1085c93c42017-11-12 15:36:47 +08001019 if (!resources.varyingPacking.collectAndPackUserVaryings(
1020 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +03001021 {
1022 return NoError();
1023 }
1024
Jamie Madillc9727f32017-11-07 12:37:07 -05001025 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -05001026 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001027 {
Jamie Madillb0a838b2016-11-13 20:02:12 -05001028 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001029 }
1030
1031 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -05001032 }
1033
Jamie Madill6db1c2e2017-11-08 09:17:40 -05001034 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -04001035
jchen10eaef1e52017-06-13 10:44:11 +08001036 setUniformValuesFromBindingQualifiers();
1037
Yunchao Heece12532017-11-21 15:50:21 +08001038 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
1039 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +08001040 ASSERT(mLinked);
1041 updateLinkedShaderStages();
1042
Jamie Madill54164b02017-08-28 15:17:37 -04001043 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -04001044 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -04001045
Jamie Madill32447362017-06-28 14:53:52 -04001046 // Save to the program cache.
1047 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
1048 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
1049 {
1050 cache->putProgram(programHash, context, this);
1051 }
1052
Jamie Madill6c58b062017-08-01 13:44:25 -04001053 double delta = platform->currentTime(platform) - startTime;
1054 int us = static_cast<int>(delta * 1000000.0);
1055 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
1056
Martin Radev4c4c8e72016-08-04 12:25:34 +03001057 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +00001058}
1059
Yunchao He85072e82017-11-14 15:43:28 +08001060void Program::updateLinkedShaderStages()
1061{
Yunchao Heece12532017-11-21 15:50:21 +08001062 mState.mLinkedShaderStages.reset();
1063
Yunchao He85072e82017-11-14 15:43:28 +08001064 if (mState.mAttachedVertexShader)
1065 {
1066 mState.mLinkedShaderStages.set(SHADER_VERTEX);
1067 }
1068
1069 if (mState.mAttachedFragmentShader)
1070 {
1071 mState.mLinkedShaderStages.set(SHADER_FRAGMENT);
1072 }
1073
1074 if (mState.mAttachedComputeShader)
1075 {
1076 mState.mLinkedShaderStages.set(SHADER_COMPUTE);
1077 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001078
1079 if (mState.mAttachedGeometryShader)
1080 {
1081 mState.mLinkedShaderStages.set(SHADER_GEOMETRY);
1082 }
Yunchao He85072e82017-11-14 15:43:28 +08001083}
1084
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +00001085// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -05001086void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001088 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -08001089 mState.mAttributesTypeMask.reset();
1090 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001091 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -04001092 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +08001093 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001094 mState.mUniforms.clear();
1095 mState.mUniformLocations.clear();
1096 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001097 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001098 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001099 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001100 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001101 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001102 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001103 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001104 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001105 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001106 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001107 mState.mNumViews = -1;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08001108 mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
1109 mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
1110 mState.mGeometryShaderInvocations = 1;
1111 mState.mGeometryShaderMaxVertices = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001112
Geoff Lang7dd2e102014-11-10 15:19:26 -05001113 mValidated = false;
1114
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001115 mLinked = false;
1116}
1117
Geoff Lange1a27752015-10-05 13:16:04 -04001118bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001119{
1120 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121}
1122
Jamie Madilla2c74982016-12-12 11:20:42 -05001123Error Program::loadBinary(const Context *context,
1124 GLenum binaryFormat,
1125 const void *binary,
1126 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001127{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001128 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001129
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001131 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001132#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001133 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1134 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001135 {
Jamie Madillf6113162015-05-07 11:49:21 -04001136 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001137 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001138 }
1139
Jamie Madill4f86d052017-06-05 12:59:26 -04001140 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1141 ANGLE_TRY_RESULT(
1142 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001143
1144 // Currently we require the full shader text to compute the program hash.
1145 // TODO(jmadill): Store the binary in the internal program cache.
1146
Jamie Madillb0a838b2016-11-13 20:02:12 -05001147 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001148#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001149}
1150
Jamie Madilla2c74982016-12-12 11:20:42 -05001151Error Program::saveBinary(const Context *context,
1152 GLenum *binaryFormat,
1153 void *binary,
1154 GLsizei bufSize,
1155 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001156{
1157 if (binaryFormat)
1158 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001159 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160 }
1161
Jamie Madill4f86d052017-06-05 12:59:26 -04001162 angle::MemoryBuffer memoryBuf;
1163 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001164
Jamie Madill4f86d052017-06-05 12:59:26 -04001165 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1166 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001167
1168 if (streamLength > bufSize)
1169 {
1170 if (length)
1171 {
1172 *length = 0;
1173 }
1174
1175 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1176 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1177 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001178 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001179 }
1180
1181 if (binary)
1182 {
1183 char *ptr = reinterpret_cast<char*>(binary);
1184
Jamie Madill48ef11b2016-04-27 15:21:52 -04001185 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001186 ptr += streamLength;
1187
1188 ASSERT(ptr - streamLength == binary);
1189 }
1190
1191 if (length)
1192 {
1193 *length = streamLength;
1194 }
1195
He Yunchaoacd18982017-01-04 10:46:42 +08001196 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001197}
1198
Jamie Madillffe00c02017-06-27 16:26:55 -04001199GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001200{
1201 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001202 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001203 if (error.isError())
1204 {
1205 return 0;
1206 }
1207
1208 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001209}
1210
Geoff Langc5629752015-12-07 16:29:04 -05001211void Program::setBinaryRetrievableHint(bool retrievable)
1212{
1213 // TODO(jmadill) : replace with dirty bits
1214 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001215 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001216}
1217
1218bool Program::getBinaryRetrievableHint() const
1219{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001220 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001221}
1222
Yunchao He61afff12017-03-14 15:34:03 +08001223void Program::setSeparable(bool separable)
1224{
1225 // TODO(yunchao) : replace with dirty bits
1226 if (mState.mSeparable != separable)
1227 {
1228 mProgram->setSeparable(separable);
1229 mState.mSeparable = separable;
1230 }
1231}
1232
1233bool Program::isSeparable() const
1234{
1235 return mState.mSeparable;
1236}
1237
Jamie Madill6c1f6712017-02-14 19:08:04 -05001238void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001239{
1240 mRefCount--;
1241
1242 if (mRefCount == 0 && mDeleteStatus)
1243 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001244 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001245 }
1246}
1247
1248void Program::addRef()
1249{
1250 mRefCount++;
1251}
1252
1253unsigned int Program::getRefCount() const
1254{
1255 return mRefCount;
1256}
1257
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001258int Program::getInfoLogLength() const
1259{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001260 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001261}
1262
Geoff Lange1a27752015-10-05 13:16:04 -04001263void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001264{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001265 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001266}
1267
Geoff Lange1a27752015-10-05 13:16:04 -04001268void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001269{
1270 int total = 0;
1271
Martin Radev4c4c8e72016-08-04 12:25:34 +03001272 if (mState.mAttachedComputeShader)
1273 {
1274 if (total < maxCount)
1275 {
1276 shaders[total] = mState.mAttachedComputeShader->getHandle();
1277 total++;
1278 }
1279 }
1280
Jamie Madill48ef11b2016-04-27 15:21:52 -04001281 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001282 {
1283 if (total < maxCount)
1284 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001285 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001286 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001287 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001288 }
1289
Jamie Madill48ef11b2016-04-27 15:21:52 -04001290 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001291 {
1292 if (total < maxCount)
1293 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001294 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001295 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001296 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001297 }
1298
Jiawei Shao89be29a2017-11-06 14:36:45 +08001299 if (mState.mAttachedGeometryShader)
1300 {
1301 if (total < maxCount)
1302 {
1303 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1304 total++;
1305 }
1306 }
1307
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001308 if (count)
1309 {
1310 *count = total;
1311 }
1312}
1313
Geoff Lange1a27752015-10-05 13:16:04 -04001314GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001315{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001316 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001317}
1318
Jamie Madill63805b42015-08-25 13:17:39 -04001319bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001320{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001321 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1322 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001323}
1324
jchen10fd7c3b52017-03-21 15:36:03 +08001325void Program::getActiveAttribute(GLuint index,
1326 GLsizei bufsize,
1327 GLsizei *length,
1328 GLint *size,
1329 GLenum *type,
1330 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001331{
Jamie Madillc349ec02015-08-21 16:53:12 -04001332 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001333 {
1334 if (bufsize > 0)
1335 {
1336 name[0] = '\0';
1337 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001338
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001339 if (length)
1340 {
1341 *length = 0;
1342 }
1343
1344 *type = GL_NONE;
1345 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001346 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001347 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001348
jchen1036e120e2017-03-14 14:53:58 +08001349 ASSERT(index < mState.mAttributes.size());
1350 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001351
1352 if (bufsize > 0)
1353 {
jchen10fd7c3b52017-03-21 15:36:03 +08001354 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001355 }
1356
1357 // Always a single 'type' instance
1358 *size = 1;
1359 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001360}
1361
Geoff Lange1a27752015-10-05 13:16:04 -04001362GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001363{
Jamie Madillc349ec02015-08-21 16:53:12 -04001364 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001365 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001366 return 0;
1367 }
1368
jchen1036e120e2017-03-14 14:53:58 +08001369 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001370}
1371
Geoff Lange1a27752015-10-05 13:16:04 -04001372GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001373{
Jamie Madillc349ec02015-08-21 16:53:12 -04001374 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001375 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001376 return 0;
1377 }
1378
1379 size_t maxLength = 0;
1380
Jamie Madill48ef11b2016-04-27 15:21:52 -04001381 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001382 {
jchen1036e120e2017-03-14 14:53:58 +08001383 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001384 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385
Jamie Madillc349ec02015-08-21 16:53:12 -04001386 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387}
1388
jchen1015015f72017-03-16 13:54:21 +08001389GLuint Program::getInputResourceIndex(const GLchar *name) const
1390{
Olli Etuahod2551232017-10-26 20:03:33 +03001391 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001392}
1393
1394GLuint Program::getOutputResourceIndex(const GLchar *name) const
1395{
1396 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1397}
1398
jchen10fd7c3b52017-03-21 15:36:03 +08001399size_t Program::getOutputResourceCount() const
1400{
1401 return (mLinked ? mState.mOutputVariables.size() : 0);
1402}
1403
jchen10baf5d942017-08-28 20:45:48 +08001404template <typename T>
1405void Program::getResourceName(GLuint index,
1406 const std::vector<T> &resources,
1407 GLsizei bufSize,
1408 GLsizei *length,
1409 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001410{
1411 if (length)
1412 {
1413 *length = 0;
1414 }
1415
1416 if (!mLinked)
1417 {
1418 if (bufSize > 0)
1419 {
1420 name[0] = '\0';
1421 }
1422 return;
1423 }
jchen10baf5d942017-08-28 20:45:48 +08001424 ASSERT(index < resources.size());
1425 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001426
1427 if (bufSize > 0)
1428 {
Olli Etuahod2551232017-10-26 20:03:33 +03001429 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001430 }
1431}
1432
jchen10baf5d942017-08-28 20:45:48 +08001433void Program::getInputResourceName(GLuint index,
1434 GLsizei bufSize,
1435 GLsizei *length,
1436 GLchar *name) const
1437{
1438 getResourceName(index, mState.mAttributes, bufSize, length, name);
1439}
1440
1441void Program::getOutputResourceName(GLuint index,
1442 GLsizei bufSize,
1443 GLsizei *length,
1444 GLchar *name) const
1445{
1446 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1447}
1448
1449void Program::getUniformResourceName(GLuint index,
1450 GLsizei bufSize,
1451 GLsizei *length,
1452 GLchar *name) const
1453{
1454 getResourceName(index, mState.mUniforms, bufSize, length, name);
1455}
1456
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001457void Program::getBufferVariableResourceName(GLuint index,
1458 GLsizei bufSize,
1459 GLsizei *length,
1460 GLchar *name) const
1461{
1462 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1463}
1464
jchen10880683b2017-04-12 16:21:55 +08001465const sh::Attribute &Program::getInputResource(GLuint index) const
1466{
1467 ASSERT(index < mState.mAttributes.size());
1468 return mState.mAttributes[index];
1469}
1470
1471const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1472{
1473 ASSERT(index < mState.mOutputVariables.size());
1474 return mState.mOutputVariables[index];
1475}
1476
Geoff Lang7dd2e102014-11-10 15:19:26 -05001477GLint Program::getFragDataLocation(const std::string &name) const
1478{
Olli Etuahod2551232017-10-26 20:03:33 +03001479 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001480}
1481
Geoff Lange1a27752015-10-05 13:16:04 -04001482void Program::getActiveUniform(GLuint index,
1483 GLsizei bufsize,
1484 GLsizei *length,
1485 GLint *size,
1486 GLenum *type,
1487 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001488{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001489 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001490 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001491 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001492 ASSERT(index < mState.mUniforms.size());
1493 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494
1495 if (bufsize > 0)
1496 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001497 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001498 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001499 }
1500
Olli Etuaho465835d2017-09-26 13:34:10 +03001501 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001502 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001503 }
1504 else
1505 {
1506 if (bufsize > 0)
1507 {
1508 name[0] = '\0';
1509 }
1510
1511 if (length)
1512 {
1513 *length = 0;
1514 }
1515
1516 *size = 0;
1517 *type = GL_NONE;
1518 }
1519}
1520
Geoff Lange1a27752015-10-05 13:16:04 -04001521GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001522{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001524 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001525 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001526 }
1527 else
1528 {
1529 return 0;
1530 }
1531}
1532
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001533size_t Program::getActiveBufferVariableCount() const
1534{
1535 return mLinked ? mState.mBufferVariables.size() : 0;
1536}
1537
Geoff Lange1a27752015-10-05 13:16:04 -04001538GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001539{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001540 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001541
1542 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001543 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001544 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001546 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001547 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001548 size_t length = uniform.name.length() + 1u;
1549 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001550 {
1551 length += 3; // Counting in "[0]".
1552 }
1553 maxLength = std::max(length, maxLength);
1554 }
1555 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001556 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557
Jamie Madill62d31cb2015-09-11 13:25:51 -04001558 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001559}
1560
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561bool Program::isValidUniformLocation(GLint location) const
1562{
Jamie Madille2e406c2016-06-02 13:04:10 -04001563 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001564 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001565 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001566}
1567
Jamie Madill62d31cb2015-09-11 13:25:51 -04001568const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001570 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001571 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001572}
1573
Jamie Madillac4e9c32017-01-13 14:07:12 -05001574const VariableLocation &Program::getUniformLocation(GLint location) const
1575{
1576 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1577 return mState.mUniformLocations[location];
1578}
1579
1580const std::vector<VariableLocation> &Program::getUniformLocations() const
1581{
1582 return mState.mUniformLocations;
1583}
1584
1585const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1586{
1587 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1588 return mState.mUniforms[index];
1589}
1590
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001591const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1592{
1593 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1594 return mState.mBufferVariables[index];
1595}
1596
Jamie Madill62d31cb2015-09-11 13:25:51 -04001597GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001598{
Olli Etuahod2551232017-10-26 20:03:33 +03001599 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600}
1601
Jamie Madill62d31cb2015-09-11 13:25:51 -04001602GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001603{
Jamie Madille7d84322017-01-10 18:21:59 -05001604 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001605}
1606
1607void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1608{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001609 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1610 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001611 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001612}
1613
1614void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1615{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001616 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1617 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001618 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001619}
1620
1621void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1622{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001623 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1624 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001625 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001626}
1627
1628void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1629{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001630 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1631 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001632 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633}
1634
Jamie Madill81c2e252017-09-09 23:32:46 -04001635Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001637 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1638 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1639
Jamie Madill81c2e252017-09-09 23:32:46 -04001640 mProgram->setUniform1iv(location, clampedCount, v);
1641
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001642 if (mState.isSamplerUniformIndex(locationInfo.index))
1643 {
1644 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001645 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001646 }
1647
Jamie Madill81c2e252017-09-09 23:32:46 -04001648 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001649}
1650
1651void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1652{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001653 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1654 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001655 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656}
1657
1658void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1659{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001660 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1661 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001662 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001663}
1664
1665void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1666{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001667 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1668 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001669 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001670}
1671
1672void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1673{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001674 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1675 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001676 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001677}
1678
1679void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1680{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001681 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1682 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001683 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684}
1685
1686void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1687{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001688 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1689 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001690 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691}
1692
1693void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1694{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001695 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1696 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001697 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001698}
1699
1700void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1701{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001702 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001703 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001704}
1705
1706void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1707{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001708 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001709 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001710}
1711
1712void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1713{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001714 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001715 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001716}
1717
1718void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1719{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001720 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001721 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001722}
1723
1724void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1725{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001726 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001727 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001728}
1729
1730void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1731{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001732 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001733 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001734}
1735
1736void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1737{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001738 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001739 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001740}
1741
1742void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1743{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001744 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001745 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001746}
1747
1748void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1749{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001750 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001751 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001752}
1753
Jamie Madill54164b02017-08-28 15:17:37 -04001754void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001755{
Jamie Madill54164b02017-08-28 15:17:37 -04001756 const auto &uniformLocation = mState.getUniformLocations()[location];
1757 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1758
1759 GLenum nativeType = gl::VariableComponentType(uniform.type);
1760 if (nativeType == GL_FLOAT)
1761 {
1762 mProgram->getUniformfv(context, location, v);
1763 }
1764 else
1765 {
1766 getUniformInternal(context, v, location, nativeType,
1767 gl::VariableComponentCount(uniform.type));
1768 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001769}
1770
Jamie Madill54164b02017-08-28 15:17:37 -04001771void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001772{
Jamie Madill54164b02017-08-28 15:17:37 -04001773 const auto &uniformLocation = mState.getUniformLocations()[location];
1774 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1775
1776 GLenum nativeType = gl::VariableComponentType(uniform.type);
1777 if (nativeType == GL_INT || nativeType == GL_BOOL)
1778 {
1779 mProgram->getUniformiv(context, location, v);
1780 }
1781 else
1782 {
1783 getUniformInternal(context, v, location, nativeType,
1784 gl::VariableComponentCount(uniform.type));
1785 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786}
1787
Jamie Madill54164b02017-08-28 15:17:37 -04001788void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001789{
Jamie Madill54164b02017-08-28 15:17:37 -04001790 const auto &uniformLocation = mState.getUniformLocations()[location];
1791 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1792
1793 GLenum nativeType = gl::VariableComponentType(uniform.type);
1794 if (nativeType == GL_UNSIGNED_INT)
1795 {
1796 mProgram->getUniformuiv(context, location, v);
1797 }
1798 else
1799 {
1800 getUniformInternal(context, v, location, nativeType,
1801 gl::VariableComponentCount(uniform.type));
1802 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001803}
1804
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001805void Program::flagForDeletion()
1806{
1807 mDeleteStatus = true;
1808}
1809
1810bool Program::isFlaggedForDeletion() const
1811{
1812 return mDeleteStatus;
1813}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001814
Brandon Jones43a53e22014-08-28 16:23:22 -07001815void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001816{
1817 mInfoLog.reset();
1818
Geoff Lang7dd2e102014-11-10 15:19:26 -05001819 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001820 {
Geoff Lang92019432017-11-20 13:09:34 -05001821 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001822 }
1823 else
1824 {
Jamie Madillf6113162015-05-07 11:49:21 -04001825 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001826 }
1827}
1828
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1830{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001831 // Skip cache if we're using an infolog, so we get the full error.
1832 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1833 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1834 {
1835 return mCachedValidateSamplersResult.value();
1836 }
1837
1838 if (mTextureUnitTypesCache.empty())
1839 {
1840 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1841 }
1842 else
1843 {
1844 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1845 }
1846
1847 // if any two active samplers in a program are of different types, but refer to the same
1848 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1849 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001850 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001851 {
Jamie Madill54164b02017-08-28 15:17:37 -04001852 if (samplerBinding.unreferenced)
1853 continue;
1854
Jamie Madille7d84322017-01-10 18:21:59 -05001855 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001856
Jamie Madille7d84322017-01-10 18:21:59 -05001857 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001858 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001859 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1860 {
1861 if (infoLog)
1862 {
1863 (*infoLog) << "Sampler uniform (" << textureUnit
1864 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1865 << caps.maxCombinedTextureImageUnits << ")";
1866 }
1867
1868 mCachedValidateSamplersResult = false;
1869 return false;
1870 }
1871
1872 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1873 {
1874 if (textureType != mTextureUnitTypesCache[textureUnit])
1875 {
1876 if (infoLog)
1877 {
1878 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1879 "image unit ("
1880 << textureUnit << ").";
1881 }
1882
1883 mCachedValidateSamplersResult = false;
1884 return false;
1885 }
1886 }
1887 else
1888 {
1889 mTextureUnitTypesCache[textureUnit] = textureType;
1890 }
1891 }
1892 }
1893
1894 mCachedValidateSamplersResult = true;
1895 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001896}
1897
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001898bool Program::isValidated() const
1899{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001900 return mValidated;
1901}
1902
Geoff Lange1a27752015-10-05 13:16:04 -04001903GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001905 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001906}
1907
jchen1058f67be2017-10-27 08:59:27 +08001908GLuint Program::getActiveAtomicCounterBufferCount() const
1909{
1910 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1911}
1912
Jiajia Qin729b2c62017-08-14 09:36:11 +08001913GLuint Program::getActiveShaderStorageBlockCount() const
1914{
1915 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1916}
1917
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001918void Program::getActiveUniformBlockName(const GLuint blockIndex,
1919 GLsizei bufSize,
1920 GLsizei *length,
1921 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001922{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001923 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1924}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001925
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001926void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1927 GLsizei bufSize,
1928 GLsizei *length,
1929 GLchar *blockName) const
1930{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001932 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001933}
1934
Qin Jiajia9bf55522018-01-29 13:56:23 +08001935template <typename T>
1936GLint Program::getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001937{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938 int maxLength = 0;
1939
1940 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001941 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001942 for (const T &resource : resources)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001943 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001944 if (!resource.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001945 {
Qin Jiajia9bf55522018-01-29 13:56:23 +08001946 int length = static_cast<int>(resource.nameWithArrayIndex().length());
jchen10af713a22017-04-19 09:10:56 +08001947 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001948 }
1949 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001950 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951
1952 return maxLength;
1953}
1954
Qin Jiajia9bf55522018-01-29 13:56:23 +08001955GLint Program::getActiveUniformBlockMaxNameLength() const
1956{
1957 return getActiveInterfaceBlockMaxNameLength(mState.mUniformBlocks);
1958}
1959
1960GLint Program::getActiveShaderStorageBlockMaxNameLength() const
1961{
1962 return getActiveInterfaceBlockMaxNameLength(mState.mShaderStorageBlocks);
1963}
1964
Geoff Lange1a27752015-10-05 13:16:04 -04001965GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001966{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001967 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1968}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001969
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001970GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1971{
1972 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001973}
1974
Jiajia Qin729b2c62017-08-14 09:36:11 +08001975const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001976{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001977 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1978 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001979}
1980
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001981const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1982{
1983 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1984 return mState.mShaderStorageBlocks[index];
1985}
1986
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001987void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1988{
jchen107a20b972017-06-13 14:25:26 +08001989 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001990 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001991 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001992}
1993
1994GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1995{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001996 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001997}
1998
Jiajia Qin729b2c62017-08-14 09:36:11 +08001999GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
2000{
2001 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
2002}
2003
Geoff Lang48dcae72014-02-05 16:28:24 -05002004void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
2005{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002006 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05002007 for (GLsizei i = 0; i < count; i++)
2008 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002009 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05002010 }
2011
Jamie Madill48ef11b2016-04-27 15:21:52 -04002012 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05002013}
2014
2015void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
2016{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002018 {
jchen10a9042d32017-03-17 08:50:45 +08002019 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2020 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
2021 std::string varName = var.nameWithArrayIndex();
2022 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05002023 if (length)
2024 {
2025 *length = lastNameIdx;
2026 }
2027 if (size)
2028 {
jchen10a9042d32017-03-17 08:50:45 +08002029 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05002030 }
2031 if (type)
2032 {
jchen10a9042d32017-03-17 08:50:45 +08002033 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05002034 }
2035 if (name)
2036 {
jchen10a9042d32017-03-17 08:50:45 +08002037 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05002038 name[lastNameIdx] = '\0';
2039 }
2040 }
2041}
2042
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002043GLsizei Program::getTransformFeedbackVaryingCount() const
2044{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002046 {
jchen10a9042d32017-03-17 08:50:45 +08002047 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05002048 }
2049 else
2050 {
2051 return 0;
2052 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002053}
2054
2055GLsizei Program::getTransformFeedbackVaryingMaxLength() const
2056{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002057 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05002058 {
2059 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08002060 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05002061 {
jchen10a9042d32017-03-17 08:50:45 +08002062 maxSize =
2063 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05002064 }
2065
2066 return maxSize;
2067 }
2068 else
2069 {
2070 return 0;
2071 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002072}
2073
2074GLenum Program::getTransformFeedbackBufferMode() const
2075{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002076 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002077}
2078
Jiawei Shao73618602017-12-20 15:47:15 +08002079bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
2080{
2081 Shader *vertexShader = mState.mAttachedVertexShader;
2082 Shader *fragmentShader = mState.mAttachedFragmentShader;
2083 Shader *computeShader = mState.mAttachedComputeShader;
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002084 Shader *geometryShader = mState.mAttachedGeometryShader;
Jiawei Shao73618602017-12-20 15:47:15 +08002085
2086 bool isComputeShaderAttached = (computeShader != nullptr);
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002087 bool isGraphicsShaderAttached =
2088 (vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +08002089 // Check whether we both have a compute and non-compute shaders attached.
2090 // If there are of both types attached, then linking should fail.
2091 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
2092 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
2093 {
2094 infoLog << "Both compute and graphics shaders are attached to the same program.";
2095 return false;
2096 }
2097
2098 if (computeShader)
2099 {
2100 if (!computeShader->isCompiled(context))
2101 {
2102 infoLog << "Attached compute shader is not compiled.";
2103 return false;
2104 }
2105 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
2106
2107 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
2108
2109 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2110 // If the work group size is not specified, a link time error should occur.
2111 if (!mState.mComputeShaderLocalSize.isDeclared())
2112 {
2113 infoLog << "Work group size is not specified.";
2114 return false;
2115 }
2116 }
2117 else
2118 {
2119 if (!fragmentShader || !fragmentShader->isCompiled(context))
2120 {
2121 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2122 return false;
2123 }
2124 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
2125
2126 if (!vertexShader || !vertexShader->isCompiled(context))
2127 {
2128 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2129 return false;
2130 }
2131 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
2132
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002133 int vertexShaderVersion = vertexShader->getShaderVersion(context);
2134 if (fragmentShader->getShaderVersion(context) != vertexShaderVersion)
Jiawei Shao73618602017-12-20 15:47:15 +08002135 {
2136 infoLog << "Fragment shader version does not match vertex shader version.";
2137 return false;
2138 }
Jiawei Shao4ed05da2018-02-02 14:26:15 +08002139
2140 if (geometryShader)
2141 {
2142 // [GL_EXT_geometry_shader] Chapter 7
2143 // Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
2144 // Language Specification, as well as any of the following reasons:
2145 // * One or more of the shader objects attached to <program> are not compiled
2146 // successfully.
2147 // * The shaders do not use the same shader language version.
2148 // * <program> contains objects to form a geometry shader, and
2149 // - <program> is not separable and contains no objects to form a vertex shader; or
2150 // - the input primitive type, output primitive type, or maximum output vertex count
2151 // is not specified in the compiled geometry shader object.
2152 if (!geometryShader->isCompiled(context))
2153 {
2154 infoLog << "The attached geometry shader isn't compiled.";
2155 return false;
2156 }
2157
2158 if (geometryShader->getShaderVersion(context) != vertexShaderVersion)
2159 {
2160 mInfoLog << "Geometry shader version does not match vertex shader version.";
2161 return false;
2162 }
2163 ASSERT(geometryShader->getType() == GL_GEOMETRY_SHADER_EXT);
2164
2165 Optional<GLenum> inputPrimitive =
2166 geometryShader->getGeometryShaderInputPrimitiveType(context);
2167 if (!inputPrimitive.valid())
2168 {
2169 mInfoLog << "Input primitive type is not specified in the geometry shader.";
2170 return false;
2171 }
2172
2173 Optional<GLenum> outputPrimitive =
2174 geometryShader->getGeometryShaderOutputPrimitiveType(context);
2175 if (!outputPrimitive.valid())
2176 {
2177 mInfoLog << "Output primitive type is not specified in the geometry shader.";
2178 return false;
2179 }
2180
2181 Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices(context);
2182 if (!maxVertices.valid())
2183 {
2184 mInfoLog << "'max_vertices' is not specified in the geometry shader.";
2185 return false;
2186 }
2187
2188 mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
2189 mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
2190 mState.mGeometryShaderMaxVertices = maxVertices.value();
2191 mState.mGeometryShaderInvocations =
2192 geometryShader->getGeometryShaderInvocations(context);
2193 }
Jiawei Shao73618602017-12-20 15:47:15 +08002194 }
2195
2196 return true;
2197}
2198
jchen10910a3da2017-11-15 09:40:11 +08002199GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2200{
2201 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2202 {
2203 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2204 if (tf.nameWithArrayIndex() == name)
2205 {
2206 return tfIndex;
2207 }
2208 }
2209 return GL_INVALID_INDEX;
2210}
2211
2212const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2213{
2214 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2215 return mState.mLinkedTransformFeedbackVaryings[index];
2216}
2217
Jamie Madillbd044ed2017-06-05 12:59:21 -04002218bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002219{
Jiawei Shaod063aff2018-02-22 10:19:09 +08002220 std::vector<Shader *> activeShaders;
2221 activeShaders.push_back(mState.mAttachedVertexShader);
2222 if (mState.mAttachedGeometryShader)
2223 {
2224 activeShaders.push_back(mState.mAttachedGeometryShader);
2225 }
2226 activeShaders.push_back(mState.mAttachedFragmentShader);
Jamie Madill192745a2016-12-22 15:58:21 -05002227
Jiawei Shaod063aff2018-02-22 10:19:09 +08002228 const size_t activeShaderCount = activeShaders.size();
2229 for (size_t shaderIndex = 0; shaderIndex < activeShaderCount - 1; ++shaderIndex)
2230 {
2231 if (!linkValidateShaderInterfaceMatching(context, activeShaders[shaderIndex],
2232 activeShaders[shaderIndex + 1], infoLog))
2233 {
2234 return false;
2235 }
2236 }
2237
2238 if (!linkValidateBuiltInVaryings(context, infoLog))
2239 {
2240 return false;
2241 }
2242
2243 if (!linkValidateFragmentInputBindings(context, infoLog))
2244 {
2245 return false;
2246 }
2247
2248 return true;
2249}
2250
2251// [OpenGL ES 3.1] Chapter 7.4.1 "Shader Interface Matchining" Page 91
2252// TODO(jiawei.shao@intel.com): add validation on input/output blocks matching
2253bool Program::linkValidateShaderInterfaceMatching(const Context *context,
2254 gl::Shader *generatingShader,
2255 gl::Shader *consumingShader,
2256 gl::InfoLog &infoLog) const
2257{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002258 ASSERT(generatingShader->getShaderVersion(context) ==
2259 consumingShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002260
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002261 const std::vector<sh::Varying> &outputVaryings = generatingShader->getOutputVaryings(context);
2262 const std::vector<sh::Varying> &inputVaryings = consumingShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002263
Jiawei Shaod063aff2018-02-22 10:19:09 +08002264 bool validateGeometryShaderInputs = consumingShader->getType() == GL_GEOMETRY_SHADER_EXT;
Sami Väisänen46eaa942016-06-29 10:26:37 +03002265
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002266 for (const sh::Varying &input : inputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002267 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002268 bool matched = false;
2269
2270 // Built-in varyings obey special rules
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002271 if (input.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002272 {
2273 continue;
2274 }
2275
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002276 for (const sh::Varying &output : outputVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002277 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002278 if (input.name == output.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002279 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002280 ASSERT(!output.isBuiltIn());
2281
2282 std::string mismatchedStructFieldName;
2283 LinkMismatchError linkError =
2284 LinkValidateVaryings(output, input, generatingShader->getShaderVersion(context),
Jiawei Shaod063aff2018-02-22 10:19:09 +08002285 validateGeometryShaderInputs, &mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002286 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002287 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002288 LogLinkMismatch(infoLog, input.name, "varying", linkError,
2289 mismatchedStructFieldName, generatingShader->getType(),
2290 consumingShader->getType());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002291 return false;
2292 }
2293
Geoff Lang7dd2e102014-11-10 15:19:26 -05002294 matched = true;
2295 break;
2296 }
2297 }
2298
2299 // We permit unmatched, unreferenced varyings
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002300 if (!matched && input.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002301 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002302 infoLog << GetShaderTypeString(consumingShader->getType()) << " varying " << input.name
2303 << " does not match any " << GetShaderTypeString(generatingShader->getType())
2304 << " varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002305 return false;
2306 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002307 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002308
Jiawei Shaod063aff2018-02-22 10:19:09 +08002309 // TODO(jmadill): verify no unmatched output varyings?
Sami Väisänen46eaa942016-06-29 10:26:37 +03002310
Jiawei Shaod063aff2018-02-22 10:19:09 +08002311 return true;
2312}
2313
2314bool Program::linkValidateFragmentInputBindings(const Context *context, gl::InfoLog &infoLog) const
2315{
2316 ASSERT(mState.mAttachedFragmentShader);
2317
2318 std::map<GLuint, std::string> staticFragmentInputLocations;
2319
2320 const std::vector<sh::Varying> &fragmentInputVaryings =
2321 mState.mAttachedFragmentShader->getInputVaryings(context);
2322 for (const sh::Varying &input : fragmentInputVaryings)
2323 {
2324 if (input.isBuiltIn() || !input.staticUse)
2325 {
Sami Väisänen46eaa942016-06-29 10:26:37 +03002326 continue;
Jiawei Shaod063aff2018-02-22 10:19:09 +08002327 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002328
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002329 const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
Sami Väisänen46eaa942016-06-29 10:26:37 +03002330 if (inputBinding == -1)
2331 continue;
2332
2333 const auto it = staticFragmentInputLocations.find(inputBinding);
2334 if (it == std::end(staticFragmentInputLocations))
2335 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002336 staticFragmentInputLocations.insert(std::make_pair(inputBinding, input.name));
Sami Väisänen46eaa942016-06-29 10:26:37 +03002337 }
2338 else
2339 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002340 infoLog << "Binding for fragment input " << input.name << " conflicts with "
Sami Väisänen46eaa942016-06-29 10:26:37 +03002341 << it->second;
2342 return false;
2343 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002344 }
2345
2346 return true;
2347}
2348
Jamie Madillbd044ed2017-06-05 12:59:21 -04002349bool Program::linkUniforms(const Context *context,
2350 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002351 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002352{
Olli Etuahob78707c2017-03-09 15:03:11 +00002353 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002354 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002355 {
2356 return false;
2357 }
2358
Olli Etuahob78707c2017-03-09 15:03:11 +00002359 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002360
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002361 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002362
jchen10eaef1e52017-06-13 10:44:11 +08002363 if (!linkAtomicCounterBuffers())
2364 {
2365 return false;
2366 }
2367
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002368 return true;
2369}
2370
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002371void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002372{
Jamie Madill982f6e02017-06-07 14:33:04 -04002373 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2374 unsigned int low = high;
2375
jchen10eaef1e52017-06-13 10:44:11 +08002376 for (auto counterIter = mState.mUniforms.rbegin();
2377 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2378 {
2379 --low;
2380 }
2381
2382 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2383
2384 high = low;
2385
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002386 for (auto imageIter = mState.mUniforms.rbegin();
2387 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2388 {
2389 --low;
2390 }
2391
2392 mState.mImageUniformRange = RangeUI(low, high);
2393
2394 // If uniform is a image type, insert it into the mImageBindings array.
2395 for (unsigned int imageIndex : mState.mImageUniformRange)
2396 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002397 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2398 // cannot load values into a uniform defined as an image. if declare without a
2399 // binding qualifier, any uniform image variable (include all elements of
2400 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002401 auto &imageUniform = mState.mUniforms[imageIndex];
2402 if (imageUniform.binding == -1)
2403 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002404 mState.mImageBindings.emplace_back(
2405 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002406 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002407 else
2408 {
2409 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002410 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002411 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002412 }
2413
2414 high = low;
2415
2416 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002417 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002418 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002419 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002420 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002421
2422 mState.mSamplerUniformRange = RangeUI(low, high);
2423
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002424 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002425 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002426 {
2427 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2428 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2429 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002430 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002431 }
2432}
2433
jchen10eaef1e52017-06-13 10:44:11 +08002434bool Program::linkAtomicCounterBuffers()
2435{
2436 for (unsigned int index : mState.mAtomicCounterUniformRange)
2437 {
2438 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002439 uniform.blockInfo.offset = uniform.offset;
2440 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2441 uniform.blockInfo.matrixStride = 0;
2442 uniform.blockInfo.isRowMajorMatrix = false;
2443
jchen10eaef1e52017-06-13 10:44:11 +08002444 bool found = false;
2445 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2446 ++bufferIndex)
2447 {
2448 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2449 if (buffer.binding == uniform.binding)
2450 {
2451 buffer.memberIndexes.push_back(index);
2452 uniform.bufferIndex = bufferIndex;
2453 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002454 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002455 break;
2456 }
2457 }
2458 if (!found)
2459 {
2460 AtomicCounterBuffer atomicCounterBuffer;
2461 atomicCounterBuffer.binding = uniform.binding;
2462 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002463 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002464 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2465 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2466 }
2467 }
2468 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
Jiawei Shao0d88ec92018-02-27 16:25:31 +08002469 // gl_Max[Vertex|Fragment|Compute|Geometry|Combined]AtomicCounterBuffers.
jchen10eaef1e52017-06-13 10:44:11 +08002470
2471 return true;
2472}
2473
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002474LinkMismatchError Program::LinkValidateInterfaceBlockFields(
2475 const sh::InterfaceBlockField &blockField1,
2476 const sh::InterfaceBlockField &blockField2,
2477 bool webglCompatibility,
2478 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002479{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002480 if (blockField1.name != blockField2.name)
2481 {
2482 return LinkMismatchError::FIELD_NAME_MISMATCH;
2483 }
2484
Frank Henigmanfccbac22017-05-28 17:29:26 -04002485 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002486 LinkMismatchError linkError = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08002487 blockField1, blockField2, webglCompatibility, true, mismatchedBlockFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002488 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002489 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002490 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2491 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002492 }
2493
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002494 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002495 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002496 AddParentPrefix(blockField1.name, mismatchedBlockFieldName);
2497 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002498 }
2499
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002500 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002501}
2502
Jamie Madilleb979bf2016-11-15 12:28:46 -05002503// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002504bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002505{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002506 const ContextState &data = context->getContextState();
2507 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002508
Geoff Lang7dd2e102014-11-10 15:19:26 -05002509 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002510 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002511 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002512
2513 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002514 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002515 {
Jamie Madillf6113162015-05-07 11:49:21 -04002516 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002517 return false;
2518 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002519
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002520 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002521
Jamie Madillc349ec02015-08-21 16:53:12 -04002522 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002523 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002524 {
Olli Etuahod2551232017-10-26 20:03:33 +03002525 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2526 // structures, so we don't need to worry about adjusting their names or generating entries
2527 // for each member/element (unlike uniforms for example).
2528 ASSERT(!attribute.isArray() && !attribute.isStruct());
2529
Jamie Madilleb979bf2016-11-15 12:28:46 -05002530 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002531 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002532 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002533 attribute.location = bindingLocation;
2534 }
2535
2536 if (attribute.location != -1)
2537 {
2538 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002539 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002540
Jamie Madill63805b42015-08-25 13:17:39 -04002541 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002542 {
Jamie Madillf6113162015-05-07 11:49:21 -04002543 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002544 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002545
2546 return false;
2547 }
2548
Jamie Madill63805b42015-08-25 13:17:39 -04002549 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002550 {
Jamie Madill63805b42015-08-25 13:17:39 -04002551 const int regLocation = attribute.location + reg;
2552 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002553
2554 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002555 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002556 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002557 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002558 // TODO(jmadill): fix aliasing on ES2
2559 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002560 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002561 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002562 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002563 return false;
2564 }
2565 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002566 else
2567 {
Jamie Madill63805b42015-08-25 13:17:39 -04002568 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002569 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002570
Jamie Madill63805b42015-08-25 13:17:39 -04002571 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002572 }
2573 }
2574 }
2575
2576 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002577 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002578 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002579 // Not set by glBindAttribLocation or by location layout qualifier
2580 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002581 {
Jamie Madill63805b42015-08-25 13:17:39 -04002582 int regs = VariableRegisterCount(attribute.type);
2583 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002584
Jamie Madill63805b42015-08-25 13:17:39 -04002585 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002586 {
Jamie Madillf6113162015-05-07 11:49:21 -04002587 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002588 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002589 }
2590
Jamie Madillc349ec02015-08-21 16:53:12 -04002591 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002592 }
2593 }
2594
Brandon Jonesc405ae72017-12-06 14:15:03 -08002595 ASSERT(mState.mAttributesTypeMask.none());
2596 ASSERT(mState.mAttributesMask.none());
2597
Jamie Madill48ef11b2016-04-27 15:21:52 -04002598 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002599 {
Jamie Madill63805b42015-08-25 13:17:39 -04002600 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002601 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002602
Jamie Madillbd159f02017-10-09 19:39:06 -04002603 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002604 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002605 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2606 mState.mActiveAttribLocationsMask.set(location);
2607 mState.mMaxActiveAttribLocation =
2608 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08002609
2610 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
2611 if (!attribute.isBuiltIn())
2612 {
2613 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
2614 location);
2615 mState.mAttributesMask.set(location);
2616 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002617 }
2618 }
2619
Geoff Lang7dd2e102014-11-10 15:19:26 -05002620 return true;
2621}
2622
Jiawei Shao73618602017-12-20 15:47:15 +08002623bool Program::ValidateGraphicsInterfaceBlocks(
Martin Radev4c4c8e72016-08-04 12:25:34 +03002624 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2625 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002626 InfoLog &infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002627 bool webglCompatibility,
2628 sh::BlockType blockType,
2629 GLuint maxCombinedInterfaceBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002630{
2631 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002632 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2633 InterfaceBlockMap linkedInterfaceBlocks;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002634 GLuint blockCount = 0;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002635
2636 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2637 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002638 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jiajia Qin8efd1262017-12-19 09:32:55 +08002639 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2640 {
2641 blockCount += std::max(vertexInterfaceBlock.arraySize, 1u);
2642 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002643 }
2644
Jamie Madille473dee2015-08-18 14:49:01 -04002645 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002646 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002647 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2648 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002649 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002650 const sh::InterfaceBlock &vertexInterfaceBlock = *(entry->second);
2651 std::string mismatchedBlockFieldName;
2652 LinkMismatchError linkError =
2653 AreMatchingInterfaceBlocks(vertexInterfaceBlock, fragmentInterfaceBlock,
2654 webglCompatibility, &mismatchedBlockFieldName);
2655 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002656 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002657 LogLinkMismatch(infoLog, fragmentInterfaceBlock.name, "interface block", linkError,
2658 mismatchedBlockFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002659 return false;
2660 }
2661 }
Jiajia Qin8efd1262017-12-19 09:32:55 +08002662 else
2663 {
2664 if (fragmentInterfaceBlock.staticUse ||
2665 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
2666 {
2667 blockCount += std::max(fragmentInterfaceBlock.arraySize, 1u);
2668 }
2669 }
2670 }
2671
2672 if (blockCount > maxCombinedInterfaceBlocks)
2673 {
2674 switch (blockType)
2675 {
2676 case sh::BlockType::BLOCK_UNIFORM:
2677 infoLog << "The sum of the number of active uniform blocks exceeds "
2678 "MAX_COMBINED_UNIFORM_BLOCKS ("
2679 << maxCombinedInterfaceBlocks << ").";
2680 break;
2681 case sh::BlockType::BLOCK_BUFFER:
2682 infoLog << "The sum of the number of active shader storage blocks exceeds "
2683 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2684 << maxCombinedInterfaceBlocks << ").";
2685 break;
2686 default:
2687 UNREACHABLE();
2688 }
2689 return false;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002690 }
2691 return true;
2692}
Jamie Madille473dee2015-08-18 14:49:01 -04002693
Jiajia Qin729b2c62017-08-14 09:36:11 +08002694bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002695{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002696 const auto &caps = context->getCaps();
2697
Martin Radev4c4c8e72016-08-04 12:25:34 +03002698 if (mState.mAttachedComputeShader)
2699 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002700 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002701 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002702
Jiajia Qin729b2c62017-08-14 09:36:11 +08002703 if (!validateInterfaceBlocksCount(
2704 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002705 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2706 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002707 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002708 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002709 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002710
2711 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2712 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2713 computeShaderStorageBlocks,
2714 "Compute shader shader storage block count exceeds "
2715 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2716 infoLog))
2717 {
2718 return false;
2719 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002720 return true;
2721 }
2722
Jamie Madillbd044ed2017-06-05 12:59:21 -04002723 Shader &vertexShader = *mState.mAttachedVertexShader;
2724 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002725
Jiajia Qin729b2c62017-08-14 09:36:11 +08002726 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2727 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002728
Jiajia Qin729b2c62017-08-14 09:36:11 +08002729 if (!validateInterfaceBlocksCount(
2730 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002731 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2732 {
2733 return false;
2734 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002735 if (!validateInterfaceBlocksCount(
2736 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002737 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2738 infoLog))
2739 {
2740
2741 return false;
2742 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002743
2744 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiawei Shao73618602017-12-20 15:47:15 +08002745 if (!ValidateGraphicsInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, infoLog,
Jiajia Qin8efd1262017-12-19 09:32:55 +08002746 webglCompatibility, sh::BlockType::BLOCK_UNIFORM,
2747 caps.maxCombinedUniformBlocks))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002748 {
2749 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002750 }
Jamie Madille473dee2015-08-18 14:49:01 -04002751
Jiajia Qin729b2c62017-08-14 09:36:11 +08002752 if (context->getClientVersion() >= Version(3, 1))
2753 {
2754 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2755 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2756
2757 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2758 vertexShaderStorageBlocks,
2759 "Vertex shader shader storage block count exceeds "
2760 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2761 infoLog))
2762 {
2763 return false;
2764 }
2765 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2766 fragmentShaderStorageBlocks,
2767 "Fragment shader shader storage block count exceeds "
2768 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2769 infoLog))
2770 {
2771
2772 return false;
2773 }
2774
Jiajia Qin8efd1262017-12-19 09:32:55 +08002775 if (!ValidateGraphicsInterfaceBlocks(
2776 vertexShaderStorageBlocks, fragmentShaderStorageBlocks, infoLog, webglCompatibility,
2777 sh::BlockType::BLOCK_BUFFER, caps.maxCombinedShaderStorageBlocks))
Jiajia Qin729b2c62017-08-14 09:36:11 +08002778 {
2779 return false;
2780 }
2781 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002782 return true;
2783}
2784
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002785LinkMismatchError Program::AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2786 const sh::InterfaceBlock &interfaceBlock2,
2787 bool webglCompatibility,
2788 std::string *mismatchedBlockFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002789{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002790 // validate blocks for the same member types
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002791 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002792 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002793 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002794 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002795 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002796 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002797 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002798 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002799 if (interfaceBlock1.layout != interfaceBlock2.layout ||
2800 interfaceBlock1.binding != interfaceBlock2.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002801 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002802 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002803 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002804 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002805 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2806 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002807 const sh::InterfaceBlockField &member1 = interfaceBlock1.fields[blockMemberIndex];
2808 const sh::InterfaceBlockField &member2 = interfaceBlock2.fields[blockMemberIndex];
2809
2810 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2811 member1, member2, webglCompatibility, mismatchedBlockFieldName);
2812 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002813 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002814 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002815 }
2816 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002817 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002818}
2819
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002820LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &variable1,
2821 const sh::ShaderVariable &variable2,
2822 bool validatePrecision,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002823 bool validateArraySize,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002824 std::string *mismatchedStructOrBlockMemberName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002825{
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002826 if (variable1.type != variable2.type)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002827 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002828 return LinkMismatchError::TYPE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002829 }
Jiawei Shaod063aff2018-02-22 10:19:09 +08002830 if (validateArraySize && variable1.arraySizes != variable2.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002831 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002832 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002833 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002834 if (validatePrecision && variable1.precision != variable2.precision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002835 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002836 return LinkMismatchError::PRECISION_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002837 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002838 if (variable1.structName != variable2.structName)
Geoff Langbb1e7502017-06-05 16:40:09 -04002839 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002840 return LinkMismatchError::STRUCT_NAME_MISMATCH;
Geoff Langbb1e7502017-06-05 16:40:09 -04002841 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002842
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002843 if (variable1.fields.size() != variable2.fields.size())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002844 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002845 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002846 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002847 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002848 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2849 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002850 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2851 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002852
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002853 if (member1.name != member2.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002854 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002855 return LinkMismatchError::FIELD_NAME_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002856 }
2857
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002858 LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
Jiawei Shaod063aff2018-02-22 10:19:09 +08002859 member1, member2, validatePrecision, true, mismatchedStructOrBlockMemberName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002860 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002861 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002862 AddParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2863 return linkErrorOnField;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002864 }
2865 }
2866
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002867 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002868}
2869
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002870LinkMismatchError Program::LinkValidateVaryings(const sh::Varying &outputVarying,
2871 const sh::Varying &inputVarying,
2872 int shaderVersion,
Jiawei Shaod063aff2018-02-22 10:19:09 +08002873 bool validateGeometryShaderInputVarying,
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002874 std::string *mismatchedStructFieldName)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002875{
Jiawei Shaod063aff2018-02-22 10:19:09 +08002876 if (validateGeometryShaderInputVarying)
2877 {
2878 // [GL_EXT_geometry_shader] Section 11.1gs.4.3:
2879 // The OpenGL ES Shading Language doesn't support multi-dimensional arrays as shader inputs
2880 // or outputs.
2881 ASSERT(inputVarying.arraySizes.size() == 1u);
2882
2883 // Geometry shader input varyings are not treated as arrays, so a vertex array output
2884 // varying cannot match a geometry shader input varying.
2885 // [GL_EXT_geometry_shader] Section 7.4.1:
2886 // Geometry shader per-vertex input variables and blocks are required to be declared as
2887 // arrays, with each element representing input or output values for a single vertex of a
2888 // multi-vertex primitive. For the purposes of interface matching, such variables and blocks
2889 // are treated as though they were not declared as arrays.
2890 if (outputVarying.isArray())
2891 {
2892 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2893 }
2894 }
2895
2896 // Skip the validation on the array sizes between a vertex output varying and a geometry input
2897 // varying as it has been done before.
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002898 LinkMismatchError linkError =
Jiawei Shaod063aff2018-02-22 10:19:09 +08002899 LinkValidateVariablesBase(outputVarying, inputVarying, false,
2900 !validateGeometryShaderInputVarying, mismatchedStructFieldName);
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002901 if (linkError != LinkMismatchError::NO_MISMATCH)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002902 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002903 return linkError;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002904 }
2905
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002906 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002907 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002908 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002909 }
2910
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002911 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002912 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002913 return LinkMismatchError::INVARIANCE_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002914 }
2915
Jiawei Shao881b7bf2017-12-25 11:18:37 +08002916 return LinkMismatchError::NO_MISMATCH;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002917}
2918
Jamie Madillbd044ed2017-06-05 12:59:21 -04002919bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002920{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002921 Shader *vertexShader = mState.mAttachedVertexShader;
2922 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002923 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2924 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002925 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002926
2927 if (shaderVersion != 100)
2928 {
2929 // Only ESSL 1.0 has restrictions on matching input and output invariance
2930 return true;
2931 }
2932
2933 bool glPositionIsInvariant = false;
2934 bool glPointSizeIsInvariant = false;
2935 bool glFragCoordIsInvariant = false;
2936 bool glPointCoordIsInvariant = false;
2937
2938 for (const sh::Varying &varying : vertexVaryings)
2939 {
2940 if (!varying.isBuiltIn())
2941 {
2942 continue;
2943 }
2944 if (varying.name.compare("gl_Position") == 0)
2945 {
2946 glPositionIsInvariant = varying.isInvariant;
2947 }
2948 else if (varying.name.compare("gl_PointSize") == 0)
2949 {
2950 glPointSizeIsInvariant = varying.isInvariant;
2951 }
2952 }
2953
2954 for (const sh::Varying &varying : fragmentVaryings)
2955 {
2956 if (!varying.isBuiltIn())
2957 {
2958 continue;
2959 }
2960 if (varying.name.compare("gl_FragCoord") == 0)
2961 {
2962 glFragCoordIsInvariant = varying.isInvariant;
2963 }
2964 else if (varying.name.compare("gl_PointCoord") == 0)
2965 {
2966 glPointCoordIsInvariant = varying.isInvariant;
2967 }
2968 }
2969
2970 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2971 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2972 // Not requiring invariance to match is supported by:
2973 // dEQP, WebGL CTS, Nexus 5X GLES
2974 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2975 {
2976 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2977 "declared invariant.";
2978 return false;
2979 }
2980 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2981 {
2982 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2983 "declared invariant.";
2984 return false;
2985 }
2986
2987 return true;
2988}
2989
jchen10a9042d32017-03-17 08:50:45 +08002990bool Program::linkValidateTransformFeedback(const gl::Context *context,
2991 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002992 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002993 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002994{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002995
jchen108225e732017-11-14 16:29:03 +08002996 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04002997 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002998 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002999 {
jchen10a9042d32017-03-17 08:50:45 +08003000 if (context->getClientVersion() < Version(3, 1) &&
3001 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04003002 {
Geoff Lang1a683462015-09-29 15:09:59 -04003003 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04003004 return false;
3005 }
jchen108225e732017-11-14 16:29:03 +08003006 if (context->getClientVersion() >= Version(3, 1))
3007 {
3008 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
3009 {
3010 infoLog << "Two transform feedback varyings include the same array element ("
3011 << tfVaryingName << ").";
3012 return false;
3013 }
3014 }
3015 else
3016 {
3017 if (uniqueNames.count(tfVaryingName) > 0)
3018 {
3019 infoLog << "Two transform feedback varyings specify the same output variable ("
3020 << tfVaryingName << ").";
3021 return false;
3022 }
3023 }
3024 uniqueNames.insert(tfVaryingName);
3025 }
3026
3027 // Validate against program varyings.
3028 size_t totalComponents = 0;
3029 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
3030 {
3031 std::vector<unsigned int> subscripts;
3032 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
3033
3034 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
3035 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08003036 {
3037 infoLog << "Transform feedback varying " << tfVaryingName
3038 << " does not exist in the vertex shader.";
3039 return false;
3040 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003041
jchen108225e732017-11-14 16:29:03 +08003042 // Validate the matching variable.
3043 if (var->isStruct())
3044 {
3045 infoLog << "Struct cannot be captured directly (" << baseName << ").";
3046 return false;
3047 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003048
jchen108225e732017-11-14 16:29:03 +08003049 size_t elementCount = 0;
3050 size_t componentCount = 0;
3051
3052 if (var->isArray())
3053 {
3054 if (context->getClientVersion() < Version(3, 1))
3055 {
3056 infoLog << "Capture of arrays is undefined and not supported.";
3057 return false;
3058 }
3059
3060 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
3061 ASSERT(!var->isArrayOfArrays());
3062
3063 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
3064 {
3065 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
3066 return false;
3067 }
3068 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
3069 }
3070 else
3071 {
3072 if (!subscripts.empty())
3073 {
3074 infoLog << "Varying '" << baseName
3075 << "' is not an array to be captured by element.";
3076 return false;
3077 }
3078 elementCount = 1;
3079 }
3080
3081 // TODO(jmadill): Investigate implementation limits on D3D11
3082 componentCount = VariableComponentCount(var->type) * elementCount;
3083 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
3084 componentCount > caps.maxTransformFeedbackSeparateComponents)
3085 {
3086 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
3087 << componentCount << ") exceed the maximum separate components ("
3088 << caps.maxTransformFeedbackSeparateComponents << ").";
3089 return false;
3090 }
3091
3092 totalComponents += componentCount;
3093 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
3094 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
3095 {
3096 infoLog << "Transform feedback varying total components (" << totalComponents
3097 << ") exceed the maximum interleaved components ("
3098 << caps.maxTransformFeedbackInterleavedComponents << ").";
3099 return false;
3100 }
3101 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05003102 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05003103}
3104
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003105bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
3106{
3107 const std::vector<sh::Uniform> &vertexUniforms =
3108 mState.mAttachedVertexShader->getUniforms(context);
3109 const std::vector<sh::Uniform> &fragmentUniforms =
3110 mState.mAttachedFragmentShader->getUniforms(context);
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003111 const std::vector<sh::Uniform> *geometryUniforms =
3112 (mState.mAttachedGeometryShader) ? &mState.mAttachedGeometryShader->getUniforms(context)
3113 : nullptr;
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003114 const std::vector<sh::Attribute> &attributes =
3115 mState.mAttachedVertexShader->getActiveAttributes(context);
3116 for (const auto &attrib : attributes)
3117 {
3118 for (const auto &uniform : vertexUniforms)
3119 {
3120 if (uniform.name == attrib.name)
3121 {
3122 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3123 return false;
3124 }
3125 }
3126 for (const auto &uniform : fragmentUniforms)
3127 {
3128 if (uniform.name == attrib.name)
3129 {
3130 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3131 return false;
3132 }
3133 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +08003134 if (geometryUniforms)
3135 {
3136 for (const auto &uniform : *geometryUniforms)
3137 {
3138 if (uniform.name == attrib.name)
3139 {
3140 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
3141 return false;
3142 }
3143 }
3144 }
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04003145 }
3146 return true;
3147}
3148
Jamie Madill3c1da042017-11-27 18:33:40 -05003149void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003150{
3151 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08003152 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04003153 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003154 {
Olli Etuahoc8538042017-09-27 11:20:15 +03003155 std::vector<unsigned int> subscripts;
3156 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08003157 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03003158 if (!subscripts.empty())
3159 {
3160 subscript = subscripts.back();
3161 }
Jamie Madill192745a2016-12-22 15:58:21 -05003162 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003163 {
Jamie Madill192745a2016-12-22 15:58:21 -05003164 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08003165 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04003166 {
jchen10a9042d32017-03-17 08:50:45 +08003167 mState.mLinkedTransformFeedbackVaryings.emplace_back(
3168 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04003169 break;
3170 }
jchen108225e732017-11-14 16:29:03 +08003171 else if (varying->isStruct())
3172 {
3173 const auto *field = FindShaderVarField(*varying, tfVaryingName);
3174 if (field != nullptr)
3175 {
3176 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
3177 break;
3178 }
3179 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04003180 }
3181 }
3182}
3183
Jamie Madill3c1da042017-11-27 18:33:40 -05003184ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04003185{
Jamie Madill3c1da042017-11-27 18:33:40 -05003186 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003187
Jiawei Shao3d404882017-10-16 13:30:48 +08003188 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003189 {
Jamie Madill192745a2016-12-22 15:58:21 -05003190 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04003191 }
3192
Jiawei Shao3d404882017-10-16 13:30:48 +08003193 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04003194 {
Jamie Madill192745a2016-12-22 15:58:21 -05003195 merged[varying.name].fragment = &varying;
3196 }
3197
3198 return merged;
3199}
3200
Jamie Madillbd044ed2017-06-05 12:59:21 -04003201void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003202{
Jamie Madillbd044ed2017-06-05 12:59:21 -04003203 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04003204 ASSERT(fragmentShader != nullptr);
3205
Geoff Lange0cff192017-05-30 13:04:56 -04003206 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04003207 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08003208 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04003209
3210 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04003211 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04003212 {
3213 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
3214 outputVariable.name != "gl_FragData")
3215 {
3216 continue;
3217 }
3218
3219 unsigned int baseLocation =
3220 (outputVariable.location == -1 ? 0u
3221 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03003222
3223 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3224 // structures, so we may use getBasicTypeElementCount().
3225 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3226 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04003227 {
3228 const unsigned int location = baseLocation + elementIndex;
3229 if (location >= mState.mOutputVariableTypes.size())
3230 {
3231 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
3232 }
Corentin Walleze7557742017-06-01 13:09:57 -04003233 ASSERT(location < mState.mActiveOutputVariables.size());
3234 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04003235 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08003236 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04003237 }
3238 }
3239
Jamie Madill80a6fc02015-08-21 16:53:16 -04003240 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04003241 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003242 return;
3243
Jamie Madillbd044ed2017-06-05 12:59:21 -04003244 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04003245 // TODO(jmadill): any caps validation here?
3246
jchen1015015f72017-03-16 13:54:21 +08003247 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04003248 outputVariableIndex++)
3249 {
jchen1015015f72017-03-16 13:54:21 +08003250 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04003251
Olli Etuahod2551232017-10-26 20:03:33 +03003252 if (outputVariable.isArray())
3253 {
3254 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
3255 // Resources and including [0] at the end of array variable names.
3256 mState.mOutputVariables[outputVariableIndex].name += "[0]";
3257 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
3258 }
3259
Jamie Madill80a6fc02015-08-21 16:53:16 -04003260 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
3261 if (outputVariable.isBuiltIn())
3262 continue;
3263
3264 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03003265 unsigned int baseLocation =
3266 (outputVariable.location == -1 ? 0u
3267 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04003268
Olli Etuaho465835d2017-09-26 13:34:10 +03003269 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
3270 // structures, so we may use getBasicTypeElementCount().
3271 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
3272 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04003273 {
Olli Etuahod2551232017-10-26 20:03:33 +03003274 const unsigned int location = baseLocation + elementIndex;
3275 if (location >= mState.mOutputLocations.size())
3276 {
3277 mState.mOutputLocations.resize(location + 1);
3278 }
3279 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03003280 if (outputVariable.isArray())
3281 {
3282 mState.mOutputLocations[location] =
3283 VariableLocation(elementIndex, outputVariableIndex);
3284 }
3285 else
3286 {
3287 VariableLocation locationInfo;
3288 locationInfo.index = outputVariableIndex;
3289 mState.mOutputLocations[location] = locationInfo;
3290 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003291 }
3292 }
3293}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003294
Olli Etuaho48fed632017-03-16 12:05:30 +00003295void Program::setUniformValuesFromBindingQualifiers()
3296{
Jamie Madill982f6e02017-06-07 14:33:04 -04003297 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003298 {
3299 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3300 if (samplerUniform.binding != -1)
3301 {
Olli Etuahod2551232017-10-26 20:03:33 +03003302 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003303 ASSERT(location != -1);
3304 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003305 for (unsigned int elementIndex = 0;
3306 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003307 {
3308 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3309 }
3310 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3311 boundTextureUnits.data());
3312 }
3313 }
3314}
3315
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003316void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003317{
jchen10af713a22017-04-19 09:10:56 +08003318 // Set initial bindings from shader.
3319 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3320 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003321 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003322 bindUniformBlock(blockIndex, uniformBlock.binding);
3323 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003324}
3325
Jamie Madille7d84322017-01-10 18:21:59 -05003326void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003327 GLsizei clampedCount,
3328 const GLint *v)
3329{
Jamie Madill81c2e252017-09-09 23:32:46 -04003330 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3331 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3332 std::vector<GLuint> *boundTextureUnits =
3333 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003334
Olli Etuaho1734e172017-10-27 15:30:27 +03003335 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04003336
3337 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003338 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003339}
3340
3341template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003342GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3343 GLsizei count,
3344 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003345 const T *v)
3346{
Jamie Madill134f93d2017-08-31 17:11:00 -04003347 if (count == 1)
3348 return 1;
3349
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003350 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003351
Corentin Wallez15ac5342016-11-03 17:06:39 -04003352 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3353 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003354 unsigned int remainingElements =
3355 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003356 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003357 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003358
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003359 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003360 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003361 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003362 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003363
3364 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003365}
3366
3367template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003368GLsizei Program::clampMatrixUniformCount(GLint location,
3369 GLsizei count,
3370 GLboolean transpose,
3371 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003372{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003373 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3374
Jamie Madill62d31cb2015-09-11 13:25:51 -04003375 if (!transpose)
3376 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003377 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003378 }
3379
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003380 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003381
3382 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3383 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003384 unsigned int remainingElements =
3385 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003386 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003387}
3388
Jamie Madill54164b02017-08-28 15:17:37 -04003389// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3390// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003391template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003392void Program::getUniformInternal(const Context *context,
3393 DestT *dataOut,
3394 GLint location,
3395 GLenum nativeType,
3396 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003397{
Jamie Madill54164b02017-08-28 15:17:37 -04003398 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003399 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003400 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003401 {
3402 GLint tempValue[16] = {0};
3403 mProgram->getUniformiv(context, location, tempValue);
3404 UniformStateQueryCastLoop<GLboolean>(
3405 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003406 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003407 }
3408 case GL_INT:
3409 {
3410 GLint tempValue[16] = {0};
3411 mProgram->getUniformiv(context, location, tempValue);
3412 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3413 components);
3414 break;
3415 }
3416 case GL_UNSIGNED_INT:
3417 {
3418 GLuint tempValue[16] = {0};
3419 mProgram->getUniformuiv(context, location, tempValue);
3420 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3421 components);
3422 break;
3423 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003424 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003425 {
3426 GLfloat tempValue[16] = {0};
3427 mProgram->getUniformfv(context, location, tempValue);
3428 UniformStateQueryCastLoop<GLfloat>(
3429 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003430 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003431 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003432 default:
3433 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003434 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003435 }
3436}
Jamie Madilla4595b82017-01-11 17:36:34 -05003437
3438bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3439{
3440 // Must be called after samplers are validated.
3441 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3442
3443 for (const auto &binding : mState.mSamplerBindings)
3444 {
3445 GLenum textureType = binding.textureType;
3446 for (const auto &unit : binding.boundTextureUnits)
3447 {
3448 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3449 if (programTextureID == textureID)
3450 {
3451 // TODO(jmadill): Check for appropriate overlap.
3452 return true;
3453 }
3454 }
3455 }
3456
3457 return false;
3458}
3459
Jamie Madilla2c74982016-12-12 11:20:42 -05003460} // namespace gl