blob: 0d223b35cb34e4e1f62bf49d1efa7af6fa34d173 [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
Jamie Madill62d31cb2015-09-11 13:25:51 -0400345} // anonymous namespace
346
Jamie Madill4a3c2342015-10-08 12:58:45 -0400347const char *const g_fakepath = "C:\\fakepath";
348
Jamie Madill3c1da042017-11-27 18:33:40 -0500349// InfoLog implementation.
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400350InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000351{
352}
353
354InfoLog::~InfoLog()
355{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356}
357
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400358size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000359{
Jamie Madill23176ce2017-07-31 14:14:33 -0400360 if (!mLazyStream)
361 {
362 return 0;
363 }
364
365 const std::string &logString = mLazyStream->str();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400366 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000367}
368
Geoff Lange1a27752015-10-05 13:16:04 -0400369void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000370{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400371 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000372
373 if (bufSize > 0)
374 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400375 const std::string logString(str());
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400376
Jamie Madill23176ce2017-07-31 14:14:33 -0400377 if (!logString.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000378 {
Jamie Madill23176ce2017-07-31 14:14:33 -0400379 index = std::min(static_cast<size_t>(bufSize) - 1, logString.length());
380 memcpy(infoLog, logString.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000381 }
382
383 infoLog[index] = '\0';
384 }
385
386 if (length)
387 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400388 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000389 }
390}
391
392// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300393// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000394// messages, so lets remove all occurrences of this fake file path from the log.
395void InfoLog::appendSanitized(const char *message)
396{
Jamie Madill23176ce2017-07-31 14:14:33 -0400397 ensureInitialized();
398
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000399 std::string msg(message);
400
401 size_t found;
402 do
403 {
404 found = msg.find(g_fakepath);
405 if (found != std::string::npos)
406 {
407 msg.erase(found, strlen(g_fakepath));
408 }
409 }
410 while (found != std::string::npos);
411
Jamie Madill23176ce2017-07-31 14:14:33 -0400412 *mLazyStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000413}
414
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000415void InfoLog::reset()
416{
Jiawei Shao02f15232017-12-27 10:10:28 +0800417 if (mLazyStream)
418 {
419 mLazyStream.reset(nullptr);
420 }
421}
422
423bool InfoLog::empty() const
424{
425 if (!mLazyStream)
426 {
427 return true;
428 }
429
430 return mLazyStream->rdbuf()->in_avail() == 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000431}
432
Jamie Madill3c1da042017-11-27 18:33:40 -0500433// VariableLocation implementation.
Olli Etuaho1734e172017-10-27 15:30:27 +0300434VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000435{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500436}
437
Olli Etuahoc8538042017-09-27 11:20:15 +0300438VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index)
Olli Etuaho1734e172017-10-27 15:30:27 +0300439 : arrayIndex(arrayIndex), index(index), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500440{
Olli Etuahoc8538042017-09-27 11:20:15 +0300441 ASSERT(arrayIndex != GL_INVALID_INDEX);
442}
443
Jamie Madill3c1da042017-11-27 18:33:40 -0500444// SamplerBindings implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500445SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced)
446 : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
447{
448}
449
450SamplerBinding::SamplerBinding(const SamplerBinding &other) = default;
451
452SamplerBinding::~SamplerBinding() = default;
453
Jamie Madill3c1da042017-11-27 18:33:40 -0500454// ProgramBindings implementation.
455ProgramBindings::ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500456{
457}
458
Jamie Madill3c1da042017-11-27 18:33:40 -0500459ProgramBindings::~ProgramBindings()
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500460{
461}
462
Jamie Madill3c1da042017-11-27 18:33:40 -0500463void ProgramBindings::bindLocation(GLuint index, const std::string &name)
Geoff Langd8605522016-04-13 10:19:12 -0400464{
465 mBindings[name] = index;
466}
467
Jamie Madill3c1da042017-11-27 18:33:40 -0500468int ProgramBindings::getBinding(const std::string &name) const
Geoff Langd8605522016-04-13 10:19:12 -0400469{
470 auto iter = mBindings.find(name);
471 return (iter != mBindings.end()) ? iter->second : -1;
472}
473
Jamie Madill3c1da042017-11-27 18:33:40 -0500474ProgramBindings::const_iterator ProgramBindings::begin() const
Geoff Langd8605522016-04-13 10:19:12 -0400475{
476 return mBindings.begin();
477}
478
Jamie Madill3c1da042017-11-27 18:33:40 -0500479ProgramBindings::const_iterator ProgramBindings::end() const
Geoff Langd8605522016-04-13 10:19:12 -0400480{
481 return mBindings.end();
482}
483
Jamie Madill3c1da042017-11-27 18:33:40 -0500484// ImageBinding implementation.
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500485ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
486{
487}
488ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
489{
490 for (size_t index = 0; index < count; ++index)
491 {
492 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
493 }
494}
495
496ImageBinding::ImageBinding(const ImageBinding &other) = default;
497
498ImageBinding::~ImageBinding() = default;
499
Jamie Madill3c1da042017-11-27 18:33:40 -0500500// ProgramState implementation.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400501ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500502 : mLabel(),
503 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400504 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300505 mAttachedComputeShader(nullptr),
Jiawei Shao89be29a2017-11-06 14:36:45 +0800506 mAttachedGeometryShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500507 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madillbd159f02017-10-09 19:39:06 -0400508 mMaxActiveAttribLocation(0),
Jamie Madille7d84322017-01-10 18:21:59 -0500509 mSamplerUniformRange(0, 0),
jchen10eaef1e52017-06-13 10:44:11 +0800510 mImageUniformRange(0, 0),
511 mAtomicCounterUniformRange(0, 0),
Martin Radev7cf61662017-07-26 17:10:53 +0300512 mBinaryRetrieveableHint(false),
513 mNumViews(-1)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400514{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300515 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400516}
517
Jamie Madill48ef11b2016-04-27 15:21:52 -0400518ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400519{
Jiawei Shao89be29a2017-11-06 14:36:45 +0800520 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader &&
521 !mAttachedGeometryShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400522}
523
Jamie Madill48ef11b2016-04-27 15:21:52 -0400524const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500525{
526 return mLabel;
527}
528
Jamie Madille7d84322017-01-10 18:21:59 -0500529GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400530{
jchen1015015f72017-03-16 13:54:21 +0800531 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400532}
533
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800534GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const
535{
536 return GetResourceIndexFromName(mBufferVariables, name);
537}
538
Jamie Madille7d84322017-01-10 18:21:59 -0500539GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
540{
541 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
542 return mUniformLocations[location].index;
543}
544
545Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
546{
547 GLuint index = getUniformIndexFromLocation(location);
548 if (!isSamplerUniformIndex(index))
549 {
550 return Optional<GLuint>::Invalid();
551 }
552
553 return getSamplerIndexFromUniformIndex(index);
554}
555
556bool ProgramState::isSamplerUniformIndex(GLuint index) const
557{
Jamie Madill982f6e02017-06-07 14:33:04 -0400558 return mSamplerUniformRange.contains(index);
Jamie Madille7d84322017-01-10 18:21:59 -0500559}
560
561GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
562{
563 ASSERT(isSamplerUniformIndex(uniformIndex));
Jamie Madill982f6e02017-06-07 14:33:04 -0400564 return uniformIndex - mSamplerUniformRange.low();
Jamie Madille7d84322017-01-10 18:21:59 -0500565}
566
Jamie Madill34ca4f52017-06-13 11:49:39 -0400567GLuint ProgramState::getAttributeLocation(const std::string &name) const
568{
569 for (const sh::Attribute &attribute : mAttributes)
570 {
571 if (attribute.name == name)
572 {
573 return attribute.location;
574 }
575 }
576
577 return static_cast<GLuint>(-1);
578}
579
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500580Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400581 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400582 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500583 mLinked(false),
584 mDeleteStatus(false),
585 mRefCount(0),
586 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500587 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500588{
589 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000590
Geoff Lang7dd2e102014-11-10 15:19:26 -0500591 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000592}
593
594Program::~Program()
595{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400596 ASSERT(!mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597}
598
Jamie Madill4928b7c2017-06-20 12:57:39 -0400599void Program::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500600{
601 if (mState.mAttachedVertexShader != nullptr)
602 {
603 mState.mAttachedVertexShader->release(context);
604 mState.mAttachedVertexShader = nullptr;
605 }
606
607 if (mState.mAttachedFragmentShader != nullptr)
608 {
609 mState.mAttachedFragmentShader->release(context);
610 mState.mAttachedFragmentShader = nullptr;
611 }
612
613 if (mState.mAttachedComputeShader != nullptr)
614 {
615 mState.mAttachedComputeShader->release(context);
616 mState.mAttachedComputeShader = nullptr;
617 }
618
Jiawei Shao89be29a2017-11-06 14:36:45 +0800619 if (mState.mAttachedGeometryShader != nullptr)
620 {
621 mState.mAttachedGeometryShader->release(context);
622 mState.mAttachedGeometryShader = nullptr;
623 }
624
Jamie Madillc564c072017-06-01 12:45:42 -0400625 mProgram->destroy(context);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400626
627 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
Jiawei Shao89be29a2017-11-06 14:36:45 +0800628 !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400629 SafeDelete(mProgram);
630
631 delete this;
Jamie Madill6c1f6712017-02-14 19:08:04 -0500632}
633
Geoff Lang70d0f492015-12-10 17:45:46 -0500634void Program::setLabel(const std::string &label)
635{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400636 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500637}
638
639const std::string &Program::getLabel() const
640{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400641 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500642}
643
Jamie Madillef300b12016-10-07 15:12:09 -0400644void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300646 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300648 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649 {
Jamie Madillef300b12016-10-07 15:12:09 -0400650 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300651 mState.mAttachedVertexShader = shader;
652 mState.mAttachedVertexShader->addRef();
653 break;
654 }
655 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656 {
Jamie Madillef300b12016-10-07 15:12:09 -0400657 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300658 mState.mAttachedFragmentShader = shader;
659 mState.mAttachedFragmentShader->addRef();
660 break;
661 }
662 case GL_COMPUTE_SHADER:
663 {
Jamie Madillef300b12016-10-07 15:12:09 -0400664 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300665 mState.mAttachedComputeShader = shader;
666 mState.mAttachedComputeShader->addRef();
667 break;
668 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800669 case GL_GEOMETRY_SHADER_EXT:
670 {
671 ASSERT(!mState.mAttachedGeometryShader);
672 mState.mAttachedGeometryShader = shader;
673 mState.mAttachedGeometryShader->addRef();
674 break;
675 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300676 default:
677 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679}
680
Jamie Madillc1d770e2017-04-13 17:31:24 -0400681void Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300683 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300685 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400687 ASSERT(mState.mAttachedVertexShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500688 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300689 mState.mAttachedVertexShader = nullptr;
690 break;
691 }
692 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400694 ASSERT(mState.mAttachedFragmentShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500695 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300696 mState.mAttachedFragmentShader = nullptr;
697 break;
698 }
699 case GL_COMPUTE_SHADER:
700 {
Jamie Madillc1d770e2017-04-13 17:31:24 -0400701 ASSERT(mState.mAttachedComputeShader == shader);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500702 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300703 mState.mAttachedComputeShader = nullptr;
704 break;
705 }
Jiawei Shao89be29a2017-11-06 14:36:45 +0800706 case GL_GEOMETRY_SHADER_EXT:
707 {
708 ASSERT(mState.mAttachedGeometryShader == shader);
709 shader->release(context);
710 mState.mAttachedGeometryShader = nullptr;
711 break;
712 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300713 default:
714 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000715 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716}
717
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000718int Program::getAttachedShadersCount() const
719{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300720 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
Jiawei Shao89be29a2017-11-06 14:36:45 +0800721 (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000722}
723
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724void Program::bindAttributeLocation(GLuint index, const char *name)
725{
Geoff Langd8605522016-04-13 10:19:12 -0400726 mAttributeBindings.bindLocation(index, name);
727}
728
729void Program::bindUniformLocation(GLuint index, const char *name)
730{
Olli Etuahod2551232017-10-26 20:03:33 +0300731 mUniformLocationBindings.bindLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732}
733
Sami Väisänen46eaa942016-06-29 10:26:37 +0300734void Program::bindFragmentInputLocation(GLint index, const char *name)
735{
736 mFragmentInputBindings.bindLocation(index, name);
737}
738
Jamie Madillbd044ed2017-06-05 12:59:21 -0400739BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const
Sami Väisänen46eaa942016-06-29 10:26:37 +0300740{
741 BindingInfo ret;
742 ret.type = GL_NONE;
743 ret.valid = false;
744
Jamie Madillbd044ed2017-06-05 12:59:21 -0400745 Shader *fragmentShader = mState.getAttachedFragmentShader();
Sami Väisänen46eaa942016-06-29 10:26:37 +0300746 ASSERT(fragmentShader);
747
748 // Find the actual fragment shader varying we're interested in
Jiawei Shao3d404882017-10-16 13:30:48 +0800749 const std::vector<sh::Varying> &inputs = fragmentShader->getInputVaryings(context);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300750
751 for (const auto &binding : mFragmentInputBindings)
752 {
753 if (binding.second != static_cast<GLuint>(index))
754 continue;
755
756 ret.valid = true;
757
Olli Etuahod2551232017-10-26 20:03:33 +0300758 size_t nameLengthWithoutArrayIndex;
759 unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300760
761 for (const auto &in : inputs)
762 {
Olli Etuahod2551232017-10-26 20:03:33 +0300763 if (in.name.length() == nameLengthWithoutArrayIndex &&
764 angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex))
Sami Väisänen46eaa942016-06-29 10:26:37 +0300765 {
766 if (in.isArray())
767 {
768 // The client wants to bind either "name" or "name[0]".
769 // GL ES 3.1 spec refers to active array names with language such as:
770 // "if the string identifies the base name of an active array, where the
771 // string would exactly match the name of the variable if the suffix "[0]"
772 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400773 if (arrayIndex == GL_INVALID_INDEX)
774 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300775
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400776 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300777 }
778 else
779 {
780 ret.name = in.mappedName;
781 }
782 ret.type = in.type;
783 return ret;
784 }
785 }
786 }
787
788 return ret;
789}
790
Jamie Madillbd044ed2017-06-05 12:59:21 -0400791void Program::pathFragmentInputGen(const Context *context,
792 GLint index,
Sami Väisänen46eaa942016-06-29 10:26:37 +0300793 GLenum genMode,
794 GLint components,
795 const GLfloat *coeffs)
796{
797 // If the location is -1 then the command is silently ignored
798 if (index == -1)
799 return;
800
Jamie Madillbd044ed2017-06-05 12:59:21 -0400801 const auto &binding = getFragmentInputBindingInfo(context, index);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300802
803 // If the input doesn't exist then then the command is silently ignored
804 // This could happen through optimization for example, the shader translator
805 // decides that a variable is not actually being used and optimizes it away.
806 if (binding.name.empty())
807 return;
808
809 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
810}
811
Martin Radev4c4c8e72016-08-04 12:25:34 +0300812// The attached shaders are checked for linking errors by matching up their variables.
813// Uniform, input and output variables get collected.
814// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500815Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000816{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500817 const auto &data = context->getContextState();
818
Jamie Madill6c58b062017-08-01 13:44:25 -0400819 auto *platform = ANGLEPlatformCurrent();
820 double startTime = platform->currentTime(platform);
821
Jamie Madill6c1f6712017-02-14 19:08:04 -0500822 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000823
Jamie Madill32447362017-06-28 14:53:52 -0400824 ProgramHash programHash;
825 auto *cache = context->getMemoryProgramCache();
826 if (cache)
827 {
828 ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
Jamie Madill6c58b062017-08-01 13:44:25 -0400829 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked);
Jamie Madill32447362017-06-28 14:53:52 -0400830 }
831
832 if (mLinked)
833 {
Jamie Madill6c58b062017-08-01 13:44:25 -0400834 double delta = platform->currentTime(platform) - startTime;
835 int us = static_cast<int>(delta * 1000000.0);
836 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us);
Jamie Madill32447362017-06-28 14:53:52 -0400837 return NoError();
838 }
839
840 // Cache load failed, fall through to normal linking.
841 unlink();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000842 mInfoLog.reset();
843
Jiawei Shao73618602017-12-20 15:47:15 +0800844 if (!linkValidateShaders(context, mInfoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500845 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300846 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400847 }
848
Jiawei Shao73618602017-12-20 15:47:15 +0800849 if (mState.mAttachedComputeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500850 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400851 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300852 {
853 return NoError();
854 }
855
Jiajia Qin729b2c62017-08-14 09:36:11 +0800856 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300857 {
858 return NoError();
859 }
860
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800861 ProgramLinkedResources resources = {
862 {0, PackMode::ANGLE_RELAXED},
863 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +0800864 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
865 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500866
867 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
868 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
869
870 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500871 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300872 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500873 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300874 }
875 }
876 else
877 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400878 if (!linkAttributes(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300879 {
880 return NoError();
881 }
882
Jamie Madillbd044ed2017-06-05 12:59:21 -0400883 if (!linkVaryings(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300884 {
885 return NoError();
886 }
887
Jamie Madillbd044ed2017-06-05 12:59:21 -0400888 if (!linkUniforms(context, mInfoLog, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300889 {
890 return NoError();
891 }
892
Jiajia Qin729b2c62017-08-14 09:36:11 +0800893 if (!linkInterfaceBlocks(context, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300894 {
895 return NoError();
896 }
897
Yuly Novikovcaa5cda2017-06-15 21:14:03 -0400898 if (!linkValidateGlobalNames(context, mInfoLog))
899 {
900 return NoError();
901 }
902
Jamie Madillbd044ed2017-06-05 12:59:21 -0400903 const auto &mergedVaryings = getMergedVaryings(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300904
Jiawei Shao73618602017-12-20 15:47:15 +0800905 ASSERT(mState.mAttachedVertexShader);
906 mState.mNumViews = mState.mAttachedVertexShader->getNumViews(context);
Martin Radev7cf61662017-07-26 17:10:53 +0300907
Jamie Madillbd044ed2017-06-05 12:59:21 -0400908 linkOutputVariables(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300909
Jamie Madill192745a2016-12-22 15:58:21 -0500910 // Map the varyings to the register file
911 // In WebGL, we use a slightly different handling for packing variables.
912 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
913 : PackMode::ANGLE_RELAXED;
Jamie Madillc9727f32017-11-07 12:37:07 -0500914
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800915 ProgramLinkedResources resources = {
916 {data.getCaps().maxVaryingVectors, packMode},
917 {&mState.mUniformBlocks, &mState.mUniforms},
Jiajia Qin94f1e892017-11-20 12:14:32 +0800918 {&mState.mShaderStorageBlocks, &mState.mBufferVariables},
919 {&mState.mAtomicCounterBuffers}};
Jamie Madillc9727f32017-11-07 12:37:07 -0500920
921 InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker);
922 InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker);
923
Jiawei Shao73618602017-12-20 15:47:15 +0800924 if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, context->getCaps()))
Jamie Madill192745a2016-12-22 15:58:21 -0500925 {
926 return NoError();
927 }
928
jchen1085c93c42017-11-12 15:36:47 +0800929 if (!resources.varyingPacking.collectAndPackUserVaryings(
930 mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames()))
Olli Etuaho39e78122017-08-29 14:34:22 +0300931 {
932 return NoError();
933 }
934
Jamie Madillc9727f32017-11-07 12:37:07 -0500935 ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500936 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300937 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500938 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300939 }
940
941 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500942 }
943
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500944 initInterfaceBlockBindings();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400945
jchen10eaef1e52017-06-13 10:44:11 +0800946 setUniformValuesFromBindingQualifiers();
947
Yunchao Heece12532017-11-21 15:50:21 +0800948 // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
949 // Only successfully linked program can replace the executables.
Yunchao He85072e82017-11-14 15:43:28 +0800950 ASSERT(mLinked);
951 updateLinkedShaderStages();
952
Jamie Madill54164b02017-08-28 15:17:37 -0400953 // Mark implementation-specific unreferenced uniforms as ignored.
Jamie Madillfb997ec2017-09-20 15:44:27 -0400954 mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
Jamie Madill54164b02017-08-28 15:17:37 -0400955
Jamie Madill32447362017-06-28 14:53:52 -0400956 // Save to the program cache.
957 if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
958 !context->getWorkarounds().disableProgramCachingForTransformFeedback))
959 {
960 cache->putProgram(programHash, context, this);
961 }
962
Jamie Madill6c58b062017-08-01 13:44:25 -0400963 double delta = platform->currentTime(platform) - startTime;
964 int us = static_cast<int>(delta * 1000000.0);
965 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us);
966
Martin Radev4c4c8e72016-08-04 12:25:34 +0300967 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000968}
969
Yunchao He85072e82017-11-14 15:43:28 +0800970void Program::updateLinkedShaderStages()
971{
Yunchao Heece12532017-11-21 15:50:21 +0800972 mState.mLinkedShaderStages.reset();
973
Yunchao He85072e82017-11-14 15:43:28 +0800974 if (mState.mAttachedVertexShader)
975 {
976 mState.mLinkedShaderStages.set(SHADER_VERTEX);
977 }
978
979 if (mState.mAttachedFragmentShader)
980 {
981 mState.mLinkedShaderStages.set(SHADER_FRAGMENT);
982 }
983
984 if (mState.mAttachedComputeShader)
985 {
986 mState.mLinkedShaderStages.set(SHADER_COMPUTE);
987 }
988}
989
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000990// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500991void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000992{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400993 mState.mAttributes.clear();
Brandon Jonesc405ae72017-12-06 14:15:03 -0800994 mState.mAttributesTypeMask.reset();
995 mState.mAttributesMask.reset();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400996 mState.mActiveAttribLocationsMask.reset();
Jamie Madillbd159f02017-10-09 19:39:06 -0400997 mState.mMaxActiveAttribLocation = 0;
jchen10a9042d32017-03-17 08:50:45 +0800998 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400999 mState.mUniforms.clear();
1000 mState.mUniformLocations.clear();
1001 mState.mUniformBlocks.clear();
jchen107a20b972017-06-13 14:25:26 +08001002 mState.mActiveUniformBlockBindings.reset();
jchen10eaef1e52017-06-13 10:44:11 +08001003 mState.mAtomicCounterBuffers.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04001004 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +08001005 mState.mOutputLocations.clear();
Geoff Lange0cff192017-05-30 13:04:56 -04001006 mState.mOutputVariableTypes.clear();
Brandon Jones76746f92017-11-22 11:44:41 -08001007 mState.mDrawBufferTypeMask.reset();
Corentin Walleze7557742017-06-01 13:09:57 -04001008 mState.mActiveOutputVariables.reset();
Martin Radev4c4c8e72016-08-04 12:25:34 +03001009 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -05001010 mState.mSamplerBindings.clear();
jchen10eaef1e52017-06-13 10:44:11 +08001011 mState.mImageBindings.clear();
Martin Radev7cf61662017-07-26 17:10:53 +03001012 mState.mNumViews = -1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001013
Geoff Lang7dd2e102014-11-10 15:19:26 -05001014 mValidated = false;
1015
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001016 mLinked = false;
1017}
1018
Geoff Lange1a27752015-10-05 13:16:04 -04001019bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +00001020{
1021 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001022}
1023
Jamie Madilla2c74982016-12-12 11:20:42 -05001024Error Program::loadBinary(const Context *context,
1025 GLenum binaryFormat,
1026 const void *binary,
1027 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001028{
Jamie Madill6c1f6712017-02-14 19:08:04 -05001029 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001030
Geoff Lang7dd2e102014-11-10 15:19:26 -05001031#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +08001032 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001033#else
Geoff Langc46cc2f2015-10-01 17:16:20 -04001034 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
1035 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001036 {
Jamie Madillf6113162015-05-07 11:49:21 -04001037 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +08001038 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001039 }
1040
Jamie Madill4f86d052017-06-05 12:59:26 -04001041 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
1042 ANGLE_TRY_RESULT(
1043 MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
Jamie Madill32447362017-06-28 14:53:52 -04001044
1045 // Currently we require the full shader text to compute the program hash.
1046 // TODO(jmadill): Store the binary in the internal program cache.
1047
Jamie Madillb0a838b2016-11-13 20:02:12 -05001048 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -05001049#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -05001050}
1051
Jamie Madilla2c74982016-12-12 11:20:42 -05001052Error Program::saveBinary(const Context *context,
1053 GLenum *binaryFormat,
1054 void *binary,
1055 GLsizei bufSize,
1056 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001057{
1058 if (binaryFormat)
1059 {
Geoff Langc46cc2f2015-10-01 17:16:20 -04001060 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061 }
1062
Jamie Madill4f86d052017-06-05 12:59:26 -04001063 angle::MemoryBuffer memoryBuf;
1064 MemoryProgramCache::Serialize(context, this, &memoryBuf);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001065
Jamie Madill4f86d052017-06-05 12:59:26 -04001066 GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
1067 const uint8_t *streamState = memoryBuf.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001068
1069 if (streamLength > bufSize)
1070 {
1071 if (length)
1072 {
1073 *length = 0;
1074 }
1075
1076 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1077 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1078 // sizes and then copy it.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001079 return InternalError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001080 }
1081
1082 if (binary)
1083 {
1084 char *ptr = reinterpret_cast<char*>(binary);
1085
Jamie Madill48ef11b2016-04-27 15:21:52 -04001086 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001087 ptr += streamLength;
1088
1089 ASSERT(ptr - streamLength == binary);
1090 }
1091
1092 if (length)
1093 {
1094 *length = streamLength;
1095 }
1096
He Yunchaoacd18982017-01-04 10:46:42 +08001097 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001098}
1099
Jamie Madillffe00c02017-06-27 16:26:55 -04001100GLint Program::getBinaryLength(const Context *context) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001101{
1102 GLint length;
Jamie Madillffe00c02017-06-27 16:26:55 -04001103 Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001104 if (error.isError())
1105 {
1106 return 0;
1107 }
1108
1109 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001110}
1111
Geoff Langc5629752015-12-07 16:29:04 -05001112void Program::setBinaryRetrievableHint(bool retrievable)
1113{
1114 // TODO(jmadill) : replace with dirty bits
1115 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001116 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001117}
1118
1119bool Program::getBinaryRetrievableHint() const
1120{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001121 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001122}
1123
Yunchao He61afff12017-03-14 15:34:03 +08001124void Program::setSeparable(bool separable)
1125{
1126 // TODO(yunchao) : replace with dirty bits
1127 if (mState.mSeparable != separable)
1128 {
1129 mProgram->setSeparable(separable);
1130 mState.mSeparable = separable;
1131 }
1132}
1133
1134bool Program::isSeparable() const
1135{
1136 return mState.mSeparable;
1137}
1138
Jamie Madill6c1f6712017-02-14 19:08:04 -05001139void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001140{
1141 mRefCount--;
1142
1143 if (mRefCount == 0 && mDeleteStatus)
1144 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001145 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001146 }
1147}
1148
1149void Program::addRef()
1150{
1151 mRefCount++;
1152}
1153
1154unsigned int Program::getRefCount() const
1155{
1156 return mRefCount;
1157}
1158
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001159int Program::getInfoLogLength() const
1160{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001161 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001162}
1163
Geoff Lange1a27752015-10-05 13:16:04 -04001164void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001165{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001166 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001167}
1168
Geoff Lange1a27752015-10-05 13:16:04 -04001169void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001170{
1171 int total = 0;
1172
Martin Radev4c4c8e72016-08-04 12:25:34 +03001173 if (mState.mAttachedComputeShader)
1174 {
1175 if (total < maxCount)
1176 {
1177 shaders[total] = mState.mAttachedComputeShader->getHandle();
1178 total++;
1179 }
1180 }
1181
Jamie Madill48ef11b2016-04-27 15:21:52 -04001182 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001183 {
1184 if (total < maxCount)
1185 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001186 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001187 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001188 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001189 }
1190
Jamie Madill48ef11b2016-04-27 15:21:52 -04001191 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001192 {
1193 if (total < maxCount)
1194 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001195 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001196 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001197 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001198 }
1199
Jiawei Shao89be29a2017-11-06 14:36:45 +08001200 if (mState.mAttachedGeometryShader)
1201 {
1202 if (total < maxCount)
1203 {
1204 shaders[total] = mState.mAttachedGeometryShader->getHandle();
1205 total++;
1206 }
1207 }
1208
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001209 if (count)
1210 {
1211 *count = total;
1212 }
1213}
1214
Geoff Lange1a27752015-10-05 13:16:04 -04001215GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001216{
Jamie Madill34ca4f52017-06-13 11:49:39 -04001217 return mState.getAttributeLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001218}
1219
Jamie Madill63805b42015-08-25 13:17:39 -04001220bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001221{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001222 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1223 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001224}
1225
jchen10fd7c3b52017-03-21 15:36:03 +08001226void Program::getActiveAttribute(GLuint index,
1227 GLsizei bufsize,
1228 GLsizei *length,
1229 GLint *size,
1230 GLenum *type,
1231 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001232{
Jamie Madillc349ec02015-08-21 16:53:12 -04001233 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001234 {
1235 if (bufsize > 0)
1236 {
1237 name[0] = '\0';
1238 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001239
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001240 if (length)
1241 {
1242 *length = 0;
1243 }
1244
1245 *type = GL_NONE;
1246 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001247 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001248 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001249
jchen1036e120e2017-03-14 14:53:58 +08001250 ASSERT(index < mState.mAttributes.size());
1251 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001252
1253 if (bufsize > 0)
1254 {
jchen10fd7c3b52017-03-21 15:36:03 +08001255 CopyStringToBuffer(name, attrib.name, bufsize, length);
Jamie Madillc349ec02015-08-21 16:53:12 -04001256 }
1257
1258 // Always a single 'type' instance
1259 *size = 1;
1260 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001261}
1262
Geoff Lange1a27752015-10-05 13:16:04 -04001263GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001264{
Jamie Madillc349ec02015-08-21 16:53:12 -04001265 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001266 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001267 return 0;
1268 }
1269
jchen1036e120e2017-03-14 14:53:58 +08001270 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001271}
1272
Geoff Lange1a27752015-10-05 13:16:04 -04001273GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001274{
Jamie Madillc349ec02015-08-21 16:53:12 -04001275 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001276 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001277 return 0;
1278 }
1279
1280 size_t maxLength = 0;
1281
Jamie Madill48ef11b2016-04-27 15:21:52 -04001282 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001283 {
jchen1036e120e2017-03-14 14:53:58 +08001284 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001285 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001286
Jamie Madillc349ec02015-08-21 16:53:12 -04001287 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001288}
1289
jchen1015015f72017-03-16 13:54:21 +08001290GLuint Program::getInputResourceIndex(const GLchar *name) const
1291{
Olli Etuahod2551232017-10-26 20:03:33 +03001292 return GetResourceIndexFromName(mState.mAttributes, std::string(name));
jchen1015015f72017-03-16 13:54:21 +08001293}
1294
1295GLuint Program::getOutputResourceIndex(const GLchar *name) const
1296{
1297 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1298}
1299
jchen10fd7c3b52017-03-21 15:36:03 +08001300size_t Program::getOutputResourceCount() const
1301{
1302 return (mLinked ? mState.mOutputVariables.size() : 0);
1303}
1304
jchen10baf5d942017-08-28 20:45:48 +08001305template <typename T>
1306void Program::getResourceName(GLuint index,
1307 const std::vector<T> &resources,
1308 GLsizei bufSize,
1309 GLsizei *length,
1310 GLchar *name) const
jchen10fd7c3b52017-03-21 15:36:03 +08001311{
1312 if (length)
1313 {
1314 *length = 0;
1315 }
1316
1317 if (!mLinked)
1318 {
1319 if (bufSize > 0)
1320 {
1321 name[0] = '\0';
1322 }
1323 return;
1324 }
jchen10baf5d942017-08-28 20:45:48 +08001325 ASSERT(index < resources.size());
1326 const auto &resource = resources[index];
jchen10fd7c3b52017-03-21 15:36:03 +08001327
1328 if (bufSize > 0)
1329 {
Olli Etuahod2551232017-10-26 20:03:33 +03001330 CopyStringToBuffer(name, resource.name, bufSize, length);
jchen10fd7c3b52017-03-21 15:36:03 +08001331 }
1332}
1333
jchen10baf5d942017-08-28 20:45:48 +08001334void Program::getInputResourceName(GLuint index,
1335 GLsizei bufSize,
1336 GLsizei *length,
1337 GLchar *name) const
1338{
1339 getResourceName(index, mState.mAttributes, bufSize, length, name);
1340}
1341
1342void Program::getOutputResourceName(GLuint index,
1343 GLsizei bufSize,
1344 GLsizei *length,
1345 GLchar *name) const
1346{
1347 getResourceName(index, mState.mOutputVariables, bufSize, length, name);
1348}
1349
1350void Program::getUniformResourceName(GLuint index,
1351 GLsizei bufSize,
1352 GLsizei *length,
1353 GLchar *name) const
1354{
1355 getResourceName(index, mState.mUniforms, bufSize, length, name);
1356}
1357
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001358void Program::getBufferVariableResourceName(GLuint index,
1359 GLsizei bufSize,
1360 GLsizei *length,
1361 GLchar *name) const
1362{
1363 getResourceName(index, mState.mBufferVariables, bufSize, length, name);
1364}
1365
jchen10880683b2017-04-12 16:21:55 +08001366const sh::Attribute &Program::getInputResource(GLuint index) const
1367{
1368 ASSERT(index < mState.mAttributes.size());
1369 return mState.mAttributes[index];
1370}
1371
1372const sh::OutputVariable &Program::getOutputResource(GLuint index) const
1373{
1374 ASSERT(index < mState.mOutputVariables.size());
1375 return mState.mOutputVariables[index];
1376}
1377
Geoff Lang7dd2e102014-11-10 15:19:26 -05001378GLint Program::getFragDataLocation(const std::string &name) const
1379{
Olli Etuahod2551232017-10-26 20:03:33 +03001380 return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001381}
1382
Geoff Lange1a27752015-10-05 13:16:04 -04001383void Program::getActiveUniform(GLuint index,
1384 GLsizei bufsize,
1385 GLsizei *length,
1386 GLint *size,
1387 GLenum *type,
1388 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001389{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001391 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001392 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001393 ASSERT(index < mState.mUniforms.size());
1394 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001395
1396 if (bufsize > 0)
1397 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001398 std::string string = uniform.name;
jchen10fd7c3b52017-03-21 15:36:03 +08001399 CopyStringToBuffer(name, string, bufsize, length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 }
1401
Olli Etuaho465835d2017-09-26 13:34:10 +03001402 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001403 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001404 }
1405 else
1406 {
1407 if (bufsize > 0)
1408 {
1409 name[0] = '\0';
1410 }
1411
1412 if (length)
1413 {
1414 *length = 0;
1415 }
1416
1417 *size = 0;
1418 *type = GL_NONE;
1419 }
1420}
1421
Geoff Lange1a27752015-10-05 13:16:04 -04001422GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001423{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001424 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001425 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001426 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001427 }
1428 else
1429 {
1430 return 0;
1431 }
1432}
1433
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001434size_t Program::getActiveBufferVariableCount() const
1435{
1436 return mLinked ? mState.mBufferVariables.size() : 0;
1437}
1438
Geoff Lange1a27752015-10-05 13:16:04 -04001439GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001440{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001441 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001442
1443 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001444 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001445 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001447 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001448 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001449 size_t length = uniform.name.length() + 1u;
1450 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001451 {
1452 length += 3; // Counting in "[0]".
1453 }
1454 maxLength = std::max(length, maxLength);
1455 }
1456 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001457 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001458
Jamie Madill62d31cb2015-09-11 13:25:51 -04001459 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001460}
1461
Geoff Lang7dd2e102014-11-10 15:19:26 -05001462bool Program::isValidUniformLocation(GLint location) const
1463{
Jamie Madille2e406c2016-06-02 13:04:10 -04001464 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001465 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
Jamie Madillfb997ec2017-09-20 15:44:27 -04001466 mState.mUniformLocations[static_cast<size_t>(location)].used());
Geoff Langd8605522016-04-13 10:19:12 -04001467}
1468
Jamie Madill62d31cb2015-09-11 13:25:51 -04001469const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001470{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001471 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001472 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473}
1474
Jamie Madillac4e9c32017-01-13 14:07:12 -05001475const VariableLocation &Program::getUniformLocation(GLint location) const
1476{
1477 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1478 return mState.mUniformLocations[location];
1479}
1480
1481const std::vector<VariableLocation> &Program::getUniformLocations() const
1482{
1483 return mState.mUniformLocations;
1484}
1485
1486const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1487{
1488 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1489 return mState.mUniforms[index];
1490}
1491
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001492const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const
1493{
1494 ASSERT(index < static_cast<size_t>(mState.mBufferVariables.size()));
1495 return mState.mBufferVariables[index];
1496}
1497
Jamie Madill62d31cb2015-09-11 13:25:51 -04001498GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001499{
Olli Etuahod2551232017-10-26 20:03:33 +03001500 return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001501}
1502
Jamie Madill62d31cb2015-09-11 13:25:51 -04001503GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504{
Jamie Madille7d84322017-01-10 18:21:59 -05001505 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001506}
1507
1508void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1509{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001510 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1511 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001512 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001513}
1514
1515void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1516{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001517 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1518 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001519 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001520}
1521
1522void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1523{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001524 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1525 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001526 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
1529void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1530{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001531 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1532 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001533 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001534}
1535
Jamie Madill81c2e252017-09-09 23:32:46 -04001536Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001537{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001538 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1539 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
1540
Jamie Madill81c2e252017-09-09 23:32:46 -04001541 mProgram->setUniform1iv(location, clampedCount, v);
1542
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001543 if (mState.isSamplerUniformIndex(locationInfo.index))
1544 {
1545 updateSamplerUniform(locationInfo, clampedCount, v);
Jamie Madill81c2e252017-09-09 23:32:46 -04001546 return SetUniformResult::SamplerChanged;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001547 }
1548
Jamie Madill81c2e252017-09-09 23:32:46 -04001549 return SetUniformResult::NoSamplerChange;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001550}
1551
1552void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1553{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001554 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1555 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001556 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557}
1558
1559void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1560{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001561 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1562 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001563 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564}
1565
1566void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1567{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001568 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1569 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001570 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001571}
1572
1573void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1574{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001575 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1576 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001577 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001578}
1579
1580void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1581{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001582 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1583 GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001584 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001585}
1586
1587void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1588{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001589 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1590 GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001591 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001592}
1593
1594void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1595{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001596 const VariableLocation &locationInfo = mState.mUniformLocations[location];
1597 GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001598 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001599}
1600
1601void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1602{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001603 GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001604 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001605}
1606
1607void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1608{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001609 GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001610 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001611}
1612
1613void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1614{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001615 GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001616 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001617}
1618
1619void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1620{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001621 GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001622 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001623}
1624
1625void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1626{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001627 GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001628 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001629}
1630
1631void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1632{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001633 GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001634 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001635}
1636
1637void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1638{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001639 GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001640 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001641}
1642
1643void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1644{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001645 GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001646 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647}
1648
1649void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1650{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04001651 GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v);
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001652 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001653}
1654
Jamie Madill54164b02017-08-28 15:17:37 -04001655void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656{
Jamie Madill54164b02017-08-28 15:17:37 -04001657 const auto &uniformLocation = mState.getUniformLocations()[location];
1658 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1659
1660 GLenum nativeType = gl::VariableComponentType(uniform.type);
1661 if (nativeType == GL_FLOAT)
1662 {
1663 mProgram->getUniformfv(context, location, v);
1664 }
1665 else
1666 {
1667 getUniformInternal(context, v, location, nativeType,
1668 gl::VariableComponentCount(uniform.type));
1669 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001670}
1671
Jamie Madill54164b02017-08-28 15:17:37 -04001672void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001673{
Jamie Madill54164b02017-08-28 15:17:37 -04001674 const auto &uniformLocation = mState.getUniformLocations()[location];
1675 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1676
1677 GLenum nativeType = gl::VariableComponentType(uniform.type);
1678 if (nativeType == GL_INT || nativeType == GL_BOOL)
1679 {
1680 mProgram->getUniformiv(context, location, v);
1681 }
1682 else
1683 {
1684 getUniformInternal(context, v, location, nativeType,
1685 gl::VariableComponentCount(uniform.type));
1686 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001687}
1688
Jamie Madill54164b02017-08-28 15:17:37 -04001689void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001690{
Jamie Madill54164b02017-08-28 15:17:37 -04001691 const auto &uniformLocation = mState.getUniformLocations()[location];
1692 const auto &uniform = mState.getUniforms()[uniformLocation.index];
1693
1694 GLenum nativeType = gl::VariableComponentType(uniform.type);
1695 if (nativeType == GL_UNSIGNED_INT)
1696 {
1697 mProgram->getUniformuiv(context, location, v);
1698 }
1699 else
1700 {
1701 getUniformInternal(context, v, location, nativeType,
1702 gl::VariableComponentCount(uniform.type));
1703 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001704}
1705
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001706void Program::flagForDeletion()
1707{
1708 mDeleteStatus = true;
1709}
1710
1711bool Program::isFlaggedForDeletion() const
1712{
1713 return mDeleteStatus;
1714}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001715
Brandon Jones43a53e22014-08-28 16:23:22 -07001716void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001717{
1718 mInfoLog.reset();
1719
Geoff Lang7dd2e102014-11-10 15:19:26 -05001720 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001721 {
Geoff Lang92019432017-11-20 13:09:34 -05001722 mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001723 }
1724 else
1725 {
Jamie Madillf6113162015-05-07 11:49:21 -04001726 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001727 }
1728}
1729
Geoff Lang7dd2e102014-11-10 15:19:26 -05001730bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1731{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001732 // Skip cache if we're using an infolog, so we get the full error.
1733 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1734 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1735 {
1736 return mCachedValidateSamplersResult.value();
1737 }
1738
1739 if (mTextureUnitTypesCache.empty())
1740 {
1741 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1742 }
1743 else
1744 {
1745 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1746 }
1747
1748 // if any two active samplers in a program are of different types, but refer to the same
1749 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1750 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001751 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001752 {
Jamie Madill54164b02017-08-28 15:17:37 -04001753 if (samplerBinding.unreferenced)
1754 continue;
1755
Jamie Madille7d84322017-01-10 18:21:59 -05001756 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001757
Jamie Madille7d84322017-01-10 18:21:59 -05001758 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001759 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001760 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1761 {
1762 if (infoLog)
1763 {
1764 (*infoLog) << "Sampler uniform (" << textureUnit
1765 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1766 << caps.maxCombinedTextureImageUnits << ")";
1767 }
1768
1769 mCachedValidateSamplersResult = false;
1770 return false;
1771 }
1772
1773 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1774 {
1775 if (textureType != mTextureUnitTypesCache[textureUnit])
1776 {
1777 if (infoLog)
1778 {
1779 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1780 "image unit ("
1781 << textureUnit << ").";
1782 }
1783
1784 mCachedValidateSamplersResult = false;
1785 return false;
1786 }
1787 }
1788 else
1789 {
1790 mTextureUnitTypesCache[textureUnit] = textureType;
1791 }
1792 }
1793 }
1794
1795 mCachedValidateSamplersResult = true;
1796 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001797}
1798
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001799bool Program::isValidated() const
1800{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001801 return mValidated;
1802}
1803
Geoff Lange1a27752015-10-05 13:16:04 -04001804GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001805{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001806 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001807}
1808
jchen1058f67be2017-10-27 08:59:27 +08001809GLuint Program::getActiveAtomicCounterBufferCount() const
1810{
1811 return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
1812}
1813
Jiajia Qin729b2c62017-08-14 09:36:11 +08001814GLuint Program::getActiveShaderStorageBlockCount() const
1815{
1816 return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
1817}
1818
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001819void Program::getActiveUniformBlockName(const GLuint blockIndex,
1820 GLsizei bufSize,
1821 GLsizei *length,
1822 GLchar *blockName) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001823{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001824 GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName);
1825}
Geoff Lang7dd2e102014-11-10 15:19:26 -05001826
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001827void Program::getActiveShaderStorageBlockName(const GLuint blockIndex,
1828 GLsizei bufSize,
1829 GLsizei *length,
1830 GLchar *blockName) const
1831{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001832
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001833 GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001834}
1835
Geoff Lange1a27752015-10-05 13:16:04 -04001836GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001837{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001838 int maxLength = 0;
1839
1840 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001841 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001842 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001843 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1844 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001845 const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001846 if (!uniformBlock.name.empty())
1847 {
jchen10af713a22017-04-19 09:10:56 +08001848 int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
1849 maxLength = std::max(length + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001850 }
1851 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001852 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001853
1854 return maxLength;
1855}
1856
Geoff Lange1a27752015-10-05 13:16:04 -04001857GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001858{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001859 return GetInterfaceBlockIndex(mState.mUniformBlocks, name);
1860}
Jamie Madill62d31cb2015-09-11 13:25:51 -04001861
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001862GLuint Program::getShaderStorageBlockIndex(const std::string &name) const
1863{
1864 return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001865}
1866
Jiajia Qin729b2c62017-08-14 09:36:11 +08001867const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001868{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001869 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1870 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001871}
1872
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001873const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const
1874{
1875 ASSERT(index < static_cast<GLuint>(mState.mShaderStorageBlocks.size()));
1876 return mState.mShaderStorageBlocks[index];
1877}
1878
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001879void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1880{
jchen107a20b972017-06-13 14:25:26 +08001881 mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001882 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001883 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001884}
1885
1886GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1887{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001888 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001889}
1890
Jiajia Qin729b2c62017-08-14 09:36:11 +08001891GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
1892{
1893 return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
1894}
1895
Geoff Lang48dcae72014-02-05 16:28:24 -05001896void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1897{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001898 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001899 for (GLsizei i = 0; i < count; i++)
1900 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001901 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001902 }
1903
Jamie Madill48ef11b2016-04-27 15:21:52 -04001904 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001905}
1906
1907void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1908{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001909 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001910 {
jchen10a9042d32017-03-17 08:50:45 +08001911 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
1912 const auto &var = mState.mLinkedTransformFeedbackVaryings[index];
1913 std::string varName = var.nameWithArrayIndex();
1914 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
Geoff Lang48dcae72014-02-05 16:28:24 -05001915 if (length)
1916 {
1917 *length = lastNameIdx;
1918 }
1919 if (size)
1920 {
jchen10a9042d32017-03-17 08:50:45 +08001921 *size = var.size();
Geoff Lang48dcae72014-02-05 16:28:24 -05001922 }
1923 if (type)
1924 {
jchen10a9042d32017-03-17 08:50:45 +08001925 *type = var.type;
Geoff Lang48dcae72014-02-05 16:28:24 -05001926 }
1927 if (name)
1928 {
jchen10a9042d32017-03-17 08:50:45 +08001929 memcpy(name, varName.c_str(), lastNameIdx);
Geoff Lang48dcae72014-02-05 16:28:24 -05001930 name[lastNameIdx] = '\0';
1931 }
1932 }
1933}
1934
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001935GLsizei Program::getTransformFeedbackVaryingCount() const
1936{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001937 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001938 {
jchen10a9042d32017-03-17 08:50:45 +08001939 return static_cast<GLsizei>(mState.mLinkedTransformFeedbackVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001940 }
1941 else
1942 {
1943 return 0;
1944 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001945}
1946
1947GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1948{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001949 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001950 {
1951 GLsizei maxSize = 0;
jchen10a9042d32017-03-17 08:50:45 +08001952 for (const auto &var : mState.mLinkedTransformFeedbackVaryings)
Geoff Lang48dcae72014-02-05 16:28:24 -05001953 {
jchen10a9042d32017-03-17 08:50:45 +08001954 maxSize =
1955 std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
Geoff Lang48dcae72014-02-05 16:28:24 -05001956 }
1957
1958 return maxSize;
1959 }
1960 else
1961 {
1962 return 0;
1963 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001964}
1965
1966GLenum Program::getTransformFeedbackBufferMode() const
1967{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001968 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001969}
1970
Jiawei Shao73618602017-12-20 15:47:15 +08001971bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
1972{
1973 Shader *vertexShader = mState.mAttachedVertexShader;
1974 Shader *fragmentShader = mState.mAttachedFragmentShader;
1975 Shader *computeShader = mState.mAttachedComputeShader;
1976
1977 bool isComputeShaderAttached = (computeShader != nullptr);
1978 bool isGraphicsShaderAttached = (vertexShader != nullptr || fragmentShader != nullptr);
1979 // Check whether we both have a compute and non-compute shaders attached.
1980 // If there are of both types attached, then linking should fail.
1981 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
1982 if (isComputeShaderAttached == true && isGraphicsShaderAttached == true)
1983 {
1984 infoLog << "Both compute and graphics shaders are attached to the same program.";
1985 return false;
1986 }
1987
1988 if (computeShader)
1989 {
1990 if (!computeShader->isCompiled(context))
1991 {
1992 infoLog << "Attached compute shader is not compiled.";
1993 return false;
1994 }
1995 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
1996
1997 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context);
1998
1999 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
2000 // If the work group size is not specified, a link time error should occur.
2001 if (!mState.mComputeShaderLocalSize.isDeclared())
2002 {
2003 infoLog << "Work group size is not specified.";
2004 return false;
2005 }
2006 }
2007 else
2008 {
2009 if (!fragmentShader || !fragmentShader->isCompiled(context))
2010 {
2011 infoLog << "No compiled fragment shader when at least one graphics shader is attached.";
2012 return false;
2013 }
2014 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
2015
2016 if (!vertexShader || !vertexShader->isCompiled(context))
2017 {
2018 infoLog << "No compiled vertex shader when at least one graphics shader is attached.";
2019 return false;
2020 }
2021 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
2022
2023 if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context))
2024 {
2025 infoLog << "Fragment shader version does not match vertex shader version.";
2026 return false;
2027 }
2028 }
2029
2030 return true;
2031}
2032
jchen10910a3da2017-11-15 09:40:11 +08002033GLuint Program::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2034{
2035 for (GLuint tfIndex = 0; tfIndex < mState.mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2036 {
2037 const auto &tf = mState.mLinkedTransformFeedbackVaryings[tfIndex];
2038 if (tf.nameWithArrayIndex() == name)
2039 {
2040 return tfIndex;
2041 }
2042 }
2043 return GL_INVALID_INDEX;
2044}
2045
2046const TransformFeedbackVarying &Program::getTransformFeedbackVaryingResource(GLuint index) const
2047{
2048 ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size());
2049 return mState.mLinkedTransformFeedbackVaryings[index];
2050}
2051
Jamie Madillbd044ed2017-06-05 12:59:21 -04002052bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002053{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002054 Shader *vertexShader = mState.mAttachedVertexShader;
2055 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill192745a2016-12-22 15:58:21 -05002056
Jamie Madillbd044ed2017-06-05 12:59:21 -04002057 ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context));
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002058
Jiawei Shao3d404882017-10-16 13:30:48 +08002059 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getOutputVaryings(context);
2060 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getInputVaryings(context);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002061
Sami Väisänen46eaa942016-06-29 10:26:37 +03002062 std::map<GLuint, std::string> staticFragmentInputLocations;
2063
Jamie Madill4cff2472015-08-21 16:53:18 -04002064 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002065 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05002066 bool matched = false;
2067
2068 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04002069 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002070 {
2071 continue;
2072 }
2073
Jamie Madill4cff2472015-08-21 16:53:18 -04002074 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002075 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04002076 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002077 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04002078 ASSERT(!input.isBuiltIn());
Jiawei Shao73618602017-12-20 15:47:15 +08002079 if (!LinkValidateVaryings(infoLog, output.name, input, output,
Jamie Madillbd044ed2017-06-05 12:59:21 -04002080 vertexShader->getShaderVersion(context)))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002081 {
2082 return false;
2083 }
2084
Geoff Lang7dd2e102014-11-10 15:19:26 -05002085 matched = true;
2086 break;
2087 }
2088 }
2089
2090 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04002091 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002092 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04002093 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002094 return false;
2095 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03002096
2097 // Check for aliased path rendering input bindings (if any).
2098 // If more than one binding refer statically to the same
2099 // location the link must fail.
2100
2101 if (!output.staticUse)
2102 continue;
2103
2104 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
2105 if (inputBinding == -1)
2106 continue;
2107
2108 const auto it = staticFragmentInputLocations.find(inputBinding);
2109 if (it == std::end(staticFragmentInputLocations))
2110 {
2111 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
2112 }
2113 else
2114 {
2115 infoLog << "Binding for fragment input " << output.name << " conflicts with "
2116 << it->second;
2117 return false;
2118 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002119 }
2120
Jamie Madillbd044ed2017-06-05 12:59:21 -04002121 if (!linkValidateBuiltInVaryings(context, infoLog))
Yuly Novikov817232e2017-02-22 18:36:10 -05002122 {
2123 return false;
2124 }
2125
Jamie Madillada9ecc2015-08-17 12:53:37 -04002126 // TODO(jmadill): verify no unmatched vertex varyings?
2127
Geoff Lang7dd2e102014-11-10 15:19:26 -05002128 return true;
2129}
2130
Jamie Madillbd044ed2017-06-05 12:59:21 -04002131bool Program::linkUniforms(const Context *context,
2132 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002133 const ProgramBindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002134{
Olli Etuahob78707c2017-03-09 15:03:11 +00002135 UniformLinker linker(mState);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002136 if (!linker.link(context, infoLog, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002137 {
2138 return false;
2139 }
2140
Olli Etuahob78707c2017-03-09 15:03:11 +00002141 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002142
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002143 linkSamplerAndImageBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002144
jchen10eaef1e52017-06-13 10:44:11 +08002145 if (!linkAtomicCounterBuffers())
2146 {
2147 return false;
2148 }
2149
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002150 return true;
2151}
2152
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002153void Program::linkSamplerAndImageBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002154{
Jamie Madill982f6e02017-06-07 14:33:04 -04002155 unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
2156 unsigned int low = high;
2157
jchen10eaef1e52017-06-13 10:44:11 +08002158 for (auto counterIter = mState.mUniforms.rbegin();
2159 counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
2160 {
2161 --low;
2162 }
2163
2164 mState.mAtomicCounterUniformRange = RangeUI(low, high);
2165
2166 high = low;
2167
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002168 for (auto imageIter = mState.mUniforms.rbegin();
2169 imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
2170 {
2171 --low;
2172 }
2173
2174 mState.mImageUniformRange = RangeUI(low, high);
2175
2176 // If uniform is a image type, insert it into the mImageBindings array.
2177 for (unsigned int imageIndex : mState.mImageUniformRange)
2178 {
Xinghua Cao0328b572017-06-26 15:51:36 +08002179 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
2180 // cannot load values into a uniform defined as an image. if declare without a
2181 // binding qualifier, any uniform image variable (include all elements of
2182 // unbound image array) shoud be bound to unit zero.
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002183 auto &imageUniform = mState.mUniforms[imageIndex];
2184 if (imageUniform.binding == -1)
2185 {
Olli Etuaho465835d2017-09-26 13:34:10 +03002186 mState.mImageBindings.emplace_back(
2187 ImageBinding(imageUniform.getBasicTypeElementCount()));
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002188 }
Xinghua Cao0328b572017-06-26 15:51:36 +08002189 else
2190 {
2191 mState.mImageBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002192 ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
Xinghua Cao0328b572017-06-26 15:51:36 +08002193 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +08002194 }
2195
2196 high = low;
2197
2198 for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
Jamie Madill982f6e02017-06-07 14:33:04 -04002199 samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002200 {
Jamie Madill982f6e02017-06-07 14:33:04 -04002201 --low;
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002202 }
Jamie Madill982f6e02017-06-07 14:33:04 -04002203
2204 mState.mSamplerUniformRange = RangeUI(low, high);
2205
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002206 // If uniform is a sampler type, insert it into the mSamplerBindings array.
Jamie Madill982f6e02017-06-07 14:33:04 -04002207 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002208 {
2209 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2210 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
2211 mState.mSamplerBindings.emplace_back(
Olli Etuaho465835d2017-09-26 13:34:10 +03002212 SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002213 }
2214}
2215
jchen10eaef1e52017-06-13 10:44:11 +08002216bool Program::linkAtomicCounterBuffers()
2217{
2218 for (unsigned int index : mState.mAtomicCounterUniformRange)
2219 {
2220 auto &uniform = mState.mUniforms[index];
Jiajia Qin94f1e892017-11-20 12:14:32 +08002221 uniform.blockInfo.offset = uniform.offset;
2222 uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0);
2223 uniform.blockInfo.matrixStride = 0;
2224 uniform.blockInfo.isRowMajorMatrix = false;
2225
jchen10eaef1e52017-06-13 10:44:11 +08002226 bool found = false;
2227 for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
2228 ++bufferIndex)
2229 {
2230 auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
2231 if (buffer.binding == uniform.binding)
2232 {
2233 buffer.memberIndexes.push_back(index);
2234 uniform.bufferIndex = bufferIndex;
2235 found = true;
jchen1058f67be2017-10-27 08:59:27 +08002236 buffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002237 break;
2238 }
2239 }
2240 if (!found)
2241 {
2242 AtomicCounterBuffer atomicCounterBuffer;
2243 atomicCounterBuffer.binding = uniform.binding;
2244 atomicCounterBuffer.memberIndexes.push_back(index);
jchen1058f67be2017-10-27 08:59:27 +08002245 atomicCounterBuffer.unionReferencesWith(uniform);
jchen10eaef1e52017-06-13 10:44:11 +08002246 mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
2247 uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
2248 }
2249 }
2250 // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
2251 // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
2252
2253 return true;
2254}
2255
Jiawei Shao73618602017-12-20 15:47:15 +08002256bool Program::LinkValidateInterfaceBlockFields(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002257 const std::string &uniformName,
2258 const sh::InterfaceBlockField &vertexUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002259 const sh::InterfaceBlockField &fragmentUniform,
2260 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002261{
Frank Henigmanfccbac22017-05-28 17:29:26 -04002262 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
Jiawei Shao73618602017-12-20 15:47:15 +08002263 if (!LinkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002264 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002265 {
2266 return false;
2267 }
2268
2269 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
2270 {
Jamie Madillf6113162015-05-07 11:49:21 -04002271 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002272 return false;
2273 }
2274
2275 return true;
2276}
2277
Jamie Madilleb979bf2016-11-15 12:28:46 -05002278// Assigns locations to all attributes from the bindings and program locations.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002279bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002280{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002281 const ContextState &data = context->getContextState();
2282 auto *vertexShader = mState.getAttachedVertexShader();
Jamie Madilleb979bf2016-11-15 12:28:46 -05002283
Geoff Lang7dd2e102014-11-10 15:19:26 -05002284 unsigned int usedLocations = 0;
Jamie Madillbd044ed2017-06-05 12:59:21 -04002285 mState.mAttributes = vertexShader->getActiveAttributes(context);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002286 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002287
2288 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002289 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002290 {
Jamie Madillf6113162015-05-07 11:49:21 -04002291 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002292 return false;
2293 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002294
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002295 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002296
Jamie Madillc349ec02015-08-21 16:53:12 -04002297 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002298 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002299 {
Olli Etuahod2551232017-10-26 20:03:33 +03002300 // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or
2301 // structures, so we don't need to worry about adjusting their names or generating entries
2302 // for each member/element (unlike uniforms for example).
2303 ASSERT(!attribute.isArray() && !attribute.isStruct());
2304
Jamie Madilleb979bf2016-11-15 12:28:46 -05002305 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002306 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002307 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002308 attribute.location = bindingLocation;
2309 }
2310
2311 if (attribute.location != -1)
2312 {
2313 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002314 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002315
Jamie Madill63805b42015-08-25 13:17:39 -04002316 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002317 {
Jamie Madillf6113162015-05-07 11:49:21 -04002318 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002319 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002320
2321 return false;
2322 }
2323
Jamie Madill63805b42015-08-25 13:17:39 -04002324 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002325 {
Jamie Madill63805b42015-08-25 13:17:39 -04002326 const int regLocation = attribute.location + reg;
2327 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002328
2329 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002330 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002331 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002332 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002333 // TODO(jmadill): fix aliasing on ES2
2334 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002335 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002336 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002337 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002338 return false;
2339 }
2340 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002341 else
2342 {
Jamie Madill63805b42015-08-25 13:17:39 -04002343 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002344 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002345
Jamie Madill63805b42015-08-25 13:17:39 -04002346 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002347 }
2348 }
2349 }
2350
2351 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002352 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002353 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002354 // Not set by glBindAttribLocation or by location layout qualifier
2355 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002356 {
Jamie Madill63805b42015-08-25 13:17:39 -04002357 int regs = VariableRegisterCount(attribute.type);
2358 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002359
Jamie Madill63805b42015-08-25 13:17:39 -04002360 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002361 {
Jamie Madillf6113162015-05-07 11:49:21 -04002362 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002363 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002364 }
2365
Jamie Madillc349ec02015-08-21 16:53:12 -04002366 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002367 }
2368 }
2369
Brandon Jonesc405ae72017-12-06 14:15:03 -08002370 ASSERT(mState.mAttributesTypeMask.none());
2371 ASSERT(mState.mAttributesMask.none());
2372
Jamie Madill48ef11b2016-04-27 15:21:52 -04002373 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002374 {
Jamie Madill63805b42015-08-25 13:17:39 -04002375 ASSERT(attribute.location != -1);
Jamie Madillbd159f02017-10-09 19:39:06 -04002376 unsigned int regs = static_cast<unsigned int>(VariableRegisterCount(attribute.type));
Jamie Madillc349ec02015-08-21 16:53:12 -04002377
Jamie Madillbd159f02017-10-09 19:39:06 -04002378 for (unsigned int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002379 {
Jamie Madillbd159f02017-10-09 19:39:06 -04002380 unsigned int location = static_cast<unsigned int>(attribute.location) + r;
2381 mState.mActiveAttribLocationsMask.set(location);
2382 mState.mMaxActiveAttribLocation =
2383 std::max(mState.mMaxActiveAttribLocation, location + 1);
Brandon Jonesc405ae72017-12-06 14:15:03 -08002384
2385 // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
2386 if (!attribute.isBuiltIn())
2387 {
2388 mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
2389 location);
2390 mState.mAttributesMask.set(location);
2391 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 }
2393 }
2394
Geoff Lang7dd2e102014-11-10 15:19:26 -05002395 return true;
2396}
2397
Jiawei Shao73618602017-12-20 15:47:15 +08002398bool Program::ValidateGraphicsInterfaceBlocks(
Martin Radev4c4c8e72016-08-04 12:25:34 +03002399 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2400 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002401 InfoLog &infoLog,
Jiawei Shao73618602017-12-20 15:47:15 +08002402 bool webglCompatibility)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002403{
2404 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jiajia Qin729b2c62017-08-14 09:36:11 +08002405 typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
2406 InterfaceBlockMap linkedInterfaceBlocks;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002407
2408 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2409 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002410 linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002411 }
2412
Jamie Madille473dee2015-08-18 14:49:01 -04002413 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002414 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08002415 auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
2416 if (entry != linkedInterfaceBlocks.end())
Geoff Lang7dd2e102014-11-10 15:19:26 -05002417 {
2418 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
Jiawei Shao73618602017-12-20 15:47:15 +08002419 if (!AreMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002420 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002421 {
2422 return false;
2423 }
2424 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002425 // TODO(jiajia.qin@intel.com): Add
2426 // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
Martin Radev4c4c8e72016-08-04 12:25:34 +03002427 }
2428 return true;
2429}
Jamie Madille473dee2015-08-18 14:49:01 -04002430
Jiajia Qin729b2c62017-08-14 09:36:11 +08002431bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002432{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002433 const auto &caps = context->getCaps();
2434
Martin Radev4c4c8e72016-08-04 12:25:34 +03002435 if (mState.mAttachedComputeShader)
2436 {
Jamie Madillbd044ed2017-06-05 12:59:21 -04002437 Shader &computeShader = *mState.mAttachedComputeShader;
Jiajia Qin729b2c62017-08-14 09:36:11 +08002438 const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002439
Jiajia Qin729b2c62017-08-14 09:36:11 +08002440 if (!validateInterfaceBlocksCount(
2441 caps.maxComputeUniformBlocks, computeUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002442 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2443 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002444 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002445 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002446 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002447
2448 const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
2449 if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
2450 computeShaderStorageBlocks,
2451 "Compute shader shader storage block count exceeds "
2452 "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
2453 infoLog))
2454 {
2455 return false;
2456 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002457 return true;
2458 }
2459
Jamie Madillbd044ed2017-06-05 12:59:21 -04002460 Shader &vertexShader = *mState.mAttachedVertexShader;
2461 Shader &fragmentShader = *mState.mAttachedFragmentShader;
Martin Radev4c4c8e72016-08-04 12:25:34 +03002462
Jiajia Qin729b2c62017-08-14 09:36:11 +08002463 const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
2464 const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +03002465
Jiajia Qin729b2c62017-08-14 09:36:11 +08002466 if (!validateInterfaceBlocksCount(
2467 caps.maxVertexUniformBlocks, vertexUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002468 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2469 {
2470 return false;
2471 }
Jiajia Qin729b2c62017-08-14 09:36:11 +08002472 if (!validateInterfaceBlocksCount(
2473 caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002474 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2475 infoLog))
2476 {
2477
2478 return false;
2479 }
Jamie Madillbd044ed2017-06-05 12:59:21 -04002480
2481 bool webglCompatibility = context->getExtensions().webglCompatibility;
Jiawei Shao73618602017-12-20 15:47:15 +08002482 if (!ValidateGraphicsInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, infoLog,
2483 webglCompatibility))
Martin Radev4c4c8e72016-08-04 12:25:34 +03002484 {
2485 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002486 }
Jamie Madille473dee2015-08-18 14:49:01 -04002487
Jiajia Qin729b2c62017-08-14 09:36:11 +08002488 if (context->getClientVersion() >= Version(3, 1))
2489 {
2490 const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
2491 const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
2492
2493 if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
2494 vertexShaderStorageBlocks,
2495 "Vertex shader shader storage block count exceeds "
2496 "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
2497 infoLog))
2498 {
2499 return false;
2500 }
2501 if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
2502 fragmentShaderStorageBlocks,
2503 "Fragment shader shader storage block count exceeds "
2504 "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
2505 infoLog))
2506 {
2507
2508 return false;
2509 }
2510
Jiawei Shao73618602017-12-20 15:47:15 +08002511 if (!ValidateGraphicsInterfaceBlocks(vertexShaderStorageBlocks, fragmentShaderStorageBlocks,
2512 infoLog, webglCompatibility))
Jiajia Qin729b2c62017-08-14 09:36:11 +08002513 {
2514 return false;
2515 }
2516 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002517 return true;
2518}
2519
Jiawei Shao73618602017-12-20 15:47:15 +08002520bool Program::AreMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002521 const sh::InterfaceBlock &vertexInterfaceBlock,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002522 const sh::InterfaceBlock &fragmentInterfaceBlock,
Jiawei Shao73618602017-12-20 15:47:15 +08002523 bool webglCompatibility)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002524{
Jiawei Shao73618602017-12-20 15:47:15 +08002525 const char *blockName = vertexInterfaceBlock.name.c_str();
Geoff Lang7dd2e102014-11-10 15:19:26 -05002526 // validate blocks for the same member types
2527 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2528 {
Jamie Madillf6113162015-05-07 11:49:21 -04002529 infoLog << "Types for interface block '" << blockName
2530 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002531 return false;
2532 }
2533 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2534 {
Jamie Madillf6113162015-05-07 11:49:21 -04002535 infoLog << "Array sizes differ for interface block '" << blockName
2536 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002537 return false;
2538 }
jchen10af713a22017-04-19 09:10:56 +08002539 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout ||
jchen10af713a22017-04-19 09:10:56 +08002540 vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002541 {
Jamie Madillf6113162015-05-07 11:49:21 -04002542 infoLog << "Layout qualifiers differ for interface block '" << blockName
2543 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002544 return false;
2545 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002546 const unsigned int numBlockMembers =
2547 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002548 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2549 {
2550 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2551 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2552 if (vertexMember.name != fragmentMember.name)
2553 {
Jamie Madillf6113162015-05-07 11:49:21 -04002554 infoLog << "Name mismatch for field " << blockMemberIndex
2555 << " of interface block '" << blockName
2556 << "': (in vertex: '" << vertexMember.name
2557 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002558 return false;
2559 }
2560 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jiawei Shao73618602017-12-20 15:47:15 +08002561 if (!LinkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember,
Frank Henigmanfccbac22017-05-28 17:29:26 -04002562 webglCompatibility))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002563 {
2564 return false;
2565 }
2566 }
2567 return true;
2568}
2569
Jiawei Shao73618602017-12-20 15:47:15 +08002570bool Program::LinkValidateVariablesBase(InfoLog &infoLog,
2571 const std::string &variableName,
2572 const sh::ShaderVariable &vertexVariable,
2573 const sh::ShaderVariable &fragmentVariable,
2574 bool validatePrecision)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002575{
2576 if (vertexVariable.type != fragmentVariable.type)
2577 {
Jamie Madillf6113162015-05-07 11:49:21 -04002578 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002579 return false;
2580 }
Olli Etuaho465835d2017-09-26 13:34:10 +03002581 if (vertexVariable.arraySizes != fragmentVariable.arraySizes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002582 {
Jamie Madillf6113162015-05-07 11:49:21 -04002583 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002584 return false;
2585 }
2586 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2587 {
Jamie Madillf6113162015-05-07 11:49:21 -04002588 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002589 return false;
2590 }
Geoff Langbb1e7502017-06-05 16:40:09 -04002591 if (vertexVariable.structName != fragmentVariable.structName)
2592 {
2593 infoLog << "Structure names for " << variableName
2594 << " differ between vertex and fragment shaders";
2595 return false;
2596 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002597
2598 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2599 {
Jamie Madillf6113162015-05-07 11:49:21 -04002600 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002601 return false;
2602 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002603 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002604 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2605 {
2606 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2607 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2608
2609 if (vertexMember.name != fragmentMember.name)
2610 {
Jamie Madillf6113162015-05-07 11:49:21 -04002611 infoLog << "Name mismatch for field '" << memberIndex
2612 << "' of " << variableName
2613 << ": (in vertex: '" << vertexMember.name
2614 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002615 return false;
2616 }
2617
2618 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2619 vertexMember.name + "'";
2620
Jiawei Shao73618602017-12-20 15:47:15 +08002621 if (!LinkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember,
2622 validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002623 {
2624 return false;
2625 }
2626 }
2627
2628 return true;
2629}
2630
Jiawei Shao73618602017-12-20 15:47:15 +08002631bool Program::LinkValidateVaryings(InfoLog &infoLog,
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002632 const std::string &varyingName,
2633 const sh::Varying &vertexVarying,
2634 const sh::Varying &fragmentVarying,
2635 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002636{
Jiawei Shao73618602017-12-20 15:47:15 +08002637 if (!LinkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002638 {
2639 return false;
2640 }
2641
Jamie Madille9cc4692015-02-19 16:00:13 -05002642 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002643 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002644 infoLog << "Interpolation types for " << varyingName
2645 << " differ between vertex and fragment shaders.";
2646 return false;
2647 }
2648
2649 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2650 {
2651 infoLog << "Invariance for " << varyingName
2652 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002653 return false;
2654 }
2655
2656 return true;
2657}
2658
Jamie Madillbd044ed2017-06-05 12:59:21 -04002659bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const
Yuly Novikov817232e2017-02-22 18:36:10 -05002660{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002661 Shader *vertexShader = mState.mAttachedVertexShader;
2662 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jiawei Shao3d404882017-10-16 13:30:48 +08002663 const auto &vertexVaryings = vertexShader->getOutputVaryings(context);
2664 const auto &fragmentVaryings = fragmentShader->getInputVaryings(context);
Jamie Madillbd044ed2017-06-05 12:59:21 -04002665 int shaderVersion = vertexShader->getShaderVersion(context);
Yuly Novikov817232e2017-02-22 18:36:10 -05002666
2667 if (shaderVersion != 100)
2668 {
2669 // Only ESSL 1.0 has restrictions on matching input and output invariance
2670 return true;
2671 }
2672
2673 bool glPositionIsInvariant = false;
2674 bool glPointSizeIsInvariant = false;
2675 bool glFragCoordIsInvariant = false;
2676 bool glPointCoordIsInvariant = false;
2677
2678 for (const sh::Varying &varying : vertexVaryings)
2679 {
2680 if (!varying.isBuiltIn())
2681 {
2682 continue;
2683 }
2684 if (varying.name.compare("gl_Position") == 0)
2685 {
2686 glPositionIsInvariant = varying.isInvariant;
2687 }
2688 else if (varying.name.compare("gl_PointSize") == 0)
2689 {
2690 glPointSizeIsInvariant = varying.isInvariant;
2691 }
2692 }
2693
2694 for (const sh::Varying &varying : fragmentVaryings)
2695 {
2696 if (!varying.isBuiltIn())
2697 {
2698 continue;
2699 }
2700 if (varying.name.compare("gl_FragCoord") == 0)
2701 {
2702 glFragCoordIsInvariant = varying.isInvariant;
2703 }
2704 else if (varying.name.compare("gl_PointCoord") == 0)
2705 {
2706 glPointCoordIsInvariant = varying.isInvariant;
2707 }
2708 }
2709
2710 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2711 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2712 // Not requiring invariance to match is supported by:
2713 // dEQP, WebGL CTS, Nexus 5X GLES
2714 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2715 {
2716 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2717 "declared invariant.";
2718 return false;
2719 }
2720 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2721 {
2722 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2723 "declared invariant.";
2724 return false;
2725 }
2726
2727 return true;
2728}
2729
jchen10a9042d32017-03-17 08:50:45 +08002730bool Program::linkValidateTransformFeedback(const gl::Context *context,
2731 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -05002732 const ProgramMergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002733 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002734{
Geoff Lang7dd2e102014-11-10 15:19:26 -05002735
jchen108225e732017-11-14 16:29:03 +08002736 // Validate the tf names regardless of the actual program varyings.
Jamie Madillccdf74b2015-08-18 10:46:12 -04002737 std::set<std::string> uniqueNames;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002738 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002739 {
jchen10a9042d32017-03-17 08:50:45 +08002740 if (context->getClientVersion() < Version(3, 1) &&
2741 tfVaryingName.find('[') != std::string::npos)
Jamie Madill89bb70e2015-08-31 14:18:39 -04002742 {
Geoff Lang1a683462015-09-29 15:09:59 -04002743 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002744 return false;
2745 }
jchen108225e732017-11-14 16:29:03 +08002746 if (context->getClientVersion() >= Version(3, 1))
2747 {
2748 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
2749 {
2750 infoLog << "Two transform feedback varyings include the same array element ("
2751 << tfVaryingName << ").";
2752 return false;
2753 }
2754 }
2755 else
2756 {
2757 if (uniqueNames.count(tfVaryingName) > 0)
2758 {
2759 infoLog << "Two transform feedback varyings specify the same output variable ("
2760 << tfVaryingName << ").";
2761 return false;
2762 }
2763 }
2764 uniqueNames.insert(tfVaryingName);
2765 }
2766
2767 // Validate against program varyings.
2768 size_t totalComponents = 0;
2769 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
2770 {
2771 std::vector<unsigned int> subscripts;
2772 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
2773
2774 const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName);
2775 if (var == nullptr)
jchen1085c93c42017-11-12 15:36:47 +08002776 {
2777 infoLog << "Transform feedback varying " << tfVaryingName
2778 << " does not exist in the vertex shader.";
2779 return false;
2780 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002781
jchen108225e732017-11-14 16:29:03 +08002782 // Validate the matching variable.
2783 if (var->isStruct())
2784 {
2785 infoLog << "Struct cannot be captured directly (" << baseName << ").";
2786 return false;
2787 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002788
jchen108225e732017-11-14 16:29:03 +08002789 size_t elementCount = 0;
2790 size_t componentCount = 0;
2791
2792 if (var->isArray())
2793 {
2794 if (context->getClientVersion() < Version(3, 1))
2795 {
2796 infoLog << "Capture of arrays is undefined and not supported.";
2797 return false;
2798 }
2799
2800 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
2801 ASSERT(!var->isArrayOfArrays());
2802
2803 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
2804 {
2805 infoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
2806 return false;
2807 }
2808 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
2809 }
2810 else
2811 {
2812 if (!subscripts.empty())
2813 {
2814 infoLog << "Varying '" << baseName
2815 << "' is not an array to be captured by element.";
2816 return false;
2817 }
2818 elementCount = 1;
2819 }
2820
2821 // TODO(jmadill): Investigate implementation limits on D3D11
2822 componentCount = VariableComponentCount(var->type) * elementCount;
2823 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
2824 componentCount > caps.maxTransformFeedbackSeparateComponents)
2825 {
2826 infoLog << "Transform feedback varying " << tfVaryingName << " components ("
2827 << componentCount << ") exceed the maximum separate components ("
2828 << caps.maxTransformFeedbackSeparateComponents << ").";
2829 return false;
2830 }
2831
2832 totalComponents += componentCount;
2833 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
2834 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
2835 {
2836 infoLog << "Transform feedback varying total components (" << totalComponents
2837 << ") exceed the maximum interleaved components ("
2838 << caps.maxTransformFeedbackInterleavedComponents << ").";
2839 return false;
2840 }
2841 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002842 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002843}
2844
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002845bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const
2846{
2847 const std::vector<sh::Uniform> &vertexUniforms =
2848 mState.mAttachedVertexShader->getUniforms(context);
2849 const std::vector<sh::Uniform> &fragmentUniforms =
2850 mState.mAttachedFragmentShader->getUniforms(context);
2851 const std::vector<sh::Attribute> &attributes =
2852 mState.mAttachedVertexShader->getActiveAttributes(context);
2853 for (const auto &attrib : attributes)
2854 {
2855 for (const auto &uniform : vertexUniforms)
2856 {
2857 if (uniform.name == attrib.name)
2858 {
2859 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2860 return false;
2861 }
2862 }
2863 for (const auto &uniform : fragmentUniforms)
2864 {
2865 if (uniform.name == attrib.name)
2866 {
2867 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
2868 return false;
2869 }
2870 }
2871 }
2872 return true;
2873}
2874
Jamie Madill3c1da042017-11-27 18:33:40 -05002875void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002876{
2877 // Gather the linked varyings that are used for transform feedback, they should all exist.
jchen10a9042d32017-03-17 08:50:45 +08002878 mState.mLinkedTransformFeedbackVaryings.clear();
Jamie Madill48ef11b2016-04-27 15:21:52 -04002879 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002880 {
Olli Etuahoc8538042017-09-27 11:20:15 +03002881 std::vector<unsigned int> subscripts;
2882 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
jchen10a9042d32017-03-17 08:50:45 +08002883 size_t subscript = GL_INVALID_INDEX;
Olli Etuahoc8538042017-09-27 11:20:15 +03002884 if (!subscripts.empty())
2885 {
2886 subscript = subscripts.back();
2887 }
Jamie Madill192745a2016-12-22 15:58:21 -05002888 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002889 {
Jamie Madill192745a2016-12-22 15:58:21 -05002890 const sh::Varying *varying = ref.second.get();
jchen10a9042d32017-03-17 08:50:45 +08002891 if (baseName == varying->name)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002892 {
jchen10a9042d32017-03-17 08:50:45 +08002893 mState.mLinkedTransformFeedbackVaryings.emplace_back(
2894 *varying, static_cast<GLuint>(subscript));
Jamie Madillccdf74b2015-08-18 10:46:12 -04002895 break;
2896 }
jchen108225e732017-11-14 16:29:03 +08002897 else if (varying->isStruct())
2898 {
2899 const auto *field = FindShaderVarField(*varying, tfVaryingName);
2900 if (field != nullptr)
2901 {
2902 mState.mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
2903 break;
2904 }
2905 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002906 }
2907 }
2908}
2909
Jamie Madill3c1da042017-11-27 18:33:40 -05002910ProgramMergedVaryings Program::getMergedVaryings(const Context *context) const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002911{
Jamie Madill3c1da042017-11-27 18:33:40 -05002912 ProgramMergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002913
Jiawei Shao3d404882017-10-16 13:30:48 +08002914 for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002915 {
Jamie Madill192745a2016-12-22 15:58:21 -05002916 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002917 }
2918
Jiawei Shao3d404882017-10-16 13:30:48 +08002919 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002920 {
Jamie Madill192745a2016-12-22 15:58:21 -05002921 merged[varying.name].fragment = &varying;
2922 }
2923
2924 return merged;
2925}
2926
Jamie Madillbd044ed2017-06-05 12:59:21 -04002927void Program::linkOutputVariables(const Context *context)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002928{
Jamie Madillbd044ed2017-06-05 12:59:21 -04002929 Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002930 ASSERT(fragmentShader != nullptr);
2931
Geoff Lange0cff192017-05-30 13:04:56 -04002932 ASSERT(mState.mOutputVariableTypes.empty());
Corentin Walleze7557742017-06-01 13:09:57 -04002933 ASSERT(mState.mActiveOutputVariables.none());
Brandon Jones76746f92017-11-22 11:44:41 -08002934 ASSERT(mState.mDrawBufferTypeMask.none());
Geoff Lange0cff192017-05-30 13:04:56 -04002935
2936 // Gather output variable types
Jamie Madillbd044ed2017-06-05 12:59:21 -04002937 for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context))
Geoff Lange0cff192017-05-30 13:04:56 -04002938 {
2939 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
2940 outputVariable.name != "gl_FragData")
2941 {
2942 continue;
2943 }
2944
2945 unsigned int baseLocation =
2946 (outputVariable.location == -1 ? 0u
2947 : static_cast<unsigned int>(outputVariable.location));
Olli Etuaho465835d2017-09-26 13:34:10 +03002948
2949 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
2950 // structures, so we may use getBasicTypeElementCount().
2951 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
2952 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Geoff Lange0cff192017-05-30 13:04:56 -04002953 {
2954 const unsigned int location = baseLocation + elementIndex;
2955 if (location >= mState.mOutputVariableTypes.size())
2956 {
2957 mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
2958 }
Corentin Walleze7557742017-06-01 13:09:57 -04002959 ASSERT(location < mState.mActiveOutputVariables.size());
2960 mState.mActiveOutputVariables.set(location);
Geoff Lange0cff192017-05-30 13:04:56 -04002961 mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
Brandon Jones76746f92017-11-22 11:44:41 -08002962 mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
Geoff Lange0cff192017-05-30 13:04:56 -04002963 }
2964 }
2965
Jamie Madill80a6fc02015-08-21 16:53:16 -04002966 // Skip this step for GLES2 shaders.
Jamie Madillbd044ed2017-06-05 12:59:21 -04002967 if (fragmentShader->getShaderVersion(context) == 100)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002968 return;
2969
Jamie Madillbd044ed2017-06-05 12:59:21 -04002970 mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002971 // TODO(jmadill): any caps validation here?
2972
jchen1015015f72017-03-16 13:54:21 +08002973 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002974 outputVariableIndex++)
2975 {
jchen1015015f72017-03-16 13:54:21 +08002976 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002977
Olli Etuahod2551232017-10-26 20:03:33 +03002978 if (outputVariable.isArray())
2979 {
2980 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
2981 // Resources and including [0] at the end of array variable names.
2982 mState.mOutputVariables[outputVariableIndex].name += "[0]";
2983 mState.mOutputVariables[outputVariableIndex].mappedName += "[0]";
2984 }
2985
Jamie Madill80a6fc02015-08-21 16:53:16 -04002986 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2987 if (outputVariable.isBuiltIn())
2988 continue;
2989
2990 // Since multiple output locations must be specified, use 0 for non-specified locations.
Olli Etuahod2551232017-10-26 20:03:33 +03002991 unsigned int baseLocation =
2992 (outputVariable.location == -1 ? 0u
2993 : static_cast<unsigned int>(outputVariable.location));
Jamie Madill80a6fc02015-08-21 16:53:16 -04002994
Olli Etuaho465835d2017-09-26 13:34:10 +03002995 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
2996 // structures, so we may use getBasicTypeElementCount().
2997 unsigned int elementCount = outputVariable.getBasicTypeElementCount();
2998 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
Jamie Madill80a6fc02015-08-21 16:53:16 -04002999 {
Olli Etuahod2551232017-10-26 20:03:33 +03003000 const unsigned int location = baseLocation + elementIndex;
3001 if (location >= mState.mOutputLocations.size())
3002 {
3003 mState.mOutputLocations.resize(location + 1);
3004 }
3005 ASSERT(!mState.mOutputLocations.at(location).used());
Olli Etuahoc8538042017-09-27 11:20:15 +03003006 if (outputVariable.isArray())
3007 {
3008 mState.mOutputLocations[location] =
3009 VariableLocation(elementIndex, outputVariableIndex);
3010 }
3011 else
3012 {
3013 VariableLocation locationInfo;
3014 locationInfo.index = outputVariableIndex;
3015 mState.mOutputLocations[location] = locationInfo;
3016 }
Jamie Madill80a6fc02015-08-21 16:53:16 -04003017 }
3018 }
3019}
Jamie Madill62d31cb2015-09-11 13:25:51 -04003020
Olli Etuaho48fed632017-03-16 12:05:30 +00003021void Program::setUniformValuesFromBindingQualifiers()
3022{
Jamie Madill982f6e02017-06-07 14:33:04 -04003023 for (unsigned int samplerIndex : mState.mSamplerUniformRange)
Olli Etuaho48fed632017-03-16 12:05:30 +00003024 {
3025 const auto &samplerUniform = mState.mUniforms[samplerIndex];
3026 if (samplerUniform.binding != -1)
3027 {
Olli Etuahod2551232017-10-26 20:03:33 +03003028 GLint location = getUniformLocation(samplerUniform.name);
Olli Etuaho48fed632017-03-16 12:05:30 +00003029 ASSERT(location != -1);
3030 std::vector<GLint> boundTextureUnits;
Olli Etuaho465835d2017-09-26 13:34:10 +03003031 for (unsigned int elementIndex = 0;
3032 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
Olli Etuaho48fed632017-03-16 12:05:30 +00003033 {
3034 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
3035 }
3036 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
3037 boundTextureUnits.data());
3038 }
3039 }
3040}
3041
Jamie Madill6db1c2e2017-11-08 09:17:40 -05003042void Program::initInterfaceBlockBindings()
Jamie Madill62d31cb2015-09-11 13:25:51 -04003043{
jchen10af713a22017-04-19 09:10:56 +08003044 // Set initial bindings from shader.
3045 for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
3046 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08003047 InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
jchen10af713a22017-04-19 09:10:56 +08003048 bindUniformBlock(blockIndex, uniformBlock.binding);
3049 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003050}
3051
Jamie Madille7d84322017-01-10 18:21:59 -05003052void Program::updateSamplerUniform(const VariableLocation &locationInfo,
Jamie Madille7d84322017-01-10 18:21:59 -05003053 GLsizei clampedCount,
3054 const GLint *v)
3055{
Jamie Madill81c2e252017-09-09 23:32:46 -04003056 ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
3057 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
3058 std::vector<GLuint> *boundTextureUnits =
3059 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
Jamie Madille7d84322017-01-10 18:21:59 -05003060
Olli Etuaho1734e172017-10-27 15:30:27 +03003061 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
Jamie Madilld68248b2017-09-11 14:34:14 -04003062
3063 // Invalidate the validation cache.
Jamie Madill81c2e252017-09-09 23:32:46 -04003064 mCachedValidateSamplersResult.reset();
Jamie Madille7d84322017-01-10 18:21:59 -05003065}
3066
3067template <typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003068GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
3069 GLsizei count,
3070 int vectorSize,
Jamie Madille7d84322017-01-10 18:21:59 -05003071 const T *v)
3072{
Jamie Madill134f93d2017-08-31 17:11:00 -04003073 if (count == 1)
3074 return 1;
3075
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003076 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04003077
Corentin Wallez15ac5342016-11-03 17:06:39 -04003078 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3079 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003080 unsigned int remainingElements =
3081 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003082 GLsizei maxElementCount =
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003083 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003084
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003085 if (count * vectorSize > maxElementCount)
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003086 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003087 return maxElementCount / vectorSize;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003088 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05003089
3090 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003091}
3092
3093template <size_t cols, size_t rows, typename T>
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003094GLsizei Program::clampMatrixUniformCount(GLint location,
3095 GLsizei count,
3096 GLboolean transpose,
3097 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003098{
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003099 const VariableLocation &locationInfo = mState.mUniformLocations[location];
3100
Jamie Madill62d31cb2015-09-11 13:25:51 -04003101 if (!transpose)
3102 {
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003103 return clampUniformCount(locationInfo, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003104 }
3105
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003106 const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index];
Corentin Wallez15ac5342016-11-03 17:06:39 -04003107
3108 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
3109 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
Olli Etuaho465835d2017-09-26 13:34:10 +03003110 unsigned int remainingElements =
3111 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
Jamie Madillbe5e2ec2017-08-31 13:28:28 -04003112 return std::min(count, static_cast<GLsizei>(remainingElements));
Jamie Madill62d31cb2015-09-11 13:25:51 -04003113}
3114
Jamie Madill54164b02017-08-28 15:17:37 -04003115// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3116// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
Jamie Madill62d31cb2015-09-11 13:25:51 -04003117template <typename DestT>
Jamie Madill54164b02017-08-28 15:17:37 -04003118void Program::getUniformInternal(const Context *context,
3119 DestT *dataOut,
3120 GLint location,
3121 GLenum nativeType,
3122 int components) const
Jamie Madill62d31cb2015-09-11 13:25:51 -04003123{
Jamie Madill54164b02017-08-28 15:17:37 -04003124 switch (nativeType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04003125 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003126 case GL_BOOL:
Jamie Madill54164b02017-08-28 15:17:37 -04003127 {
3128 GLint tempValue[16] = {0};
3129 mProgram->getUniformiv(context, location, tempValue);
3130 UniformStateQueryCastLoop<GLboolean>(
3131 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003132 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003133 }
3134 case GL_INT:
3135 {
3136 GLint tempValue[16] = {0};
3137 mProgram->getUniformiv(context, location, tempValue);
3138 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3139 components);
3140 break;
3141 }
3142 case GL_UNSIGNED_INT:
3143 {
3144 GLuint tempValue[16] = {0};
3145 mProgram->getUniformuiv(context, location, tempValue);
3146 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3147 components);
3148 break;
3149 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003150 case GL_FLOAT:
Jamie Madill54164b02017-08-28 15:17:37 -04003151 {
3152 GLfloat tempValue[16] = {0};
3153 mProgram->getUniformfv(context, location, tempValue);
3154 UniformStateQueryCastLoop<GLfloat>(
3155 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
Jamie Madill62d31cb2015-09-11 13:25:51 -04003156 break;
Jamie Madill54164b02017-08-28 15:17:37 -04003157 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04003158 default:
3159 UNREACHABLE();
Jamie Madill54164b02017-08-28 15:17:37 -04003160 break;
Jamie Madill62d31cb2015-09-11 13:25:51 -04003161 }
3162}
Jamie Madilla4595b82017-01-11 17:36:34 -05003163
3164bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
3165{
3166 // Must be called after samplers are validated.
3167 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
3168
3169 for (const auto &binding : mState.mSamplerBindings)
3170 {
3171 GLenum textureType = binding.textureType;
3172 for (const auto &unit : binding.boundTextureUnits)
3173 {
3174 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
3175 if (programTextureID == textureID)
3176 {
3177 // TODO(jmadill): Check for appropriate overlap.
3178 return true;
3179 }
3180 }
3181 }
3182
3183 return false;
3184}
3185
Jamie Madilla2c74982016-12-12 11:20:42 -05003186} // namespace gl