blob: 37341769d01334fb82a6b904c98390cb0a52c6d9 [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 Madill80a6fc02015-08-21 16:53:16 -040014#include "common/BitSetIterator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
17#include "common/utilities.h"
18#include "common/version.h"
19#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill437d2662014-12-05 14:23:35 -050021#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050022#include "libANGLE/features.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040023#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill192745a2016-12-22 15:58:21 -050025#include "libANGLE/VaryingPacking.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040026#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040027#include "libANGLE/Uniform.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000028#include "libANGLE/UniformLinker.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050029
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030namespace gl
31{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000032
Geoff Lang7dd2e102014-11-10 15:19:26 -050033namespace
34{
35
Jamie Madill62d31cb2015-09-11 13:25:51 -040036void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
37{
38 stream->writeInt(var.type);
39 stream->writeInt(var.precision);
40 stream->writeString(var.name);
41 stream->writeString(var.mappedName);
42 stream->writeInt(var.arraySize);
43 stream->writeInt(var.staticUse);
44 stream->writeString(var.structName);
45 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050046}
47
Jamie Madill62d31cb2015-09-11 13:25:51 -040048void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
49{
50 var->type = stream->readInt<GLenum>();
51 var->precision = stream->readInt<GLenum>();
52 var->name = stream->readString();
53 var->mappedName = stream->readString();
54 var->arraySize = stream->readInt<unsigned int>();
55 var->staticUse = stream->readBool();
56 var->structName = stream->readString();
57}
58
Jamie Madill62d31cb2015-09-11 13:25:51 -040059// This simplified cast function doesn't need to worry about advanced concepts like
60// depth range values, or casting to bool.
61template <typename DestT, typename SrcT>
62DestT UniformStateQueryCast(SrcT value);
63
64// From-Float-To-Integer Casts
65template <>
66GLint UniformStateQueryCast(GLfloat value)
67{
68 return clampCast<GLint>(roundf(value));
69}
70
71template <>
72GLuint UniformStateQueryCast(GLfloat value)
73{
74 return clampCast<GLuint>(roundf(value));
75}
76
77// From-Integer-to-Integer Casts
78template <>
79GLint UniformStateQueryCast(GLuint value)
80{
81 return clampCast<GLint>(value);
82}
83
84template <>
85GLuint UniformStateQueryCast(GLint value)
86{
87 return clampCast<GLuint>(value);
88}
89
90// From-Boolean-to-Anything Casts
91template <>
92GLfloat UniformStateQueryCast(GLboolean value)
93{
94 return (value == GL_TRUE ? 1.0f : 0.0f);
95}
96
97template <>
98GLint UniformStateQueryCast(GLboolean value)
99{
100 return (value == GL_TRUE ? 1 : 0);
101}
102
103template <>
104GLuint UniformStateQueryCast(GLboolean value)
105{
106 return (value == GL_TRUE ? 1u : 0u);
107}
108
109// Default to static_cast
110template <typename DestT, typename SrcT>
111DestT UniformStateQueryCast(SrcT value)
112{
113 return static_cast<DestT>(value);
114}
115
116template <typename SrcT, typename DestT>
117void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
118{
119 for (int comp = 0; comp < components; ++comp)
120 {
121 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
122 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
123 size_t offset = comp * 4;
124 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
125 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
126 }
127}
128
Jamie Madill192745a2016-12-22 15:58:21 -0500129// true if varying x has a higher priority in packing than y
130bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
131{
132 return gl::CompareShaderVar(*x.varying, *y.varying);
133}
134
jchen1015015f72017-03-16 13:54:21 +0800135template <typename VarT>
136GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
137{
138 size_t subscript = GL_INVALID_INDEX;
139 std::string baseName = ParseResourceName(name, &subscript);
140
141 // The app is not allowed to specify array indices other than 0 for arrays of basic types
142 if (subscript != 0 && subscript != GL_INVALID_INDEX)
143 {
144 return GL_INVALID_INDEX;
145 }
146
147 for (size_t index = 0; index < list.size(); index++)
148 {
149 const VarT &resource = list[index];
150 if (resource.name == baseName)
151 {
152 if (resource.isArray() || subscript == GL_INVALID_INDEX)
153 {
154 return static_cast<GLuint>(index);
155 }
156 }
157 }
158
159 return GL_INVALID_INDEX;
160}
161
Jamie Madill62d31cb2015-09-11 13:25:51 -0400162} // anonymous namespace
163
Jamie Madill4a3c2342015-10-08 12:58:45 -0400164const char *const g_fakepath = "C:\\fakepath";
165
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400166InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000167{
168}
169
170InfoLog::~InfoLog()
171{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000172}
173
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400174size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000175{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400176 const std::string &logString = mStream.str();
177 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000178}
179
Geoff Lange1a27752015-10-05 13:16:04 -0400180void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000181{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000183
184 if (bufSize > 0)
185 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400186 const std::string str(mStream.str());
187
188 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000189 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400190 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
191 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000192 }
193
194 infoLog[index] = '\0';
195 }
196
197 if (length)
198 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400199 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000200 }
201}
202
203// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300204// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000205// messages, so lets remove all occurrences of this fake file path from the log.
206void InfoLog::appendSanitized(const char *message)
207{
208 std::string msg(message);
209
210 size_t found;
211 do
212 {
213 found = msg.find(g_fakepath);
214 if (found != std::string::npos)
215 {
216 msg.erase(found, strlen(g_fakepath));
217 }
218 }
219 while (found != std::string::npos);
220
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400221 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000222}
223
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000224void InfoLog::reset()
225{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000226}
227
Geoff Langd8605522016-04-13 10:19:12 -0400228VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000229{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500230}
231
Geoff Langd8605522016-04-13 10:19:12 -0400232VariableLocation::VariableLocation(const std::string &name,
233 unsigned int element,
234 unsigned int index)
235 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500236{
237}
238
Geoff Langd8605522016-04-13 10:19:12 -0400239void Program::Bindings::bindLocation(GLuint index, const std::string &name)
240{
241 mBindings[name] = index;
242}
243
244int Program::Bindings::getBinding(const std::string &name) const
245{
246 auto iter = mBindings.find(name);
247 return (iter != mBindings.end()) ? iter->second : -1;
248}
249
250Program::Bindings::const_iterator Program::Bindings::begin() const
251{
252 return mBindings.begin();
253}
254
255Program::Bindings::const_iterator Program::Bindings::end() const
256{
257 return mBindings.end();
258}
259
Jamie Madill48ef11b2016-04-27 15:21:52 -0400260ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500261 : mLabel(),
262 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400263 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300264 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500265 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madille7d84322017-01-10 18:21:59 -0500266 mSamplerUniformRange(0, 0),
Geoff Langc5629752015-12-07 16:29:04 -0500267 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400268{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300269 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400270}
271
Jamie Madill48ef11b2016-04-27 15:21:52 -0400272ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400273{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500274 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400275}
276
Jamie Madill48ef11b2016-04-27 15:21:52 -0400277const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500278{
279 return mLabel;
280}
281
Jamie Madill48ef11b2016-04-27 15:21:52 -0400282GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400283{
284 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +0800285 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400286
287 for (size_t location = 0; location < mUniformLocations.size(); ++location)
288 {
289 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400290 if (!uniformLocation.used)
291 {
292 continue;
293 }
294
295 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400296
297 if (uniform.name == baseName)
298 {
Geoff Langd8605522016-04-13 10:19:12 -0400299 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400300 {
Geoff Langd8605522016-04-13 10:19:12 -0400301 if (uniformLocation.element == subscript ||
302 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
303 {
304 return static_cast<GLint>(location);
305 }
306 }
307 else
308 {
309 if (subscript == GL_INVALID_INDEX)
310 {
311 return static_cast<GLint>(location);
312 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400313 }
314 }
315 }
316
317 return -1;
318}
319
Jamie Madille7d84322017-01-10 18:21:59 -0500320GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400321{
jchen1015015f72017-03-16 13:54:21 +0800322 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400323}
324
Jamie Madille7d84322017-01-10 18:21:59 -0500325GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
326{
327 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
328 return mUniformLocations[location].index;
329}
330
331Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
332{
333 GLuint index = getUniformIndexFromLocation(location);
334 if (!isSamplerUniformIndex(index))
335 {
336 return Optional<GLuint>::Invalid();
337 }
338
339 return getSamplerIndexFromUniformIndex(index);
340}
341
342bool ProgramState::isSamplerUniformIndex(GLuint index) const
343{
344 return index >= mSamplerUniformRange.start && index < mSamplerUniformRange.end;
345}
346
347GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
348{
349 ASSERT(isSamplerUniformIndex(uniformIndex));
350 return uniformIndex - mSamplerUniformRange.start;
351}
352
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500353Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400354 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400355 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500356 mLinked(false),
357 mDeleteStatus(false),
358 mRefCount(0),
359 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500360 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500361{
362 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000363
364 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500365 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366}
367
368Program::~Program()
369{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500370 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
371 !mState.mAttachedComputeShader);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500372 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373}
374
Jamie Madill6c1f6712017-02-14 19:08:04 -0500375void Program::destroy(const Context *context)
376{
377 if (mState.mAttachedVertexShader != nullptr)
378 {
379 mState.mAttachedVertexShader->release(context);
380 mState.mAttachedVertexShader = nullptr;
381 }
382
383 if (mState.mAttachedFragmentShader != nullptr)
384 {
385 mState.mAttachedFragmentShader->release(context);
386 mState.mAttachedFragmentShader = nullptr;
387 }
388
389 if (mState.mAttachedComputeShader != nullptr)
390 {
391 mState.mAttachedComputeShader->release(context);
392 mState.mAttachedComputeShader = nullptr;
393 }
394
395 mProgram->destroy(rx::SafeGetImpl(context));
396}
397
Geoff Lang70d0f492015-12-10 17:45:46 -0500398void Program::setLabel(const std::string &label)
399{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400400 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500401}
402
403const std::string &Program::getLabel() const
404{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400405 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500406}
407
Jamie Madillef300b12016-10-07 15:12:09 -0400408void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000409{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300410 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300412 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 {
Jamie Madillef300b12016-10-07 15:12:09 -0400414 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300415 mState.mAttachedVertexShader = shader;
416 mState.mAttachedVertexShader->addRef();
417 break;
418 }
419 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Jamie Madillef300b12016-10-07 15:12:09 -0400421 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300422 mState.mAttachedFragmentShader = shader;
423 mState.mAttachedFragmentShader->addRef();
424 break;
425 }
426 case GL_COMPUTE_SHADER:
427 {
Jamie Madillef300b12016-10-07 15:12:09 -0400428 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300429 mState.mAttachedComputeShader = shader;
430 mState.mAttachedComputeShader->addRef();
431 break;
432 }
433 default:
434 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436}
437
Jamie Madill6c1f6712017-02-14 19:08:04 -0500438bool Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300440 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300442 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300444 if (mState.mAttachedVertexShader != shader)
445 {
446 return false;
447 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448
Jamie Madill6c1f6712017-02-14 19:08:04 -0500449 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300450 mState.mAttachedVertexShader = nullptr;
451 break;
452 }
453 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300455 if (mState.mAttachedFragmentShader != shader)
456 {
457 return false;
458 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459
Jamie Madill6c1f6712017-02-14 19:08:04 -0500460 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300461 mState.mAttachedFragmentShader = nullptr;
462 break;
463 }
464 case GL_COMPUTE_SHADER:
465 {
466 if (mState.mAttachedComputeShader != shader)
467 {
468 return false;
469 }
470
Jamie Madill6c1f6712017-02-14 19:08:04 -0500471 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300472 mState.mAttachedComputeShader = nullptr;
473 break;
474 }
475 default:
476 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 return true;
480}
481
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000482int Program::getAttachedShadersCount() const
483{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300484 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
485 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000486}
487
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000488void Program::bindAttributeLocation(GLuint index, const char *name)
489{
Geoff Langd8605522016-04-13 10:19:12 -0400490 mAttributeBindings.bindLocation(index, name);
491}
492
493void Program::bindUniformLocation(GLuint index, const char *name)
494{
495 // Bind the base uniform name only since array indices other than 0 cannot be bound
jchen1015015f72017-03-16 13:54:21 +0800496 mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497}
498
Sami Väisänen46eaa942016-06-29 10:26:37 +0300499void Program::bindFragmentInputLocation(GLint index, const char *name)
500{
501 mFragmentInputBindings.bindLocation(index, name);
502}
503
504BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
505{
506 BindingInfo ret;
507 ret.type = GL_NONE;
508 ret.valid = false;
509
510 const Shader *fragmentShader = mState.getAttachedFragmentShader();
511 ASSERT(fragmentShader);
512
513 // Find the actual fragment shader varying we're interested in
514 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
515
516 for (const auto &binding : mFragmentInputBindings)
517 {
518 if (binding.second != static_cast<GLuint>(index))
519 continue;
520
521 ret.valid = true;
522
523 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400524 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300525
526 for (const auto &in : inputs)
527 {
528 if (in.name == originalName)
529 {
530 if (in.isArray())
531 {
532 // The client wants to bind either "name" or "name[0]".
533 // GL ES 3.1 spec refers to active array names with language such as:
534 // "if the string identifies the base name of an active array, where the
535 // string would exactly match the name of the variable if the suffix "[0]"
536 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400537 if (arrayIndex == GL_INVALID_INDEX)
538 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300539
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400540 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300541 }
542 else
543 {
544 ret.name = in.mappedName;
545 }
546 ret.type = in.type;
547 return ret;
548 }
549 }
550 }
551
552 return ret;
553}
554
555void Program::pathFragmentInputGen(GLint index,
556 GLenum genMode,
557 GLint components,
558 const GLfloat *coeffs)
559{
560 // If the location is -1 then the command is silently ignored
561 if (index == -1)
562 return;
563
564 const auto &binding = getFragmentInputBindingInfo(index);
565
566 // If the input doesn't exist then then the command is silently ignored
567 // This could happen through optimization for example, the shader translator
568 // decides that a variable is not actually being used and optimizes it away.
569 if (binding.name.empty())
570 return;
571
572 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
573}
574
Martin Radev4c4c8e72016-08-04 12:25:34 +0300575// The attached shaders are checked for linking errors by matching up their variables.
576// Uniform, input and output variables get collected.
577// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500578Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000579{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500580 const auto &data = context->getContextState();
581
Jamie Madill6c1f6712017-02-14 19:08:04 -0500582 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000583
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000584 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000585 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000586
Martin Radev4c4c8e72016-08-04 12:25:34 +0300587 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500588
Jamie Madill192745a2016-12-22 15:58:21 -0500589 auto vertexShader = mState.mAttachedVertexShader;
590 auto fragmentShader = mState.mAttachedFragmentShader;
591 auto computeShader = mState.mAttachedComputeShader;
592
593 bool isComputeShaderAttached = (computeShader != nullptr);
594 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300595 // Check whether we both have a compute and non-compute shaders attached.
596 // If there are of both types attached, then linking should fail.
597 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
598 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500599 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300600 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
601 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400602 }
603
Jamie Madill192745a2016-12-22 15:58:21 -0500604 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500605 {
Jamie Madill192745a2016-12-22 15:58:21 -0500606 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300607 {
608 mInfoLog << "Attached compute shader is not compiled.";
609 return NoError();
610 }
Jamie Madill192745a2016-12-22 15:58:21 -0500611 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300612
Jamie Madill192745a2016-12-22 15:58:21 -0500613 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300614
615 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
616 // If the work group size is not specified, a link time error should occur.
617 if (!mState.mComputeShaderLocalSize.isDeclared())
618 {
619 mInfoLog << "Work group size is not specified.";
620 return NoError();
621 }
622
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000623 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300624 {
625 return NoError();
626 }
627
628 if (!linkUniformBlocks(mInfoLog, caps))
629 {
630 return NoError();
631 }
632
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500633 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
634 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), noPacking, mInfoLog),
635 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500636 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300637 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500638 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300639 }
640 }
641 else
642 {
Jamie Madill192745a2016-12-22 15:58:21 -0500643 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300644 {
645 return NoError();
646 }
Jamie Madill192745a2016-12-22 15:58:21 -0500647 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300648
Jamie Madill192745a2016-12-22 15:58:21 -0500649 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300650 {
651 return NoError();
652 }
Jamie Madill192745a2016-12-22 15:58:21 -0500653 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300654
Jamie Madill192745a2016-12-22 15:58:21 -0500655 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300656 {
657 mInfoLog << "Fragment shader version does not match vertex shader version.";
658 return NoError();
659 }
660
Jamie Madilleb979bf2016-11-15 12:28:46 -0500661 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300662 {
663 return NoError();
664 }
665
Jamie Madill192745a2016-12-22 15:58:21 -0500666 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300667 {
668 return NoError();
669 }
670
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000671 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300672 {
673 return NoError();
674 }
675
676 if (!linkUniformBlocks(mInfoLog, caps))
677 {
678 return NoError();
679 }
680
681 const auto &mergedVaryings = getMergedVaryings();
682
683 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
684 {
685 return NoError();
686 }
687
688 linkOutputVariables();
689
Jamie Madill192745a2016-12-22 15:58:21 -0500690 // Validate we can pack the varyings.
691 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
692
693 // Map the varyings to the register file
694 // In WebGL, we use a slightly different handling for packing variables.
695 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
696 : PackMode::ANGLE_RELAXED;
697 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
698 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
699 mState.getTransformFeedbackVaryingNames()))
700 {
701 return NoError();
702 }
703
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500704 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), varyingPacking, mInfoLog),
705 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500706 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300707 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500708 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300709 }
710
711 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500712 }
713
Olli Etuaho48fed632017-03-16 12:05:30 +0000714 setUniformValuesFromBindingQualifiers();
715
Jamie Madill4a3c2342015-10-08 12:58:45 -0400716 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400717
Martin Radev4c4c8e72016-08-04 12:25:34 +0300718 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000719}
720
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000721// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500722void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400724 mState.mAttributes.clear();
725 mState.mActiveAttribLocationsMask.reset();
726 mState.mTransformFeedbackVaryingVars.clear();
727 mState.mUniforms.clear();
728 mState.mUniformLocations.clear();
729 mState.mUniformBlocks.clear();
730 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800731 mState.mOutputLocations.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300732 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500733 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500734
Geoff Lang7dd2e102014-11-10 15:19:26 -0500735 mValidated = false;
736
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000737 mLinked = false;
738}
739
Geoff Lange1a27752015-10-05 13:16:04 -0400740bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000741{
742 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743}
744
Jamie Madilla2c74982016-12-12 11:20:42 -0500745Error Program::loadBinary(const Context *context,
746 GLenum binaryFormat,
747 const void *binary,
748 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000749{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500750 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000751
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800753 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500754#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400755 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
756 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000757 {
Jamie Madillf6113162015-05-07 11:49:21 -0400758 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800759 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500760 }
761
Geoff Langc46cc2f2015-10-01 17:16:20 -0400762 BinaryInputStream stream(binary, length);
763
Jamie Madilla2c74982016-12-12 11:20:42 -0500764 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
765 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
766 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
767 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500768 {
Jamie Madillf6113162015-05-07 11:49:21 -0400769 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800770 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500771 }
772
Jamie Madilla2c74982016-12-12 11:20:42 -0500773 int majorVersion = stream.readInt<int>();
774 int minorVersion = stream.readInt<int>();
775 if (majorVersion != context->getClientMajorVersion() ||
776 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500778 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800779 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500780 }
781
Martin Radev4c4c8e72016-08-04 12:25:34 +0300782 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
783 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
784 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
785
Jamie Madill63805b42015-08-25 13:17:39 -0400786 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
787 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400788 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500789
Jamie Madill3da79b72015-04-27 11:09:17 -0400790 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400791 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400792 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
793 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400794 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400795 LoadShaderVar(&stream, &attrib);
796 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400797 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400798 }
799
Jamie Madill62d31cb2015-09-11 13:25:51 -0400800 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400801 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400802 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
803 {
804 LinkedUniform uniform;
805 LoadShaderVar(&stream, &uniform);
806
807 uniform.blockIndex = stream.readInt<int>();
808 uniform.blockInfo.offset = stream.readInt<int>();
809 uniform.blockInfo.arrayStride = stream.readInt<int>();
810 uniform.blockInfo.matrixStride = stream.readInt<int>();
811 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
812
Jamie Madill48ef11b2016-04-27 15:21:52 -0400813 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400814 }
815
816 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400817 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400818 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
819 uniformIndexIndex++)
820 {
821 VariableLocation variable;
822 stream.readString(&variable.name);
823 stream.readInt(&variable.element);
824 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400825 stream.readBool(&variable.used);
826 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400827
Jamie Madill48ef11b2016-04-27 15:21:52 -0400828 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400829 }
830
831 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400832 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400833 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
834 ++uniformBlockIndex)
835 {
836 UniformBlock uniformBlock;
837 stream.readString(&uniformBlock.name);
838 stream.readBool(&uniformBlock.isArray);
839 stream.readInt(&uniformBlock.arrayElement);
840 stream.readInt(&uniformBlock.dataSize);
841 stream.readBool(&uniformBlock.vertexStaticUse);
842 stream.readBool(&uniformBlock.fragmentStaticUse);
843
844 unsigned int numMembers = stream.readInt<unsigned int>();
845 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
846 {
847 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
848 }
849
Jamie Madill48ef11b2016-04-27 15:21:52 -0400850 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400851 }
852
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500853 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
854 ++bindingIndex)
855 {
856 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
857 mState.mActiveUniformBlockBindings.set(bindingIndex,
858 mState.mUniformBlockBindings[bindingIndex] != 0);
859 }
860
Brandon Jones1048ea72015-10-06 15:34:52 -0700861 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400862 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700863 for (unsigned int transformFeedbackVaryingIndex = 0;
864 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
865 ++transformFeedbackVaryingIndex)
866 {
867 sh::Varying varying;
868 stream.readInt(&varying.arraySize);
869 stream.readInt(&varying.type);
870 stream.readString(&varying.name);
871
Jamie Madill48ef11b2016-04-27 15:21:52 -0400872 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700873 }
874
Jamie Madill48ef11b2016-04-27 15:21:52 -0400875 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400876
jchen1015015f72017-03-16 13:54:21 +0800877 unsigned int outputCount = stream.readInt<unsigned int>();
878 ASSERT(mState.mOutputVariables.empty());
879 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
880 {
881 sh::OutputVariable output;
882 LoadShaderVar(&stream, &output);
883 output.location = stream.readInt<int>();
884 mState.mOutputVariables.push_back(output);
885 }
886
Jamie Madill80a6fc02015-08-21 16:53:16 -0400887 unsigned int outputVarCount = stream.readInt<unsigned int>();
888 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
889 {
890 int locationIndex = stream.readInt<int>();
891 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400892 stream.readInt(&locationData.element);
893 stream.readInt(&locationData.index);
894 stream.readString(&locationData.name);
jchen1015015f72017-03-16 13:54:21 +0800895 mState.mOutputLocations[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400896 }
897
Jamie Madille7d84322017-01-10 18:21:59 -0500898 stream.readInt(&mState.mSamplerUniformRange.start);
899 stream.readInt(&mState.mSamplerUniformRange.end);
900
901 unsigned int samplerCount = stream.readInt<unsigned int>();
902 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
903 {
904 GLenum textureType = stream.readInt<GLenum>();
905 size_t bindingCount = stream.readInt<size_t>();
906 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
907 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400908
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500909 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000910
Jamie Madillb0a838b2016-11-13 20:02:12 -0500911 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500912#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500913}
914
Jamie Madilla2c74982016-12-12 11:20:42 -0500915Error Program::saveBinary(const Context *context,
916 GLenum *binaryFormat,
917 void *binary,
918 GLsizei bufSize,
919 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500920{
921 if (binaryFormat)
922 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400923 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500924 }
925
926 BinaryOutputStream stream;
927
Geoff Lang7dd2e102014-11-10 15:19:26 -0500928 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
929
Jamie Madilla2c74982016-12-12 11:20:42 -0500930 // nullptr context is supported when computing binary length.
931 if (context)
932 {
933 stream.writeInt(context->getClientVersion().major);
934 stream.writeInt(context->getClientVersion().minor);
935 }
936 else
937 {
938 stream.writeInt(2);
939 stream.writeInt(0);
940 }
941
Martin Radev4c4c8e72016-08-04 12:25:34 +0300942 stream.writeInt(mState.mComputeShaderLocalSize[0]);
943 stream.writeInt(mState.mComputeShaderLocalSize[1]);
944 stream.writeInt(mState.mComputeShaderLocalSize[2]);
945
Jamie Madill48ef11b2016-04-27 15:21:52 -0400946 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500947
Jamie Madill48ef11b2016-04-27 15:21:52 -0400948 stream.writeInt(mState.mAttributes.size());
949 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400950 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400951 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400952 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400953 }
954
Jamie Madill48ef11b2016-04-27 15:21:52 -0400955 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500956 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400957 {
958 WriteShaderVar(&stream, uniform);
959
960 // FIXME: referenced
961
962 stream.writeInt(uniform.blockIndex);
963 stream.writeInt(uniform.blockInfo.offset);
964 stream.writeInt(uniform.blockInfo.arrayStride);
965 stream.writeInt(uniform.blockInfo.matrixStride);
966 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
967 }
968
Jamie Madill48ef11b2016-04-27 15:21:52 -0400969 stream.writeInt(mState.mUniformLocations.size());
970 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400971 {
972 stream.writeString(variable.name);
973 stream.writeInt(variable.element);
974 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400975 stream.writeInt(variable.used);
976 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400977 }
978
Jamie Madill48ef11b2016-04-27 15:21:52 -0400979 stream.writeInt(mState.mUniformBlocks.size());
980 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400981 {
982 stream.writeString(uniformBlock.name);
983 stream.writeInt(uniformBlock.isArray);
984 stream.writeInt(uniformBlock.arrayElement);
985 stream.writeInt(uniformBlock.dataSize);
986
987 stream.writeInt(uniformBlock.vertexStaticUse);
988 stream.writeInt(uniformBlock.fragmentStaticUse);
989
990 stream.writeInt(uniformBlock.memberUniformIndexes.size());
991 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
992 {
993 stream.writeInt(memberUniformIndex);
994 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400995 }
996
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500997 for (GLuint binding : mState.mUniformBlockBindings)
998 {
999 stream.writeInt(binding);
1000 }
1001
Jamie Madill48ef11b2016-04-27 15:21:52 -04001002 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
1003 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -07001004 {
1005 stream.writeInt(varying.arraySize);
1006 stream.writeInt(varying.type);
1007 stream.writeString(varying.name);
1008 }
1009
Jamie Madill48ef11b2016-04-27 15:21:52 -04001010 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001011
Jamie Madill48ef11b2016-04-27 15:21:52 -04001012 stream.writeInt(mState.mOutputVariables.size());
jchen1015015f72017-03-16 13:54:21 +08001013 for (const sh::OutputVariable &output : mState.mOutputVariables)
1014 {
1015 WriteShaderVar(&stream, output);
1016 stream.writeInt(output.location);
1017 }
1018
1019 stream.writeInt(mState.mOutputLocations.size());
1020 for (const auto &outputPair : mState.mOutputLocations)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001021 {
1022 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001023 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001024 stream.writeInt(outputPair.second.index);
1025 stream.writeString(outputPair.second.name);
1026 }
1027
Jamie Madille7d84322017-01-10 18:21:59 -05001028 stream.writeInt(mState.mSamplerUniformRange.start);
1029 stream.writeInt(mState.mSamplerUniformRange.end);
1030
1031 stream.writeInt(mState.mSamplerBindings.size());
1032 for (const auto &samplerBinding : mState.mSamplerBindings)
1033 {
1034 stream.writeInt(samplerBinding.textureType);
1035 stream.writeInt(samplerBinding.boundTextureUnits.size());
1036 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001037
Jamie Madilla2c74982016-12-12 11:20:42 -05001038 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001039
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001040 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001041 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042
1043 if (streamLength > bufSize)
1044 {
1045 if (length)
1046 {
1047 *length = 0;
1048 }
1049
1050 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1051 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1052 // sizes and then copy it.
1053 return Error(GL_INVALID_OPERATION);
1054 }
1055
1056 if (binary)
1057 {
1058 char *ptr = reinterpret_cast<char*>(binary);
1059
Jamie Madill48ef11b2016-04-27 15:21:52 -04001060 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061 ptr += streamLength;
1062
1063 ASSERT(ptr - streamLength == binary);
1064 }
1065
1066 if (length)
1067 {
1068 *length = streamLength;
1069 }
1070
He Yunchaoacd18982017-01-04 10:46:42 +08001071 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001072}
1073
1074GLint Program::getBinaryLength() const
1075{
1076 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001077 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001078 if (error.isError())
1079 {
1080 return 0;
1081 }
1082
1083 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001084}
1085
Geoff Langc5629752015-12-07 16:29:04 -05001086void Program::setBinaryRetrievableHint(bool retrievable)
1087{
1088 // TODO(jmadill) : replace with dirty bits
1089 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001090 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001091}
1092
1093bool Program::getBinaryRetrievableHint() const
1094{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001095 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001096}
1097
Jamie Madill6c1f6712017-02-14 19:08:04 -05001098void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001099{
1100 mRefCount--;
1101
1102 if (mRefCount == 0 && mDeleteStatus)
1103 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001104 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001105 }
1106}
1107
1108void Program::addRef()
1109{
1110 mRefCount++;
1111}
1112
1113unsigned int Program::getRefCount() const
1114{
1115 return mRefCount;
1116}
1117
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001118int Program::getInfoLogLength() const
1119{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001120 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001121}
1122
Geoff Lange1a27752015-10-05 13:16:04 -04001123void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001124{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001125 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001126}
1127
Geoff Lange1a27752015-10-05 13:16:04 -04001128void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001129{
1130 int total = 0;
1131
Martin Radev4c4c8e72016-08-04 12:25:34 +03001132 if (mState.mAttachedComputeShader)
1133 {
1134 if (total < maxCount)
1135 {
1136 shaders[total] = mState.mAttachedComputeShader->getHandle();
1137 total++;
1138 }
1139 }
1140
Jamie Madill48ef11b2016-04-27 15:21:52 -04001141 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001142 {
1143 if (total < maxCount)
1144 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001145 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001146 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001147 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001148 }
1149
Jamie Madill48ef11b2016-04-27 15:21:52 -04001150 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001151 {
1152 if (total < maxCount)
1153 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001154 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001155 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001156 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001157 }
1158
1159 if (count)
1160 {
1161 *count = total;
1162 }
1163}
1164
Geoff Lange1a27752015-10-05 13:16:04 -04001165GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001166{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001167 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001168 {
jchen1036e120e2017-03-14 14:53:58 +08001169 if (attribute.name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001170 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001171 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001172 }
1173 }
1174
Austin Kinrossb8af7232015-03-16 22:33:25 -07001175 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176}
1177
Jamie Madill63805b42015-08-25 13:17:39 -04001178bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001179{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001180 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1181 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001182}
1183
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001184void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1185{
Jamie Madillc349ec02015-08-21 16:53:12 -04001186 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001187 {
1188 if (bufsize > 0)
1189 {
1190 name[0] = '\0';
1191 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001192
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001193 if (length)
1194 {
1195 *length = 0;
1196 }
1197
1198 *type = GL_NONE;
1199 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001200 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001201 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001202
jchen1036e120e2017-03-14 14:53:58 +08001203 ASSERT(index < mState.mAttributes.size());
1204 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001205
1206 if (bufsize > 0)
1207 {
1208 const char *string = attrib.name.c_str();
1209
1210 strncpy(name, string, bufsize);
1211 name[bufsize - 1] = '\0';
1212
1213 if (length)
1214 {
1215 *length = static_cast<GLsizei>(strlen(name));
1216 }
1217 }
1218
1219 // Always a single 'type' instance
1220 *size = 1;
1221 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001222}
1223
Geoff Lange1a27752015-10-05 13:16:04 -04001224GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001225{
Jamie Madillc349ec02015-08-21 16:53:12 -04001226 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001227 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001228 return 0;
1229 }
1230
jchen1036e120e2017-03-14 14:53:58 +08001231 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001232}
1233
Geoff Lange1a27752015-10-05 13:16:04 -04001234GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001235{
Jamie Madillc349ec02015-08-21 16:53:12 -04001236 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001237 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001238 return 0;
1239 }
1240
1241 size_t maxLength = 0;
1242
Jamie Madill48ef11b2016-04-27 15:21:52 -04001243 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001244 {
jchen1036e120e2017-03-14 14:53:58 +08001245 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001246 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001247
Jamie Madillc349ec02015-08-21 16:53:12 -04001248 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001249}
1250
jchen1015015f72017-03-16 13:54:21 +08001251GLuint Program::getInputResourceIndex(const GLchar *name) const
1252{
1253 for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
1254 {
1255 const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
1256 if (attribute.name == name)
1257 {
1258 return attributeIndex;
1259 }
1260 }
1261 return GL_INVALID_INDEX;
1262}
1263
1264GLuint Program::getOutputResourceIndex(const GLchar *name) const
1265{
1266 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1267}
1268
Geoff Lang7dd2e102014-11-10 15:19:26 -05001269GLint Program::getFragDataLocation(const std::string &name) const
1270{
1271 std::string baseName(name);
1272 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
jchen1015015f72017-03-16 13:54:21 +08001273 for (auto outputPair : mState.mOutputLocations)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001274 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001275 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001276 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1277 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001278 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001279 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001280 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001281 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001282}
1283
Geoff Lange1a27752015-10-05 13:16:04 -04001284void Program::getActiveUniform(GLuint index,
1285 GLsizei bufsize,
1286 GLsizei *length,
1287 GLint *size,
1288 GLenum *type,
1289 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001290{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001291 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001292 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001293 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001294 ASSERT(index < mState.mUniforms.size());
1295 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001296
1297 if (bufsize > 0)
1298 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001299 std::string string = uniform.name;
1300 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001301 {
1302 string += "[0]";
1303 }
1304
1305 strncpy(name, string.c_str(), bufsize);
1306 name[bufsize - 1] = '\0';
1307
1308 if (length)
1309 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001310 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001311 }
1312 }
1313
Jamie Madill62d31cb2015-09-11 13:25:51 -04001314 *size = uniform.elementCount();
1315 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001316 }
1317 else
1318 {
1319 if (bufsize > 0)
1320 {
1321 name[0] = '\0';
1322 }
1323
1324 if (length)
1325 {
1326 *length = 0;
1327 }
1328
1329 *size = 0;
1330 *type = GL_NONE;
1331 }
1332}
1333
Geoff Lange1a27752015-10-05 13:16:04 -04001334GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001335{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001336 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001337 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001338 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001339 }
1340 else
1341 {
1342 return 0;
1343 }
1344}
1345
Geoff Lange1a27752015-10-05 13:16:04 -04001346GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001347{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001348 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001349
1350 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001351 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001352 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001353 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001354 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001355 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001356 size_t length = uniform.name.length() + 1u;
1357 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001358 {
1359 length += 3; // Counting in "[0]".
1360 }
1361 maxLength = std::max(length, maxLength);
1362 }
1363 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001364 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001365
Jamie Madill62d31cb2015-09-11 13:25:51 -04001366 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001367}
1368
1369GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1370{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001371 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001372 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001374 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001375 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1376 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1377 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1378 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1379 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1380 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1381 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1382 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1383 default:
1384 UNREACHABLE();
1385 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001386 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387 return 0;
1388}
1389
1390bool Program::isValidUniformLocation(GLint location) const
1391{
Jamie Madille2e406c2016-06-02 13:04:10 -04001392 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001393 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1394 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001395}
1396
Jamie Madill62d31cb2015-09-11 13:25:51 -04001397const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001399 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001400 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001401}
1402
Jamie Madillac4e9c32017-01-13 14:07:12 -05001403const VariableLocation &Program::getUniformLocation(GLint location) const
1404{
1405 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1406 return mState.mUniformLocations[location];
1407}
1408
1409const std::vector<VariableLocation> &Program::getUniformLocations() const
1410{
1411 return mState.mUniformLocations;
1412}
1413
1414const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1415{
1416 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1417 return mState.mUniforms[index];
1418}
1419
Jamie Madill62d31cb2015-09-11 13:25:51 -04001420GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001421{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001422 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001423}
1424
Jamie Madill62d31cb2015-09-11 13:25:51 -04001425GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001426{
Jamie Madille7d84322017-01-10 18:21:59 -05001427 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001428}
1429
1430void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1431{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001432 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1433 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001434}
1435
1436void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1437{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001438 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1439 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001440}
1441
1442void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1443{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001444 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1445 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446}
1447
1448void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1449{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001450 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1451 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001452}
1453
1454void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1455{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001456 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1457 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001458}
1459
1460void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1461{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001462 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1463 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001464}
1465
1466void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1467{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001468 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1469 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001470}
1471
1472void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1473{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001474 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1475 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001476}
1477
1478void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1479{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001480 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1481 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001482}
1483
1484void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1485{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001486 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1487 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001488}
1489
1490void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1491{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001492 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1493 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001494}
1495
1496void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1497{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001498 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1499 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001500}
1501
1502void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1503{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001504 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1505 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001506}
1507
1508void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1509{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001510 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1511 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001512}
1513
1514void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1515{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001516 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1517 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001518}
1519
1520void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1521{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001522 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1523 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001524}
1525
1526void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1527{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001528 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1529 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001530}
1531
1532void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1533{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001534 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1535 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001536}
1537
1538void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1539{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001540 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1541 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001542}
1543
1544void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1545{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001546 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1547 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001548}
1549
1550void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1551{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001552 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1553 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001554}
1555
Geoff Lange1a27752015-10-05 13:16:04 -04001556void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001558 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001559}
1560
Geoff Lange1a27752015-10-05 13:16:04 -04001561void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001562{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001563 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564}
1565
Geoff Lange1a27752015-10-05 13:16:04 -04001566void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001567{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001568 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569}
1570
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001571void Program::flagForDeletion()
1572{
1573 mDeleteStatus = true;
1574}
1575
1576bool Program::isFlaggedForDeletion() const
1577{
1578 return mDeleteStatus;
1579}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001580
Brandon Jones43a53e22014-08-28 16:23:22 -07001581void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001582{
1583 mInfoLog.reset();
1584
Geoff Lang7dd2e102014-11-10 15:19:26 -05001585 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001586 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001587 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001588 }
1589 else
1590 {
Jamie Madillf6113162015-05-07 11:49:21 -04001591 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001592 }
1593}
1594
Geoff Lang7dd2e102014-11-10 15:19:26 -05001595bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1596{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001597 // Skip cache if we're using an infolog, so we get the full error.
1598 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1599 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1600 {
1601 return mCachedValidateSamplersResult.value();
1602 }
1603
1604 if (mTextureUnitTypesCache.empty())
1605 {
1606 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1607 }
1608 else
1609 {
1610 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1611 }
1612
1613 // if any two active samplers in a program are of different types, but refer to the same
1614 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1615 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001616 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001617 {
Jamie Madille7d84322017-01-10 18:21:59 -05001618 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001619
Jamie Madille7d84322017-01-10 18:21:59 -05001620 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001621 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001622 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1623 {
1624 if (infoLog)
1625 {
1626 (*infoLog) << "Sampler uniform (" << textureUnit
1627 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1628 << caps.maxCombinedTextureImageUnits << ")";
1629 }
1630
1631 mCachedValidateSamplersResult = false;
1632 return false;
1633 }
1634
1635 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1636 {
1637 if (textureType != mTextureUnitTypesCache[textureUnit])
1638 {
1639 if (infoLog)
1640 {
1641 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1642 "image unit ("
1643 << textureUnit << ").";
1644 }
1645
1646 mCachedValidateSamplersResult = false;
1647 return false;
1648 }
1649 }
1650 else
1651 {
1652 mTextureUnitTypesCache[textureUnit] = textureType;
1653 }
1654 }
1655 }
1656
1657 mCachedValidateSamplersResult = true;
1658 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001659}
1660
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001661bool Program::isValidated() const
1662{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001663 return mValidated;
1664}
1665
Geoff Lange1a27752015-10-05 13:16:04 -04001666GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001667{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001668 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001669}
1670
1671void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1672{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001673 ASSERT(
1674 uniformBlockIndex <
1675 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001676
Jamie Madill48ef11b2016-04-27 15:21:52 -04001677 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001678
1679 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001680 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001681 std::string string = uniformBlock.name;
1682
Jamie Madill62d31cb2015-09-11 13:25:51 -04001683 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001685 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001686 }
1687
1688 strncpy(uniformBlockName, string.c_str(), bufSize);
1689 uniformBlockName[bufSize - 1] = '\0';
1690
1691 if (length)
1692 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001693 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001694 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001695 }
1696}
1697
Geoff Lange1a27752015-10-05 13:16:04 -04001698GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001699{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001700 int maxLength = 0;
1701
1702 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001703 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001704 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001705 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1706 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001707 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001708 if (!uniformBlock.name.empty())
1709 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001710 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001711
1712 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001713 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001714
1715 maxLength = std::max(length + arrayLength, maxLength);
1716 }
1717 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001718 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001719
1720 return maxLength;
1721}
1722
Geoff Lange1a27752015-10-05 13:16:04 -04001723GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001724{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001725 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08001726 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001727
Jamie Madill48ef11b2016-04-27 15:21:52 -04001728 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001729 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1730 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001731 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001732 if (uniformBlock.name == baseName)
1733 {
1734 const bool arrayElementZero =
1735 (subscript == GL_INVALID_INDEX &&
1736 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1737 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1738 {
1739 return blockIndex;
1740 }
1741 }
1742 }
1743
1744 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001745}
1746
Jamie Madill62d31cb2015-09-11 13:25:51 -04001747const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001748{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001749 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1750 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001751}
1752
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001753void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1754{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001755 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001756 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001757 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001758}
1759
1760GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1761{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001762 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001763}
1764
1765void Program::resetUniformBlockBindings()
1766{
1767 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1768 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001769 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001770 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001771 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001772}
1773
Geoff Lang48dcae72014-02-05 16:28:24 -05001774void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1775{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001776 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001777 for (GLsizei i = 0; i < count; i++)
1778 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001779 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001780 }
1781
Jamie Madill48ef11b2016-04-27 15:21:52 -04001782 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001783}
1784
1785void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1786{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001787 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001788 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001789 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1790 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001791 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1792 if (length)
1793 {
1794 *length = lastNameIdx;
1795 }
1796 if (size)
1797 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001798 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001799 }
1800 if (type)
1801 {
1802 *type = varying.type;
1803 }
1804 if (name)
1805 {
1806 memcpy(name, varying.name.c_str(), lastNameIdx);
1807 name[lastNameIdx] = '\0';
1808 }
1809 }
1810}
1811
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001812GLsizei Program::getTransformFeedbackVaryingCount() const
1813{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001814 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001815 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001816 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001817 }
1818 else
1819 {
1820 return 0;
1821 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001822}
1823
1824GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1825{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001826 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001827 {
1828 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001829 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001830 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001831 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1832 }
1833
1834 return maxSize;
1835 }
1836 else
1837 {
1838 return 0;
1839 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001840}
1841
1842GLenum Program::getTransformFeedbackBufferMode() const
1843{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001844 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001845}
1846
Jamie Madill192745a2016-12-22 15:58:21 -05001847bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001848{
Jamie Madill192745a2016-12-22 15:58:21 -05001849 const Shader *vertexShader = mState.mAttachedVertexShader;
1850 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1851
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001852 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1853
Jamie Madill4cff2472015-08-21 16:53:18 -04001854 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1855 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856
Sami Väisänen46eaa942016-06-29 10:26:37 +03001857 std::map<GLuint, std::string> staticFragmentInputLocations;
1858
Jamie Madill4cff2472015-08-21 16:53:18 -04001859 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861 bool matched = false;
1862
1863 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001864 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001865 {
1866 continue;
1867 }
1868
Jamie Madill4cff2472015-08-21 16:53:18 -04001869 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001870 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001871 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001872 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001873 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001874 if (!linkValidateVaryings(infoLog, output.name, input, output,
1875 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001876 {
1877 return false;
1878 }
1879
Geoff Lang7dd2e102014-11-10 15:19:26 -05001880 matched = true;
1881 break;
1882 }
1883 }
1884
1885 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001886 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001888 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001889 return false;
1890 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001891
1892 // Check for aliased path rendering input bindings (if any).
1893 // If more than one binding refer statically to the same
1894 // location the link must fail.
1895
1896 if (!output.staticUse)
1897 continue;
1898
1899 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1900 if (inputBinding == -1)
1901 continue;
1902
1903 const auto it = staticFragmentInputLocations.find(inputBinding);
1904 if (it == std::end(staticFragmentInputLocations))
1905 {
1906 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1907 }
1908 else
1909 {
1910 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1911 << it->second;
1912 return false;
1913 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001914 }
1915
Yuly Novikov817232e2017-02-22 18:36:10 -05001916 if (!linkValidateBuiltInVaryings(infoLog))
1917 {
1918 return false;
1919 }
1920
Jamie Madillada9ecc2015-08-17 12:53:37 -04001921 // TODO(jmadill): verify no unmatched vertex varyings?
1922
Geoff Lang7dd2e102014-11-10 15:19:26 -05001923 return true;
1924}
1925
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001926bool Program::linkUniforms(InfoLog &infoLog,
1927 const Caps &caps,
1928 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001929{
Olli Etuahob78707c2017-03-09 15:03:11 +00001930 UniformLinker linker(mState);
1931 if (!linker.link(infoLog, caps, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04001932 {
1933 return false;
1934 }
1935
Olli Etuahob78707c2017-03-09 15:03:11 +00001936 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001937
Olli Etuaho48fed632017-03-16 12:05:30 +00001938 linkSamplerBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001939
1940 return true;
1941}
1942
Olli Etuaho48fed632017-03-16 12:05:30 +00001943void Program::linkSamplerBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001944{
1945 mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
1946 mState.mSamplerUniformRange.start = mState.mSamplerUniformRange.end;
1947 auto samplerIter = mState.mUniforms.rbegin();
1948 while (samplerIter != mState.mUniforms.rend() && samplerIter->isSampler())
1949 {
1950 --mState.mSamplerUniformRange.start;
1951 ++samplerIter;
1952 }
1953 // If uniform is a sampler type, insert it into the mSamplerBindings array.
1954 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
1955 samplerIndex < mState.mUniforms.size(); ++samplerIndex)
1956 {
1957 const auto &samplerUniform = mState.mUniforms[samplerIndex];
1958 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
1959 mState.mSamplerBindings.emplace_back(
1960 SamplerBinding(textureType, samplerUniform.elementCount()));
1961 }
1962}
1963
Martin Radev4c4c8e72016-08-04 12:25:34 +03001964bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
1965 const std::string &uniformName,
1966 const sh::InterfaceBlockField &vertexUniform,
1967 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001968{
Jamie Madillc4c744222015-11-04 09:39:47 -05001969 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1970 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001971 {
1972 return false;
1973 }
1974
1975 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1976 {
Jamie Madillf6113162015-05-07 11:49:21 -04001977 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001978 return false;
1979 }
1980
1981 return true;
1982}
1983
Jamie Madilleb979bf2016-11-15 12:28:46 -05001984// Assigns locations to all attributes from the bindings and program locations.
1985bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001986{
Jamie Madilleb979bf2016-11-15 12:28:46 -05001987 const auto *vertexShader = mState.getAttachedVertexShader();
1988
Geoff Lang7dd2e102014-11-10 15:19:26 -05001989 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001990 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001991 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04001992
1993 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001994 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001995 {
Jamie Madillf6113162015-05-07 11:49:21 -04001996 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001997 return false;
1998 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001999
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002000 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002001
Jamie Madillc349ec02015-08-21 16:53:12 -04002002 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002003 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002004 {
Jamie Madilleb979bf2016-11-15 12:28:46 -05002005 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002006 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002007 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002008 attribute.location = bindingLocation;
2009 }
2010
2011 if (attribute.location != -1)
2012 {
2013 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002014 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002015
Jamie Madill63805b42015-08-25 13:17:39 -04002016 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017 {
Jamie Madillf6113162015-05-07 11:49:21 -04002018 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002019 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002020
2021 return false;
2022 }
2023
Jamie Madill63805b42015-08-25 13:17:39 -04002024 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002025 {
Jamie Madill63805b42015-08-25 13:17:39 -04002026 const int regLocation = attribute.location + reg;
2027 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002028
2029 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002030 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002031 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002032 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002033 // TODO(jmadill): fix aliasing on ES2
2034 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002035 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002036 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002037 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002038 return false;
2039 }
2040 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002041 else
2042 {
Jamie Madill63805b42015-08-25 13:17:39 -04002043 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002044 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045
Jamie Madill63805b42015-08-25 13:17:39 -04002046 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002047 }
2048 }
2049 }
2050
2051 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002052 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002053 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002054 // Not set by glBindAttribLocation or by location layout qualifier
2055 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002056 {
Jamie Madill63805b42015-08-25 13:17:39 -04002057 int regs = VariableRegisterCount(attribute.type);
2058 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002059
Jamie Madill63805b42015-08-25 13:17:39 -04002060 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002061 {
Jamie Madillf6113162015-05-07 11:49:21 -04002062 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002063 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002064 }
2065
Jamie Madillc349ec02015-08-21 16:53:12 -04002066 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002067 }
2068 }
2069
Jamie Madill48ef11b2016-04-27 15:21:52 -04002070 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071 {
Jamie Madill63805b42015-08-25 13:17:39 -04002072 ASSERT(attribute.location != -1);
2073 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002074
Jamie Madill63805b42015-08-25 13:17:39 -04002075 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002076 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002077 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002078 }
2079 }
2080
Geoff Lang7dd2e102014-11-10 15:19:26 -05002081 return true;
2082}
2083
Martin Radev4c4c8e72016-08-04 12:25:34 +03002084bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2085 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2086 const std::string &errorMessage,
2087 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002088{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002089 GLuint blockCount = 0;
2090 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002091 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002092 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002093 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002094 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002095 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002096 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002097 return false;
2098 }
2099 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002100 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002101 return true;
2102}
Jamie Madille473dee2015-08-18 14:49:01 -04002103
Martin Radev4c4c8e72016-08-04 12:25:34 +03002104bool Program::validateVertexAndFragmentInterfaceBlocks(
2105 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2106 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2107 InfoLog &infoLog) const
2108{
2109 // Check that interface blocks defined in the vertex and fragment shaders are identical
2110 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2111 UniformBlockMap linkedUniformBlocks;
2112
2113 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2114 {
2115 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2116 }
2117
Jamie Madille473dee2015-08-18 14:49:01 -04002118 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002119 {
Jamie Madille473dee2015-08-18 14:49:01 -04002120 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002121 if (entry != linkedUniformBlocks.end())
2122 {
2123 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2124 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2125 {
2126 return false;
2127 }
2128 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002129 }
2130 return true;
2131}
Jamie Madille473dee2015-08-18 14:49:01 -04002132
Martin Radev4c4c8e72016-08-04 12:25:34 +03002133bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2134{
2135 if (mState.mAttachedComputeShader)
2136 {
2137 const Shader &computeShader = *mState.mAttachedComputeShader;
2138 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2139
2140 if (!validateUniformBlocksCount(
2141 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2142 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2143 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002145 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002146 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002147 return true;
2148 }
2149
2150 const Shader &vertexShader = *mState.mAttachedVertexShader;
2151 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2152
2153 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2154 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2155
2156 if (!validateUniformBlocksCount(
2157 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2158 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2159 {
2160 return false;
2161 }
2162 if (!validateUniformBlocksCount(
2163 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2164 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2165 infoLog))
2166 {
2167
2168 return false;
2169 }
2170 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2171 infoLog))
2172 {
2173 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 }
Jamie Madille473dee2015-08-18 14:49:01 -04002175
Geoff Lang7dd2e102014-11-10 15:19:26 -05002176 return true;
2177}
2178
Jamie Madilla2c74982016-12-12 11:20:42 -05002179bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002180 const sh::InterfaceBlock &vertexInterfaceBlock,
2181 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002182{
2183 const char* blockName = vertexInterfaceBlock.name.c_str();
2184 // validate blocks for the same member types
2185 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2186 {
Jamie Madillf6113162015-05-07 11:49:21 -04002187 infoLog << "Types for interface block '" << blockName
2188 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189 return false;
2190 }
2191 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2192 {
Jamie Madillf6113162015-05-07 11:49:21 -04002193 infoLog << "Array sizes differ for interface block '" << blockName
2194 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002195 return false;
2196 }
2197 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2198 {
Jamie Madillf6113162015-05-07 11:49:21 -04002199 infoLog << "Layout qualifiers differ for interface block '" << blockName
2200 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002201 return false;
2202 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002203 const unsigned int numBlockMembers =
2204 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2206 {
2207 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2208 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2209 if (vertexMember.name != fragmentMember.name)
2210 {
Jamie Madillf6113162015-05-07 11:49:21 -04002211 infoLog << "Name mismatch for field " << blockMemberIndex
2212 << " of interface block '" << blockName
2213 << "': (in vertex: '" << vertexMember.name
2214 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002215 return false;
2216 }
2217 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2218 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2219 {
2220 return false;
2221 }
2222 }
2223 return true;
2224}
2225
2226bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2227 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2228{
2229 if (vertexVariable.type != fragmentVariable.type)
2230 {
Jamie Madillf6113162015-05-07 11:49:21 -04002231 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002232 return false;
2233 }
2234 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2235 {
Jamie Madillf6113162015-05-07 11:49:21 -04002236 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002237 return false;
2238 }
2239 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2240 {
Jamie Madillf6113162015-05-07 11:49:21 -04002241 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002242 return false;
2243 }
2244
2245 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2246 {
Jamie Madillf6113162015-05-07 11:49:21 -04002247 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002248 return false;
2249 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002250 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002251 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2252 {
2253 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2254 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2255
2256 if (vertexMember.name != fragmentMember.name)
2257 {
Jamie Madillf6113162015-05-07 11:49:21 -04002258 infoLog << "Name mismatch for field '" << memberIndex
2259 << "' of " << variableName
2260 << ": (in vertex: '" << vertexMember.name
2261 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002262 return false;
2263 }
2264
2265 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2266 vertexMember.name + "'";
2267
2268 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2269 {
2270 return false;
2271 }
2272 }
2273
2274 return true;
2275}
2276
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002277bool Program::linkValidateVaryings(InfoLog &infoLog,
2278 const std::string &varyingName,
2279 const sh::Varying &vertexVarying,
2280 const sh::Varying &fragmentVarying,
2281 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002282{
2283 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2284 {
2285 return false;
2286 }
2287
Jamie Madille9cc4692015-02-19 16:00:13 -05002288 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002289 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002290 infoLog << "Interpolation types for " << varyingName
2291 << " differ between vertex and fragment shaders.";
2292 return false;
2293 }
2294
2295 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2296 {
2297 infoLog << "Invariance for " << varyingName
2298 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002299 return false;
2300 }
2301
2302 return true;
2303}
2304
Yuly Novikov817232e2017-02-22 18:36:10 -05002305bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
2306{
2307 const Shader *vertexShader = mState.mAttachedVertexShader;
2308 const Shader *fragmentShader = mState.mAttachedFragmentShader;
2309 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
2310 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
2311 int shaderVersion = vertexShader->getShaderVersion();
2312
2313 if (shaderVersion != 100)
2314 {
2315 // Only ESSL 1.0 has restrictions on matching input and output invariance
2316 return true;
2317 }
2318
2319 bool glPositionIsInvariant = false;
2320 bool glPointSizeIsInvariant = false;
2321 bool glFragCoordIsInvariant = false;
2322 bool glPointCoordIsInvariant = false;
2323
2324 for (const sh::Varying &varying : vertexVaryings)
2325 {
2326 if (!varying.isBuiltIn())
2327 {
2328 continue;
2329 }
2330 if (varying.name.compare("gl_Position") == 0)
2331 {
2332 glPositionIsInvariant = varying.isInvariant;
2333 }
2334 else if (varying.name.compare("gl_PointSize") == 0)
2335 {
2336 glPointSizeIsInvariant = varying.isInvariant;
2337 }
2338 }
2339
2340 for (const sh::Varying &varying : fragmentVaryings)
2341 {
2342 if (!varying.isBuiltIn())
2343 {
2344 continue;
2345 }
2346 if (varying.name.compare("gl_FragCoord") == 0)
2347 {
2348 glFragCoordIsInvariant = varying.isInvariant;
2349 }
2350 else if (varying.name.compare("gl_PointCoord") == 0)
2351 {
2352 glPointCoordIsInvariant = varying.isInvariant;
2353 }
2354 }
2355
2356 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2357 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2358 // Not requiring invariance to match is supported by:
2359 // dEQP, WebGL CTS, Nexus 5X GLES
2360 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2361 {
2362 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2363 "declared invariant.";
2364 return false;
2365 }
2366 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2367 {
2368 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2369 "declared invariant.";
2370 return false;
2371 }
2372
2373 return true;
2374}
2375
Jamie Madillccdf74b2015-08-18 10:46:12 -04002376bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002377 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002378 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002379{
2380 size_t totalComponents = 0;
2381
Jamie Madillccdf74b2015-08-18 10:46:12 -04002382 std::set<std::string> uniqueNames;
2383
Jamie Madill48ef11b2016-04-27 15:21:52 -04002384 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002385 {
2386 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002387 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002388 {
Jamie Madill192745a2016-12-22 15:58:21 -05002389 const sh::Varying *varying = ref.second.get();
2390
Jamie Madillccdf74b2015-08-18 10:46:12 -04002391 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002393 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002394 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002395 infoLog << "Two transform feedback varyings specify the same output variable ("
2396 << tfVaryingName << ").";
2397 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002398 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002399 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002400
Geoff Lang1a683462015-09-29 15:09:59 -04002401 if (varying->isArray())
2402 {
2403 infoLog << "Capture of arrays is undefined and not supported.";
2404 return false;
2405 }
2406
Jamie Madillccdf74b2015-08-18 10:46:12 -04002407 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002408 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002409 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002410 componentCount > caps.maxTransformFeedbackSeparateComponents)
2411 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002412 infoLog << "Transform feedback varying's " << varying->name << " components ("
2413 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002414 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002415 return false;
2416 }
2417
2418 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002419 found = true;
2420 break;
2421 }
2422 }
2423
Jamie Madill89bb70e2015-08-31 14:18:39 -04002424 if (tfVaryingName.find('[') != std::string::npos)
2425 {
Geoff Lang1a683462015-09-29 15:09:59 -04002426 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002427 return false;
2428 }
2429
Geoff Lang7dd2e102014-11-10 15:19:26 -05002430 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2431 ASSERT(found);
2432 }
2433
Jamie Madill48ef11b2016-04-27 15:21:52 -04002434 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002435 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002436 {
Jamie Madillf6113162015-05-07 11:49:21 -04002437 infoLog << "Transform feedback varying total components (" << totalComponents
2438 << ") exceed the maximum interleaved components ("
2439 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002440 return false;
2441 }
2442
2443 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002444}
2445
Jamie Madill192745a2016-12-22 15:58:21 -05002446void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002447{
2448 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002449 mState.mTransformFeedbackVaryingVars.clear();
2450 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002451 {
Jamie Madill192745a2016-12-22 15:58:21 -05002452 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002453 {
Jamie Madill192745a2016-12-22 15:58:21 -05002454 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002455 if (tfVaryingName == varying->name)
2456 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002457 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002458 break;
2459 }
2460 }
2461 }
2462}
2463
Jamie Madill192745a2016-12-22 15:58:21 -05002464Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002465{
Jamie Madill192745a2016-12-22 15:58:21 -05002466 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002467
Jamie Madill48ef11b2016-04-27 15:21:52 -04002468 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002469 {
Jamie Madill192745a2016-12-22 15:58:21 -05002470 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002471 }
2472
Jamie Madill48ef11b2016-04-27 15:21:52 -04002473 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002474 {
Jamie Madill192745a2016-12-22 15:58:21 -05002475 merged[varying.name].fragment = &varying;
2476 }
2477
2478 return merged;
2479}
2480
2481std::vector<PackedVarying> Program::getPackedVaryings(
2482 const Program::MergedVaryings &mergedVaryings) const
2483{
2484 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2485 std::vector<PackedVarying> packedVaryings;
2486
2487 for (const auto &ref : mergedVaryings)
2488 {
2489 const sh::Varying *input = ref.second.vertex;
2490 const sh::Varying *output = ref.second.fragment;
2491
2492 // Only pack varyings that have a matched input or output, plus special builtins.
2493 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002494 {
Jamie Madill192745a2016-12-22 15:58:21 -05002495 // Will get the vertex shader interpolation by default.
2496 auto interpolation = ref.second.get()->interpolation;
2497
2498 // Interpolation qualifiers must match.
2499 if (output->isStruct())
2500 {
2501 ASSERT(!output->isArray());
2502 for (const auto &field : output->fields)
2503 {
2504 ASSERT(!field.isStruct() && !field.isArray());
2505 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2506 }
2507 }
2508 else
2509 {
2510 packedVaryings.push_back(PackedVarying(*output, interpolation));
2511 }
2512 continue;
2513 }
2514
2515 // Keep Transform FB varyings in the merged list always.
2516 if (!input)
2517 {
2518 continue;
2519 }
2520
2521 for (const std::string &tfVarying : tfVaryings)
2522 {
2523 if (tfVarying == input->name)
2524 {
2525 // Transform feedback for varying structs is underspecified.
2526 // See Khronos bug 9856.
2527 // TODO(jmadill): Figure out how to be spec-compliant here.
2528 if (!input->isStruct())
2529 {
2530 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2531 packedVaryings.back().vertexOnly = true;
2532 }
2533 break;
2534 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002535 }
2536 }
2537
Jamie Madill192745a2016-12-22 15:58:21 -05002538 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2539
2540 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002541}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002542
2543void Program::linkOutputVariables()
2544{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002545 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002546 ASSERT(fragmentShader != nullptr);
2547
2548 // Skip this step for GLES2 shaders.
2549 if (fragmentShader->getShaderVersion() == 100)
2550 return;
2551
jchen1015015f72017-03-16 13:54:21 +08002552 mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002553 // TODO(jmadill): any caps validation here?
2554
jchen1015015f72017-03-16 13:54:21 +08002555 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002556 outputVariableIndex++)
2557 {
jchen1015015f72017-03-16 13:54:21 +08002558 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002559
2560 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2561 if (outputVariable.isBuiltIn())
2562 continue;
2563
2564 // Since multiple output locations must be specified, use 0 for non-specified locations.
2565 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2566
Jamie Madill80a6fc02015-08-21 16:53:16 -04002567 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2568 elementIndex++)
2569 {
2570 const int location = baseLocation + elementIndex;
jchen1015015f72017-03-16 13:54:21 +08002571 ASSERT(mState.mOutputLocations.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002572 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08002573 mState.mOutputLocations[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002574 VariableLocation(outputVariable.name, element, outputVariableIndex);
2575 }
2576 }
2577}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002578
Olli Etuaho48fed632017-03-16 12:05:30 +00002579void Program::setUniformValuesFromBindingQualifiers()
2580{
2581 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
2582 samplerIndex < mState.mSamplerUniformRange.end; ++samplerIndex)
2583 {
2584 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2585 if (samplerUniform.binding != -1)
2586 {
2587 GLint location = mState.getUniformLocation(samplerUniform.name);
2588 ASSERT(location != -1);
2589 std::vector<GLint> boundTextureUnits;
2590 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2591 ++elementIndex)
2592 {
2593 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2594 }
2595 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2596 boundTextureUnits.data());
2597 }
2598 }
2599}
2600
Jamie Madill62d31cb2015-09-11 13:25:51 -04002601void Program::gatherInterfaceBlockInfo()
2602{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002603 ASSERT(mState.mUniformBlocks.empty());
2604
2605 if (mState.mAttachedComputeShader)
2606 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002607 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002608
2609 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2610 {
2611
2612 // Only 'packed' blocks are allowed to be considered inactive.
2613 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2614 continue;
2615
Jamie Madilla2c74982016-12-12 11:20:42 -05002616 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002617 {
2618 if (block.name == computeBlock.name)
2619 {
2620 block.computeStaticUse = computeBlock.staticUse;
2621 }
2622 }
2623
2624 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2625 }
2626 return;
2627 }
2628
Jamie Madill62d31cb2015-09-11 13:25:51 -04002629 std::set<std::string> visitedList;
2630
Jamie Madilla2c74982016-12-12 11:20:42 -05002631 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002632
Jamie Madill62d31cb2015-09-11 13:25:51 -04002633 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2634 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002635 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002636 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2637 continue;
2638
2639 if (visitedList.count(vertexBlock.name) > 0)
2640 continue;
2641
2642 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2643 visitedList.insert(vertexBlock.name);
2644 }
2645
Jamie Madilla2c74982016-12-12 11:20:42 -05002646 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002647
2648 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2649 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002650 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002651 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2652 continue;
2653
2654 if (visitedList.count(fragmentBlock.name) > 0)
2655 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002656 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002657 {
2658 if (block.name == fragmentBlock.name)
2659 {
2660 block.fragmentStaticUse = fragmentBlock.staticUse;
2661 }
2662 }
2663
2664 continue;
2665 }
2666
2667 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2668 visitedList.insert(fragmentBlock.name);
2669 }
2670}
2671
Jamie Madill4a3c2342015-10-08 12:58:45 -04002672template <typename VarT>
2673void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2674 const std::string &prefix,
2675 int blockIndex)
2676{
2677 for (const VarT &field : fields)
2678 {
2679 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2680
2681 if (field.isStruct())
2682 {
2683 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2684 {
2685 const std::string uniformElementName =
2686 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2687 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2688 }
2689 }
2690 else
2691 {
2692 // If getBlockMemberInfo returns false, the uniform is optimized out.
2693 sh::BlockMemberInfo memberInfo;
2694 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2695 {
2696 continue;
2697 }
2698
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002699 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04002700 blockIndex, memberInfo);
2701
2702 // Since block uniforms have no location, we don't need to store them in the uniform
2703 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002704 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002705 }
2706 }
2707}
2708
Jamie Madill62d31cb2015-09-11 13:25:51 -04002709void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2710{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002711 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002712 size_t blockSize = 0;
2713
2714 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002715 std::stringstream blockNameStr;
2716 blockNameStr << interfaceBlock.name;
2717 if (interfaceBlock.arraySize > 0)
2718 {
2719 blockNameStr << "[0]";
2720 }
2721 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002722 {
2723 return;
2724 }
2725
2726 // Track the first and last uniform index to determine the range of active uniforms in the
2727 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002728 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002729 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002730 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002731
2732 std::vector<unsigned int> blockUniformIndexes;
2733 for (size_t blockUniformIndex = firstBlockUniformIndex;
2734 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2735 {
2736 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2737 }
2738
2739 if (interfaceBlock.arraySize > 0)
2740 {
2741 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2742 {
2743 UniformBlock block(interfaceBlock.name, true, arrayElement);
2744 block.memberUniformIndexes = blockUniformIndexes;
2745
Martin Radev4c4c8e72016-08-04 12:25:34 +03002746 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002747 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002748 case GL_VERTEX_SHADER:
2749 {
2750 block.vertexStaticUse = interfaceBlock.staticUse;
2751 break;
2752 }
2753 case GL_FRAGMENT_SHADER:
2754 {
2755 block.fragmentStaticUse = interfaceBlock.staticUse;
2756 break;
2757 }
2758 case GL_COMPUTE_SHADER:
2759 {
2760 block.computeStaticUse = interfaceBlock.staticUse;
2761 break;
2762 }
2763 default:
2764 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002765 }
2766
Qin Jiajia0350a642016-11-01 17:01:51 +08002767 // Since all block elements in an array share the same active uniforms, they will all be
2768 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2769 // here we will add every block element in the array.
2770 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002771 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002772 }
2773 }
2774 else
2775 {
2776 UniformBlock block(interfaceBlock.name, false, 0);
2777 block.memberUniformIndexes = blockUniformIndexes;
2778
Martin Radev4c4c8e72016-08-04 12:25:34 +03002779 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002780 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002781 case GL_VERTEX_SHADER:
2782 {
2783 block.vertexStaticUse = interfaceBlock.staticUse;
2784 break;
2785 }
2786 case GL_FRAGMENT_SHADER:
2787 {
2788 block.fragmentStaticUse = interfaceBlock.staticUse;
2789 break;
2790 }
2791 case GL_COMPUTE_SHADER:
2792 {
2793 block.computeStaticUse = interfaceBlock.staticUse;
2794 break;
2795 }
2796 default:
2797 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002798 }
2799
Jamie Madill4a3c2342015-10-08 12:58:45 -04002800 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002801 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002802 }
2803}
2804
Jamie Madille7d84322017-01-10 18:21:59 -05002805template <>
2806void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2807 const uint8_t *destPointer,
2808 GLsizei clampedCount,
2809 const GLint *v)
2810{
2811 // Invalidate the validation cache only if we modify the sampler data.
2812 if (mState.isSamplerUniformIndex(locationInfo.index) &&
2813 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
2814 {
2815 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2816 std::vector<GLuint> *boundTextureUnits =
2817 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
2818
2819 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
2820 mCachedValidateSamplersResult.reset();
2821 }
2822}
2823
2824template <typename T>
2825void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2826 const uint8_t *destPointer,
2827 GLsizei clampedCount,
2828 const T *v)
2829{
2830}
2831
Jamie Madill62d31cb2015-09-11 13:25:51 -04002832template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002833GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002834{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002835 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2836 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002837 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2838
Corentin Wallez15ac5342016-11-03 17:06:39 -04002839 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2840 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2841 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002842 GLsizei maxElementCount =
2843 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2844
2845 GLsizei count = countIn;
2846 GLsizei clampedCount = count * vectorSize;
2847 if (clampedCount > maxElementCount)
2848 {
2849 clampedCount = maxElementCount;
2850 count = maxElementCount / vectorSize;
2851 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002852
Jamie Madill62d31cb2015-09-11 13:25:51 -04002853 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2854 {
2855 // Do a cast conversion for boolean types. From the spec:
2856 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2857 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002858 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002859 {
2860 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2861 }
2862 }
2863 else
2864 {
Jamie Madille7d84322017-01-10 18:21:59 -05002865 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002866 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002867 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002868
2869 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002870}
2871
2872template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002873GLsizei Program::setMatrixUniformInternal(GLint location,
2874 GLsizei count,
2875 GLboolean transpose,
2876 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002877{
2878 if (!transpose)
2879 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002880 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002881 }
2882
2883 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002884 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2885 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002886 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04002887
2888 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2889 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2890 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
2891 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
2892
2893 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002894 {
2895 size_t elementOffset = element * rows * cols;
2896
2897 for (size_t row = 0; row < rows; ++row)
2898 {
2899 for (size_t col = 0; col < cols; ++col)
2900 {
2901 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2902 }
2903 }
2904 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002905
2906 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002907}
2908
2909template <typename DestT>
2910void Program::getUniformInternal(GLint location, DestT *dataOut) const
2911{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002912 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2913 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002914
2915 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2916
2917 GLenum componentType = VariableComponentType(uniform.type);
2918 if (componentType == GLTypeToGLenum<DestT>::value)
2919 {
2920 memcpy(dataOut, srcPointer, uniform.getElementSize());
2921 return;
2922 }
2923
Corentin Wallez6596c462016-03-17 17:26:58 -04002924 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002925
2926 switch (componentType)
2927 {
2928 case GL_INT:
2929 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2930 break;
2931 case GL_UNSIGNED_INT:
2932 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2933 break;
2934 case GL_BOOL:
2935 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2936 break;
2937 case GL_FLOAT:
2938 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2939 break;
2940 default:
2941 UNREACHABLE();
2942 }
2943}
Jamie Madilla4595b82017-01-11 17:36:34 -05002944
2945bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
2946{
2947 // Must be called after samplers are validated.
2948 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
2949
2950 for (const auto &binding : mState.mSamplerBindings)
2951 {
2952 GLenum textureType = binding.textureType;
2953 for (const auto &unit : binding.boundTextureUnits)
2954 {
2955 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
2956 if (programTextureID == textureID)
2957 {
2958 // TODO(jmadill): Check for appropriate overlap.
2959 return true;
2960 }
2961 }
2962 }
2963
2964 return false;
2965}
2966
Jamie Madilla2c74982016-12-12 11:20:42 -05002967} // namespace gl