blob: 396d8c6860af0bfc73d6dba88e30a66aeb5c264e [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
Jamie Madill4a3c2342015-10-08 12:58:45 -0400714 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400715
Martin Radev4c4c8e72016-08-04 12:25:34 +0300716 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000717}
718
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000719// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500720void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000721{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400722 mState.mAttributes.clear();
723 mState.mActiveAttribLocationsMask.reset();
724 mState.mTransformFeedbackVaryingVars.clear();
725 mState.mUniforms.clear();
726 mState.mUniformLocations.clear();
727 mState.mUniformBlocks.clear();
728 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800729 mState.mOutputLocations.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300730 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500731 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500732
Geoff Lang7dd2e102014-11-10 15:19:26 -0500733 mValidated = false;
734
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000735 mLinked = false;
736}
737
Geoff Lange1a27752015-10-05 13:16:04 -0400738bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000739{
740 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741}
742
Jamie Madilla2c74982016-12-12 11:20:42 -0500743Error Program::loadBinary(const Context *context,
744 GLenum binaryFormat,
745 const void *binary,
746 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000747{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500748 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000749
Geoff Lang7dd2e102014-11-10 15:19:26 -0500750#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800751 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400753 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
754 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000755 {
Jamie Madillf6113162015-05-07 11:49:21 -0400756 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800757 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500758 }
759
Geoff Langc46cc2f2015-10-01 17:16:20 -0400760 BinaryInputStream stream(binary, length);
761
Jamie Madilla2c74982016-12-12 11:20:42 -0500762 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
763 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
764 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
765 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500766 {
Jamie Madillf6113162015-05-07 11:49:21 -0400767 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800768 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500769 }
770
Jamie Madilla2c74982016-12-12 11:20:42 -0500771 int majorVersion = stream.readInt<int>();
772 int minorVersion = stream.readInt<int>();
773 if (majorVersion != context->getClientMajorVersion() ||
774 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500775 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500776 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800777 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500778 }
779
Martin Radev4c4c8e72016-08-04 12:25:34 +0300780 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
781 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
782 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
783
Jamie Madill63805b42015-08-25 13:17:39 -0400784 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
785 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400786 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500787
Jamie Madill3da79b72015-04-27 11:09:17 -0400788 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400789 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400790 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
791 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400792 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400793 LoadShaderVar(&stream, &attrib);
794 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400795 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400796 }
797
Jamie Madill62d31cb2015-09-11 13:25:51 -0400798 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400799 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400800 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
801 {
802 LinkedUniform uniform;
803 LoadShaderVar(&stream, &uniform);
804
805 uniform.blockIndex = stream.readInt<int>();
806 uniform.blockInfo.offset = stream.readInt<int>();
807 uniform.blockInfo.arrayStride = stream.readInt<int>();
808 uniform.blockInfo.matrixStride = stream.readInt<int>();
809 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
810
Jamie Madill48ef11b2016-04-27 15:21:52 -0400811 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400812 }
813
814 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400815 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400816 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
817 uniformIndexIndex++)
818 {
819 VariableLocation variable;
820 stream.readString(&variable.name);
821 stream.readInt(&variable.element);
822 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400823 stream.readBool(&variable.used);
824 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400825
Jamie Madill48ef11b2016-04-27 15:21:52 -0400826 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400827 }
828
829 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400830 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400831 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
832 ++uniformBlockIndex)
833 {
834 UniformBlock uniformBlock;
835 stream.readString(&uniformBlock.name);
836 stream.readBool(&uniformBlock.isArray);
837 stream.readInt(&uniformBlock.arrayElement);
838 stream.readInt(&uniformBlock.dataSize);
839 stream.readBool(&uniformBlock.vertexStaticUse);
840 stream.readBool(&uniformBlock.fragmentStaticUse);
841
842 unsigned int numMembers = stream.readInt<unsigned int>();
843 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
844 {
845 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
846 }
847
Jamie Madill48ef11b2016-04-27 15:21:52 -0400848 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400849 }
850
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500851 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
852 ++bindingIndex)
853 {
854 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
855 mState.mActiveUniformBlockBindings.set(bindingIndex,
856 mState.mUniformBlockBindings[bindingIndex] != 0);
857 }
858
Brandon Jones1048ea72015-10-06 15:34:52 -0700859 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400860 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700861 for (unsigned int transformFeedbackVaryingIndex = 0;
862 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
863 ++transformFeedbackVaryingIndex)
864 {
865 sh::Varying varying;
866 stream.readInt(&varying.arraySize);
867 stream.readInt(&varying.type);
868 stream.readString(&varying.name);
869
Jamie Madill48ef11b2016-04-27 15:21:52 -0400870 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700871 }
872
Jamie Madill48ef11b2016-04-27 15:21:52 -0400873 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400874
jchen1015015f72017-03-16 13:54:21 +0800875 unsigned int outputCount = stream.readInt<unsigned int>();
876 ASSERT(mState.mOutputVariables.empty());
877 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
878 {
879 sh::OutputVariable output;
880 LoadShaderVar(&stream, &output);
881 output.location = stream.readInt<int>();
882 mState.mOutputVariables.push_back(output);
883 }
884
Jamie Madill80a6fc02015-08-21 16:53:16 -0400885 unsigned int outputVarCount = stream.readInt<unsigned int>();
886 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
887 {
888 int locationIndex = stream.readInt<int>();
889 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400890 stream.readInt(&locationData.element);
891 stream.readInt(&locationData.index);
892 stream.readString(&locationData.name);
jchen1015015f72017-03-16 13:54:21 +0800893 mState.mOutputLocations[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400894 }
895
Jamie Madille7d84322017-01-10 18:21:59 -0500896 stream.readInt(&mState.mSamplerUniformRange.start);
897 stream.readInt(&mState.mSamplerUniformRange.end);
898
899 unsigned int samplerCount = stream.readInt<unsigned int>();
900 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
901 {
902 GLenum textureType = stream.readInt<GLenum>();
903 size_t bindingCount = stream.readInt<size_t>();
904 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
905 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400906
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500907 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000908
Jamie Madillb0a838b2016-11-13 20:02:12 -0500909 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500910#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500911}
912
Jamie Madilla2c74982016-12-12 11:20:42 -0500913Error Program::saveBinary(const Context *context,
914 GLenum *binaryFormat,
915 void *binary,
916 GLsizei bufSize,
917 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500918{
919 if (binaryFormat)
920 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400921 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500922 }
923
924 BinaryOutputStream stream;
925
Geoff Lang7dd2e102014-11-10 15:19:26 -0500926 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
927
Jamie Madilla2c74982016-12-12 11:20:42 -0500928 // nullptr context is supported when computing binary length.
929 if (context)
930 {
931 stream.writeInt(context->getClientVersion().major);
932 stream.writeInt(context->getClientVersion().minor);
933 }
934 else
935 {
936 stream.writeInt(2);
937 stream.writeInt(0);
938 }
939
Martin Radev4c4c8e72016-08-04 12:25:34 +0300940 stream.writeInt(mState.mComputeShaderLocalSize[0]);
941 stream.writeInt(mState.mComputeShaderLocalSize[1]);
942 stream.writeInt(mState.mComputeShaderLocalSize[2]);
943
Jamie Madill48ef11b2016-04-27 15:21:52 -0400944 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500945
Jamie Madill48ef11b2016-04-27 15:21:52 -0400946 stream.writeInt(mState.mAttributes.size());
947 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400948 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400949 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400950 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400951 }
952
Jamie Madill48ef11b2016-04-27 15:21:52 -0400953 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500954 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400955 {
956 WriteShaderVar(&stream, uniform);
957
958 // FIXME: referenced
959
960 stream.writeInt(uniform.blockIndex);
961 stream.writeInt(uniform.blockInfo.offset);
962 stream.writeInt(uniform.blockInfo.arrayStride);
963 stream.writeInt(uniform.blockInfo.matrixStride);
964 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
965 }
966
Jamie Madill48ef11b2016-04-27 15:21:52 -0400967 stream.writeInt(mState.mUniformLocations.size());
968 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400969 {
970 stream.writeString(variable.name);
971 stream.writeInt(variable.element);
972 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400973 stream.writeInt(variable.used);
974 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400975 }
976
Jamie Madill48ef11b2016-04-27 15:21:52 -0400977 stream.writeInt(mState.mUniformBlocks.size());
978 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400979 {
980 stream.writeString(uniformBlock.name);
981 stream.writeInt(uniformBlock.isArray);
982 stream.writeInt(uniformBlock.arrayElement);
983 stream.writeInt(uniformBlock.dataSize);
984
985 stream.writeInt(uniformBlock.vertexStaticUse);
986 stream.writeInt(uniformBlock.fragmentStaticUse);
987
988 stream.writeInt(uniformBlock.memberUniformIndexes.size());
989 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
990 {
991 stream.writeInt(memberUniformIndex);
992 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400993 }
994
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500995 for (GLuint binding : mState.mUniformBlockBindings)
996 {
997 stream.writeInt(binding);
998 }
999
Jamie Madill48ef11b2016-04-27 15:21:52 -04001000 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
1001 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -07001002 {
1003 stream.writeInt(varying.arraySize);
1004 stream.writeInt(varying.type);
1005 stream.writeString(varying.name);
1006 }
1007
Jamie Madill48ef11b2016-04-27 15:21:52 -04001008 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001009
Jamie Madill48ef11b2016-04-27 15:21:52 -04001010 stream.writeInt(mState.mOutputVariables.size());
jchen1015015f72017-03-16 13:54:21 +08001011 for (const sh::OutputVariable &output : mState.mOutputVariables)
1012 {
1013 WriteShaderVar(&stream, output);
1014 stream.writeInt(output.location);
1015 }
1016
1017 stream.writeInt(mState.mOutputLocations.size());
1018 for (const auto &outputPair : mState.mOutputLocations)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001019 {
1020 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001021 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001022 stream.writeInt(outputPair.second.index);
1023 stream.writeString(outputPair.second.name);
1024 }
1025
Jamie Madille7d84322017-01-10 18:21:59 -05001026 stream.writeInt(mState.mSamplerUniformRange.start);
1027 stream.writeInt(mState.mSamplerUniformRange.end);
1028
1029 stream.writeInt(mState.mSamplerBindings.size());
1030 for (const auto &samplerBinding : mState.mSamplerBindings)
1031 {
1032 stream.writeInt(samplerBinding.textureType);
1033 stream.writeInt(samplerBinding.boundTextureUnits.size());
1034 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001035
Jamie Madilla2c74982016-12-12 11:20:42 -05001036 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001037
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001038 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001039 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001040
1041 if (streamLength > bufSize)
1042 {
1043 if (length)
1044 {
1045 *length = 0;
1046 }
1047
1048 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1049 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1050 // sizes and then copy it.
1051 return Error(GL_INVALID_OPERATION);
1052 }
1053
1054 if (binary)
1055 {
1056 char *ptr = reinterpret_cast<char*>(binary);
1057
Jamie Madill48ef11b2016-04-27 15:21:52 -04001058 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001059 ptr += streamLength;
1060
1061 ASSERT(ptr - streamLength == binary);
1062 }
1063
1064 if (length)
1065 {
1066 *length = streamLength;
1067 }
1068
He Yunchaoacd18982017-01-04 10:46:42 +08001069 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001070}
1071
1072GLint Program::getBinaryLength() const
1073{
1074 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001075 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001076 if (error.isError())
1077 {
1078 return 0;
1079 }
1080
1081 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001082}
1083
Geoff Langc5629752015-12-07 16:29:04 -05001084void Program::setBinaryRetrievableHint(bool retrievable)
1085{
1086 // TODO(jmadill) : replace with dirty bits
1087 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001088 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001089}
1090
1091bool Program::getBinaryRetrievableHint() const
1092{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001093 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001094}
1095
Jamie Madill6c1f6712017-02-14 19:08:04 -05001096void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001097{
1098 mRefCount--;
1099
1100 if (mRefCount == 0 && mDeleteStatus)
1101 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001102 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001103 }
1104}
1105
1106void Program::addRef()
1107{
1108 mRefCount++;
1109}
1110
1111unsigned int Program::getRefCount() const
1112{
1113 return mRefCount;
1114}
1115
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001116int Program::getInfoLogLength() const
1117{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001118 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001119}
1120
Geoff Lange1a27752015-10-05 13:16:04 -04001121void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001122{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001123 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001124}
1125
Geoff Lange1a27752015-10-05 13:16:04 -04001126void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001127{
1128 int total = 0;
1129
Martin Radev4c4c8e72016-08-04 12:25:34 +03001130 if (mState.mAttachedComputeShader)
1131 {
1132 if (total < maxCount)
1133 {
1134 shaders[total] = mState.mAttachedComputeShader->getHandle();
1135 total++;
1136 }
1137 }
1138
Jamie Madill48ef11b2016-04-27 15:21:52 -04001139 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001140 {
1141 if (total < maxCount)
1142 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001143 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001144 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001145 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001146 }
1147
Jamie Madill48ef11b2016-04-27 15:21:52 -04001148 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001149 {
1150 if (total < maxCount)
1151 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001152 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001153 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001154 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001155 }
1156
1157 if (count)
1158 {
1159 *count = total;
1160 }
1161}
1162
Geoff Lange1a27752015-10-05 13:16:04 -04001163GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001164{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001165 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001166 {
jchen1036e120e2017-03-14 14:53:58 +08001167 if (attribute.name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001168 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001169 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001170 }
1171 }
1172
Austin Kinrossb8af7232015-03-16 22:33:25 -07001173 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001174}
1175
Jamie Madill63805b42015-08-25 13:17:39 -04001176bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001177{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001178 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1179 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001180}
1181
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001182void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1183{
Jamie Madillc349ec02015-08-21 16:53:12 -04001184 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001185 {
1186 if (bufsize > 0)
1187 {
1188 name[0] = '\0';
1189 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001190
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001191 if (length)
1192 {
1193 *length = 0;
1194 }
1195
1196 *type = GL_NONE;
1197 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001198 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001199 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001200
jchen1036e120e2017-03-14 14:53:58 +08001201 ASSERT(index < mState.mAttributes.size());
1202 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001203
1204 if (bufsize > 0)
1205 {
1206 const char *string = attrib.name.c_str();
1207
1208 strncpy(name, string, bufsize);
1209 name[bufsize - 1] = '\0';
1210
1211 if (length)
1212 {
1213 *length = static_cast<GLsizei>(strlen(name));
1214 }
1215 }
1216
1217 // Always a single 'type' instance
1218 *size = 1;
1219 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001220}
1221
Geoff Lange1a27752015-10-05 13:16:04 -04001222GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001223{
Jamie Madillc349ec02015-08-21 16:53:12 -04001224 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001225 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001226 return 0;
1227 }
1228
jchen1036e120e2017-03-14 14:53:58 +08001229 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001230}
1231
Geoff Lange1a27752015-10-05 13:16:04 -04001232GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001233{
Jamie Madillc349ec02015-08-21 16:53:12 -04001234 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001235 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001236 return 0;
1237 }
1238
1239 size_t maxLength = 0;
1240
Jamie Madill48ef11b2016-04-27 15:21:52 -04001241 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001242 {
jchen1036e120e2017-03-14 14:53:58 +08001243 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001244 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001245
Jamie Madillc349ec02015-08-21 16:53:12 -04001246 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001247}
1248
jchen1015015f72017-03-16 13:54:21 +08001249GLuint Program::getInputResourceIndex(const GLchar *name) const
1250{
1251 for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
1252 {
1253 const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
1254 if (attribute.name == name)
1255 {
1256 return attributeIndex;
1257 }
1258 }
1259 return GL_INVALID_INDEX;
1260}
1261
1262GLuint Program::getOutputResourceIndex(const GLchar *name) const
1263{
1264 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1265}
1266
Geoff Lang7dd2e102014-11-10 15:19:26 -05001267GLint Program::getFragDataLocation(const std::string &name) const
1268{
1269 std::string baseName(name);
1270 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
jchen1015015f72017-03-16 13:54:21 +08001271 for (auto outputPair : mState.mOutputLocations)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001272 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001273 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001274 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1275 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001276 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001277 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001278 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001279 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001280}
1281
Geoff Lange1a27752015-10-05 13:16:04 -04001282void Program::getActiveUniform(GLuint index,
1283 GLsizei bufsize,
1284 GLsizei *length,
1285 GLint *size,
1286 GLenum *type,
1287 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001288{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001289 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001290 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001291 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001292 ASSERT(index < mState.mUniforms.size());
1293 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001294
1295 if (bufsize > 0)
1296 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001297 std::string string = uniform.name;
1298 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001299 {
1300 string += "[0]";
1301 }
1302
1303 strncpy(name, string.c_str(), bufsize);
1304 name[bufsize - 1] = '\0';
1305
1306 if (length)
1307 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001308 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001309 }
1310 }
1311
Jamie Madill62d31cb2015-09-11 13:25:51 -04001312 *size = uniform.elementCount();
1313 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001314 }
1315 else
1316 {
1317 if (bufsize > 0)
1318 {
1319 name[0] = '\0';
1320 }
1321
1322 if (length)
1323 {
1324 *length = 0;
1325 }
1326
1327 *size = 0;
1328 *type = GL_NONE;
1329 }
1330}
1331
Geoff Lange1a27752015-10-05 13:16:04 -04001332GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001333{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001334 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001335 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001336 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001337 }
1338 else
1339 {
1340 return 0;
1341 }
1342}
1343
Geoff Lange1a27752015-10-05 13:16:04 -04001344GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001345{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001346 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001347
1348 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001349 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001350 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001351 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001352 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001353 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001354 size_t length = uniform.name.length() + 1u;
1355 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001356 {
1357 length += 3; // Counting in "[0]".
1358 }
1359 maxLength = std::max(length, maxLength);
1360 }
1361 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001362 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001363
Jamie Madill62d31cb2015-09-11 13:25:51 -04001364 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001365}
1366
1367GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1368{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001369 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001370 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001371 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001372 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1374 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1375 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1376 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1377 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1378 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1379 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1380 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1381 default:
1382 UNREACHABLE();
1383 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001384 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385 return 0;
1386}
1387
1388bool Program::isValidUniformLocation(GLint location) const
1389{
Jamie Madille2e406c2016-06-02 13:04:10 -04001390 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001391 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1392 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001393}
1394
Jamie Madill62d31cb2015-09-11 13:25:51 -04001395const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001396{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001397 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001398 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399}
1400
Jamie Madillac4e9c32017-01-13 14:07:12 -05001401const VariableLocation &Program::getUniformLocation(GLint location) const
1402{
1403 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1404 return mState.mUniformLocations[location];
1405}
1406
1407const std::vector<VariableLocation> &Program::getUniformLocations() const
1408{
1409 return mState.mUniformLocations;
1410}
1411
1412const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1413{
1414 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1415 return mState.mUniforms[index];
1416}
1417
Jamie Madill62d31cb2015-09-11 13:25:51 -04001418GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001419{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001420 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001421}
1422
Jamie Madill62d31cb2015-09-11 13:25:51 -04001423GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001424{
Jamie Madille7d84322017-01-10 18:21:59 -05001425 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001426}
1427
1428void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1429{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001430 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1431 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001432}
1433
1434void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1435{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001436 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1437 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438}
1439
1440void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1441{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001442 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1443 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001444}
1445
1446void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1447{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001448 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1449 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001450}
1451
1452void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1453{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001454 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1455 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001456}
1457
1458void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1459{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001460 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1461 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001462}
1463
1464void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1465{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001466 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1467 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001468}
1469
1470void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1471{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001472 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1473 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001474}
1475
1476void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1477{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001478 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1479 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001480}
1481
1482void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1483{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001484 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1485 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001486}
1487
1488void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1489{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001490 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1491 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001492}
1493
1494void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1495{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001496 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1497 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001498}
1499
1500void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1501{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001502 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1503 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504}
1505
1506void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1507{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001508 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1509 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001510}
1511
1512void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1513{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001514 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1515 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001516}
1517
1518void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1519{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001520 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1521 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001522}
1523
1524void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1525{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001526 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1527 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001528}
1529
1530void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1531{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001532 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1533 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001534}
1535
1536void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1537{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001538 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1539 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001540}
1541
1542void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1543{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001544 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1545 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001546}
1547
1548void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1549{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001550 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1551 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001552}
1553
Geoff Lange1a27752015-10-05 13:16:04 -04001554void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001555{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001556 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557}
1558
Geoff Lange1a27752015-10-05 13:16:04 -04001559void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001560{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001561 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001562}
1563
Geoff Lange1a27752015-10-05 13:16:04 -04001564void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001565{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001566 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001567}
1568
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001569void Program::flagForDeletion()
1570{
1571 mDeleteStatus = true;
1572}
1573
1574bool Program::isFlaggedForDeletion() const
1575{
1576 return mDeleteStatus;
1577}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001578
Brandon Jones43a53e22014-08-28 16:23:22 -07001579void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001580{
1581 mInfoLog.reset();
1582
Geoff Lang7dd2e102014-11-10 15:19:26 -05001583 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001584 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001585 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001586 }
1587 else
1588 {
Jamie Madillf6113162015-05-07 11:49:21 -04001589 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001590 }
1591}
1592
Geoff Lang7dd2e102014-11-10 15:19:26 -05001593bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1594{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001595 // Skip cache if we're using an infolog, so we get the full error.
1596 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1597 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1598 {
1599 return mCachedValidateSamplersResult.value();
1600 }
1601
1602 if (mTextureUnitTypesCache.empty())
1603 {
1604 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1605 }
1606 else
1607 {
1608 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1609 }
1610
1611 // if any two active samplers in a program are of different types, but refer to the same
1612 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1613 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001614 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001615 {
Jamie Madille7d84322017-01-10 18:21:59 -05001616 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001617
Jamie Madille7d84322017-01-10 18:21:59 -05001618 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001619 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001620 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1621 {
1622 if (infoLog)
1623 {
1624 (*infoLog) << "Sampler uniform (" << textureUnit
1625 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1626 << caps.maxCombinedTextureImageUnits << ")";
1627 }
1628
1629 mCachedValidateSamplersResult = false;
1630 return false;
1631 }
1632
1633 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1634 {
1635 if (textureType != mTextureUnitTypesCache[textureUnit])
1636 {
1637 if (infoLog)
1638 {
1639 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1640 "image unit ("
1641 << textureUnit << ").";
1642 }
1643
1644 mCachedValidateSamplersResult = false;
1645 return false;
1646 }
1647 }
1648 else
1649 {
1650 mTextureUnitTypesCache[textureUnit] = textureType;
1651 }
1652 }
1653 }
1654
1655 mCachedValidateSamplersResult = true;
1656 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001657}
1658
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001659bool Program::isValidated() const
1660{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001661 return mValidated;
1662}
1663
Geoff Lange1a27752015-10-05 13:16:04 -04001664GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001665{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001666 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001667}
1668
1669void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1670{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001671 ASSERT(
1672 uniformBlockIndex <
1673 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674
Jamie Madill48ef11b2016-04-27 15:21:52 -04001675 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001676
1677 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001678 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001679 std::string string = uniformBlock.name;
1680
Jamie Madill62d31cb2015-09-11 13:25:51 -04001681 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001682 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001683 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684 }
1685
1686 strncpy(uniformBlockName, string.c_str(), bufSize);
1687 uniformBlockName[bufSize - 1] = '\0';
1688
1689 if (length)
1690 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001691 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001692 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001693 }
1694}
1695
Geoff Lange1a27752015-10-05 13:16:04 -04001696GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001697{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001698 int maxLength = 0;
1699
1700 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001701 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001702 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001703 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1704 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001705 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001706 if (!uniformBlock.name.empty())
1707 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001708 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001709
1710 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001711 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001712
1713 maxLength = std::max(length + arrayLength, maxLength);
1714 }
1715 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001716 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001717
1718 return maxLength;
1719}
1720
Geoff Lange1a27752015-10-05 13:16:04 -04001721GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001722{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001723 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08001724 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001725
Jamie Madill48ef11b2016-04-27 15:21:52 -04001726 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001727 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1728 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001729 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001730 if (uniformBlock.name == baseName)
1731 {
1732 const bool arrayElementZero =
1733 (subscript == GL_INVALID_INDEX &&
1734 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1735 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1736 {
1737 return blockIndex;
1738 }
1739 }
1740 }
1741
1742 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001743}
1744
Jamie Madill62d31cb2015-09-11 13:25:51 -04001745const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001746{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001747 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1748 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001749}
1750
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001751void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1752{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001753 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001754 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001755 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001756}
1757
1758GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1759{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001760 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001761}
1762
1763void Program::resetUniformBlockBindings()
1764{
1765 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1766 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001767 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001768 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001769 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001770}
1771
Geoff Lang48dcae72014-02-05 16:28:24 -05001772void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1773{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001774 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001775 for (GLsizei i = 0; i < count; i++)
1776 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001777 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001778 }
1779
Jamie Madill48ef11b2016-04-27 15:21:52 -04001780 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001781}
1782
1783void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1784{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001785 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001786 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001787 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1788 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001789 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1790 if (length)
1791 {
1792 *length = lastNameIdx;
1793 }
1794 if (size)
1795 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001796 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001797 }
1798 if (type)
1799 {
1800 *type = varying.type;
1801 }
1802 if (name)
1803 {
1804 memcpy(name, varying.name.c_str(), lastNameIdx);
1805 name[lastNameIdx] = '\0';
1806 }
1807 }
1808}
1809
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001810GLsizei Program::getTransformFeedbackVaryingCount() const
1811{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001812 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001813 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001814 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001815 }
1816 else
1817 {
1818 return 0;
1819 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001820}
1821
1822GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1823{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001824 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001825 {
1826 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001827 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001828 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001829 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1830 }
1831
1832 return maxSize;
1833 }
1834 else
1835 {
1836 return 0;
1837 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001838}
1839
1840GLenum Program::getTransformFeedbackBufferMode() const
1841{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001842 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001843}
1844
Jamie Madill192745a2016-12-22 15:58:21 -05001845bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001846{
Jamie Madill192745a2016-12-22 15:58:21 -05001847 const Shader *vertexShader = mState.mAttachedVertexShader;
1848 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1849
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001850 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1851
Jamie Madill4cff2472015-08-21 16:53:18 -04001852 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1853 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001854
Sami Väisänen46eaa942016-06-29 10:26:37 +03001855 std::map<GLuint, std::string> staticFragmentInputLocations;
1856
Jamie Madill4cff2472015-08-21 16:53:18 -04001857 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001858 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001859 bool matched = false;
1860
1861 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001862 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863 {
1864 continue;
1865 }
1866
Jamie Madill4cff2472015-08-21 16:53:18 -04001867 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001868 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001869 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001870 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001871 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001872 if (!linkValidateVaryings(infoLog, output.name, input, output,
1873 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001874 {
1875 return false;
1876 }
1877
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878 matched = true;
1879 break;
1880 }
1881 }
1882
1883 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001884 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001886 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 return false;
1888 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001889
1890 // Check for aliased path rendering input bindings (if any).
1891 // If more than one binding refer statically to the same
1892 // location the link must fail.
1893
1894 if (!output.staticUse)
1895 continue;
1896
1897 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1898 if (inputBinding == -1)
1899 continue;
1900
1901 const auto it = staticFragmentInputLocations.find(inputBinding);
1902 if (it == std::end(staticFragmentInputLocations))
1903 {
1904 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1905 }
1906 else
1907 {
1908 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1909 << it->second;
1910 return false;
1911 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001912 }
1913
Yuly Novikov817232e2017-02-22 18:36:10 -05001914 if (!linkValidateBuiltInVaryings(infoLog))
1915 {
1916 return false;
1917 }
1918
Jamie Madillada9ecc2015-08-17 12:53:37 -04001919 // TODO(jmadill): verify no unmatched vertex varyings?
1920
Geoff Lang7dd2e102014-11-10 15:19:26 -05001921 return true;
1922}
1923
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001924bool Program::linkUniforms(InfoLog &infoLog,
1925 const Caps &caps,
1926 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001927{
Olli Etuahob78707c2017-03-09 15:03:11 +00001928 UniformLinker linker(mState);
1929 if (!linker.link(infoLog, caps, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04001930 {
1931 return false;
1932 }
1933
Olli Etuahob78707c2017-03-09 15:03:11 +00001934 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001935
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001936 updateSamplerBindings();
1937
1938 return true;
1939}
1940
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001941void Program::updateSamplerBindings()
1942{
1943 mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
1944 mState.mSamplerUniformRange.start = mState.mSamplerUniformRange.end;
1945 auto samplerIter = mState.mUniforms.rbegin();
1946 while (samplerIter != mState.mUniforms.rend() && samplerIter->isSampler())
1947 {
1948 --mState.mSamplerUniformRange.start;
1949 ++samplerIter;
1950 }
1951 // If uniform is a sampler type, insert it into the mSamplerBindings array.
1952 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
1953 samplerIndex < mState.mUniforms.size(); ++samplerIndex)
1954 {
1955 const auto &samplerUniform = mState.mUniforms[samplerIndex];
1956 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
1957 mState.mSamplerBindings.emplace_back(
1958 SamplerBinding(textureType, samplerUniform.elementCount()));
1959 }
1960}
1961
Martin Radev4c4c8e72016-08-04 12:25:34 +03001962bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
1963 const std::string &uniformName,
1964 const sh::InterfaceBlockField &vertexUniform,
1965 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001966{
Jamie Madillc4c744222015-11-04 09:39:47 -05001967 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1968 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001969 {
1970 return false;
1971 }
1972
1973 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1974 {
Jamie Madillf6113162015-05-07 11:49:21 -04001975 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001976 return false;
1977 }
1978
1979 return true;
1980}
1981
Jamie Madilleb979bf2016-11-15 12:28:46 -05001982// Assigns locations to all attributes from the bindings and program locations.
1983bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001984{
Jamie Madilleb979bf2016-11-15 12:28:46 -05001985 const auto *vertexShader = mState.getAttachedVertexShader();
1986
Geoff Lang7dd2e102014-11-10 15:19:26 -05001987 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001988 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001989 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04001990
1991 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04001992 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001993 {
Jamie Madillf6113162015-05-07 11:49:21 -04001994 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001995 return false;
1996 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001997
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001998 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001999
Jamie Madillc349ec02015-08-21 16:53:12 -04002000 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002001 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002002 {
Jamie Madilleb979bf2016-11-15 12:28:46 -05002003 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002004 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002005 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002006 attribute.location = bindingLocation;
2007 }
2008
2009 if (attribute.location != -1)
2010 {
2011 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002012 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002013
Jamie Madill63805b42015-08-25 13:17:39 -04002014 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002015 {
Jamie Madillf6113162015-05-07 11:49:21 -04002016 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002017 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002018
2019 return false;
2020 }
2021
Jamie Madill63805b42015-08-25 13:17:39 -04002022 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002023 {
Jamie Madill63805b42015-08-25 13:17:39 -04002024 const int regLocation = attribute.location + reg;
2025 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002026
2027 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002028 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002029 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002030 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002031 // TODO(jmadill): fix aliasing on ES2
2032 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002033 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002034 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002035 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002036 return false;
2037 }
2038 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002039 else
2040 {
Jamie Madill63805b42015-08-25 13:17:39 -04002041 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002042 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002043
Jamie Madill63805b42015-08-25 13:17:39 -04002044 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002045 }
2046 }
2047 }
2048
2049 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002050 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002051 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002052 // Not set by glBindAttribLocation or by location layout qualifier
2053 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002054 {
Jamie Madill63805b42015-08-25 13:17:39 -04002055 int regs = VariableRegisterCount(attribute.type);
2056 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002057
Jamie Madill63805b42015-08-25 13:17:39 -04002058 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002059 {
Jamie Madillf6113162015-05-07 11:49:21 -04002060 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002061 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002062 }
2063
Jamie Madillc349ec02015-08-21 16:53:12 -04002064 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002065 }
2066 }
2067
Jamie Madill48ef11b2016-04-27 15:21:52 -04002068 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002069 {
Jamie Madill63805b42015-08-25 13:17:39 -04002070 ASSERT(attribute.location != -1);
2071 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002072
Jamie Madill63805b42015-08-25 13:17:39 -04002073 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002074 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002075 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002076 }
2077 }
2078
Geoff Lang7dd2e102014-11-10 15:19:26 -05002079 return true;
2080}
2081
Martin Radev4c4c8e72016-08-04 12:25:34 +03002082bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2083 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2084 const std::string &errorMessage,
2085 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002086{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002087 GLuint blockCount = 0;
2088 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002089 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002090 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002091 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002092 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002093 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002094 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002095 return false;
2096 }
2097 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002098 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002099 return true;
2100}
Jamie Madille473dee2015-08-18 14:49:01 -04002101
Martin Radev4c4c8e72016-08-04 12:25:34 +03002102bool Program::validateVertexAndFragmentInterfaceBlocks(
2103 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2104 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2105 InfoLog &infoLog) const
2106{
2107 // Check that interface blocks defined in the vertex and fragment shaders are identical
2108 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2109 UniformBlockMap linkedUniformBlocks;
2110
2111 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2112 {
2113 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2114 }
2115
Jamie Madille473dee2015-08-18 14:49:01 -04002116 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002117 {
Jamie Madille473dee2015-08-18 14:49:01 -04002118 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002119 if (entry != linkedUniformBlocks.end())
2120 {
2121 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2122 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2123 {
2124 return false;
2125 }
2126 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002127 }
2128 return true;
2129}
Jamie Madille473dee2015-08-18 14:49:01 -04002130
Martin Radev4c4c8e72016-08-04 12:25:34 +03002131bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2132{
2133 if (mState.mAttachedComputeShader)
2134 {
2135 const Shader &computeShader = *mState.mAttachedComputeShader;
2136 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2137
2138 if (!validateUniformBlocksCount(
2139 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2140 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2141 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002142 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002143 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002144 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002145 return true;
2146 }
2147
2148 const Shader &vertexShader = *mState.mAttachedVertexShader;
2149 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2150
2151 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2152 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2153
2154 if (!validateUniformBlocksCount(
2155 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2156 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2157 {
2158 return false;
2159 }
2160 if (!validateUniformBlocksCount(
2161 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2162 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2163 infoLog))
2164 {
2165
2166 return false;
2167 }
2168 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2169 infoLog))
2170 {
2171 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002172 }
Jamie Madille473dee2015-08-18 14:49:01 -04002173
Geoff Lang7dd2e102014-11-10 15:19:26 -05002174 return true;
2175}
2176
Jamie Madilla2c74982016-12-12 11:20:42 -05002177bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002178 const sh::InterfaceBlock &vertexInterfaceBlock,
2179 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002180{
2181 const char* blockName = vertexInterfaceBlock.name.c_str();
2182 // validate blocks for the same member types
2183 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2184 {
Jamie Madillf6113162015-05-07 11:49:21 -04002185 infoLog << "Types for interface block '" << blockName
2186 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002187 return false;
2188 }
2189 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2190 {
Jamie Madillf6113162015-05-07 11:49:21 -04002191 infoLog << "Array sizes differ for interface block '" << blockName
2192 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002193 return false;
2194 }
2195 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2196 {
Jamie Madillf6113162015-05-07 11:49:21 -04002197 infoLog << "Layout qualifiers differ for interface block '" << blockName
2198 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002199 return false;
2200 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002201 const unsigned int numBlockMembers =
2202 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002203 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2204 {
2205 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2206 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2207 if (vertexMember.name != fragmentMember.name)
2208 {
Jamie Madillf6113162015-05-07 11:49:21 -04002209 infoLog << "Name mismatch for field " << blockMemberIndex
2210 << " of interface block '" << blockName
2211 << "': (in vertex: '" << vertexMember.name
2212 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002213 return false;
2214 }
2215 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2216 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2217 {
2218 return false;
2219 }
2220 }
2221 return true;
2222}
2223
2224bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2225 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2226{
2227 if (vertexVariable.type != fragmentVariable.type)
2228 {
Jamie Madillf6113162015-05-07 11:49:21 -04002229 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002230 return false;
2231 }
2232 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2233 {
Jamie Madillf6113162015-05-07 11:49:21 -04002234 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002235 return false;
2236 }
2237 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2238 {
Jamie Madillf6113162015-05-07 11:49:21 -04002239 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002240 return false;
2241 }
2242
2243 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2244 {
Jamie Madillf6113162015-05-07 11:49:21 -04002245 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002246 return false;
2247 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002248 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002249 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2250 {
2251 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2252 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2253
2254 if (vertexMember.name != fragmentMember.name)
2255 {
Jamie Madillf6113162015-05-07 11:49:21 -04002256 infoLog << "Name mismatch for field '" << memberIndex
2257 << "' of " << variableName
2258 << ": (in vertex: '" << vertexMember.name
2259 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002260 return false;
2261 }
2262
2263 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2264 vertexMember.name + "'";
2265
2266 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2267 {
2268 return false;
2269 }
2270 }
2271
2272 return true;
2273}
2274
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002275bool Program::linkValidateVaryings(InfoLog &infoLog,
2276 const std::string &varyingName,
2277 const sh::Varying &vertexVarying,
2278 const sh::Varying &fragmentVarying,
2279 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002280{
2281 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2282 {
2283 return false;
2284 }
2285
Jamie Madille9cc4692015-02-19 16:00:13 -05002286 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002287 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002288 infoLog << "Interpolation types for " << varyingName
2289 << " differ between vertex and fragment shaders.";
2290 return false;
2291 }
2292
2293 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2294 {
2295 infoLog << "Invariance for " << varyingName
2296 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002297 return false;
2298 }
2299
2300 return true;
2301}
2302
Yuly Novikov817232e2017-02-22 18:36:10 -05002303bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
2304{
2305 const Shader *vertexShader = mState.mAttachedVertexShader;
2306 const Shader *fragmentShader = mState.mAttachedFragmentShader;
2307 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
2308 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
2309 int shaderVersion = vertexShader->getShaderVersion();
2310
2311 if (shaderVersion != 100)
2312 {
2313 // Only ESSL 1.0 has restrictions on matching input and output invariance
2314 return true;
2315 }
2316
2317 bool glPositionIsInvariant = false;
2318 bool glPointSizeIsInvariant = false;
2319 bool glFragCoordIsInvariant = false;
2320 bool glPointCoordIsInvariant = false;
2321
2322 for (const sh::Varying &varying : vertexVaryings)
2323 {
2324 if (!varying.isBuiltIn())
2325 {
2326 continue;
2327 }
2328 if (varying.name.compare("gl_Position") == 0)
2329 {
2330 glPositionIsInvariant = varying.isInvariant;
2331 }
2332 else if (varying.name.compare("gl_PointSize") == 0)
2333 {
2334 glPointSizeIsInvariant = varying.isInvariant;
2335 }
2336 }
2337
2338 for (const sh::Varying &varying : fragmentVaryings)
2339 {
2340 if (!varying.isBuiltIn())
2341 {
2342 continue;
2343 }
2344 if (varying.name.compare("gl_FragCoord") == 0)
2345 {
2346 glFragCoordIsInvariant = varying.isInvariant;
2347 }
2348 else if (varying.name.compare("gl_PointCoord") == 0)
2349 {
2350 glPointCoordIsInvariant = varying.isInvariant;
2351 }
2352 }
2353
2354 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2355 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2356 // Not requiring invariance to match is supported by:
2357 // dEQP, WebGL CTS, Nexus 5X GLES
2358 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2359 {
2360 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2361 "declared invariant.";
2362 return false;
2363 }
2364 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2365 {
2366 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2367 "declared invariant.";
2368 return false;
2369 }
2370
2371 return true;
2372}
2373
Jamie Madillccdf74b2015-08-18 10:46:12 -04002374bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002375 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002376 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002377{
2378 size_t totalComponents = 0;
2379
Jamie Madillccdf74b2015-08-18 10:46:12 -04002380 std::set<std::string> uniqueNames;
2381
Jamie Madill48ef11b2016-04-27 15:21:52 -04002382 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002383 {
2384 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002385 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002386 {
Jamie Madill192745a2016-12-22 15:58:21 -05002387 const sh::Varying *varying = ref.second.get();
2388
Jamie Madillccdf74b2015-08-18 10:46:12 -04002389 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002390 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002391 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002392 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002393 infoLog << "Two transform feedback varyings specify the same output variable ("
2394 << tfVaryingName << ").";
2395 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002396 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002397 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002398
Geoff Lang1a683462015-09-29 15:09:59 -04002399 if (varying->isArray())
2400 {
2401 infoLog << "Capture of arrays is undefined and not supported.";
2402 return false;
2403 }
2404
Jamie Madillccdf74b2015-08-18 10:46:12 -04002405 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002406 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002407 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002408 componentCount > caps.maxTransformFeedbackSeparateComponents)
2409 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002410 infoLog << "Transform feedback varying's " << varying->name << " components ("
2411 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002412 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002413 return false;
2414 }
2415
2416 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002417 found = true;
2418 break;
2419 }
2420 }
2421
Jamie Madill89bb70e2015-08-31 14:18:39 -04002422 if (tfVaryingName.find('[') != std::string::npos)
2423 {
Geoff Lang1a683462015-09-29 15:09:59 -04002424 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002425 return false;
2426 }
2427
Geoff Lang7dd2e102014-11-10 15:19:26 -05002428 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2429 ASSERT(found);
2430 }
2431
Jamie Madill48ef11b2016-04-27 15:21:52 -04002432 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002433 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002434 {
Jamie Madillf6113162015-05-07 11:49:21 -04002435 infoLog << "Transform feedback varying total components (" << totalComponents
2436 << ") exceed the maximum interleaved components ("
2437 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002438 return false;
2439 }
2440
2441 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002442}
2443
Jamie Madill192745a2016-12-22 15:58:21 -05002444void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002445{
2446 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002447 mState.mTransformFeedbackVaryingVars.clear();
2448 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002449 {
Jamie Madill192745a2016-12-22 15:58:21 -05002450 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002451 {
Jamie Madill192745a2016-12-22 15:58:21 -05002452 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002453 if (tfVaryingName == varying->name)
2454 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002455 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002456 break;
2457 }
2458 }
2459 }
2460}
2461
Jamie Madill192745a2016-12-22 15:58:21 -05002462Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002463{
Jamie Madill192745a2016-12-22 15:58:21 -05002464 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002465
Jamie Madill48ef11b2016-04-27 15:21:52 -04002466 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002467 {
Jamie Madill192745a2016-12-22 15:58:21 -05002468 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002469 }
2470
Jamie Madill48ef11b2016-04-27 15:21:52 -04002471 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002472 {
Jamie Madill192745a2016-12-22 15:58:21 -05002473 merged[varying.name].fragment = &varying;
2474 }
2475
2476 return merged;
2477}
2478
2479std::vector<PackedVarying> Program::getPackedVaryings(
2480 const Program::MergedVaryings &mergedVaryings) const
2481{
2482 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2483 std::vector<PackedVarying> packedVaryings;
2484
2485 for (const auto &ref : mergedVaryings)
2486 {
2487 const sh::Varying *input = ref.second.vertex;
2488 const sh::Varying *output = ref.second.fragment;
2489
2490 // Only pack varyings that have a matched input or output, plus special builtins.
2491 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002492 {
Jamie Madill192745a2016-12-22 15:58:21 -05002493 // Will get the vertex shader interpolation by default.
2494 auto interpolation = ref.second.get()->interpolation;
2495
2496 // Interpolation qualifiers must match.
2497 if (output->isStruct())
2498 {
2499 ASSERT(!output->isArray());
2500 for (const auto &field : output->fields)
2501 {
2502 ASSERT(!field.isStruct() && !field.isArray());
2503 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2504 }
2505 }
2506 else
2507 {
2508 packedVaryings.push_back(PackedVarying(*output, interpolation));
2509 }
2510 continue;
2511 }
2512
2513 // Keep Transform FB varyings in the merged list always.
2514 if (!input)
2515 {
2516 continue;
2517 }
2518
2519 for (const std::string &tfVarying : tfVaryings)
2520 {
2521 if (tfVarying == input->name)
2522 {
2523 // Transform feedback for varying structs is underspecified.
2524 // See Khronos bug 9856.
2525 // TODO(jmadill): Figure out how to be spec-compliant here.
2526 if (!input->isStruct())
2527 {
2528 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2529 packedVaryings.back().vertexOnly = true;
2530 }
2531 break;
2532 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002533 }
2534 }
2535
Jamie Madill192745a2016-12-22 15:58:21 -05002536 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2537
2538 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002539}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002540
2541void Program::linkOutputVariables()
2542{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002543 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002544 ASSERT(fragmentShader != nullptr);
2545
2546 // Skip this step for GLES2 shaders.
2547 if (fragmentShader->getShaderVersion() == 100)
2548 return;
2549
jchen1015015f72017-03-16 13:54:21 +08002550 mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002551 // TODO(jmadill): any caps validation here?
2552
jchen1015015f72017-03-16 13:54:21 +08002553 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002554 outputVariableIndex++)
2555 {
jchen1015015f72017-03-16 13:54:21 +08002556 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002557
2558 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2559 if (outputVariable.isBuiltIn())
2560 continue;
2561
2562 // Since multiple output locations must be specified, use 0 for non-specified locations.
2563 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2564
Jamie Madill80a6fc02015-08-21 16:53:16 -04002565 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2566 elementIndex++)
2567 {
2568 const int location = baseLocation + elementIndex;
jchen1015015f72017-03-16 13:54:21 +08002569 ASSERT(mState.mOutputLocations.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002570 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08002571 mState.mOutputLocations[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002572 VariableLocation(outputVariable.name, element, outputVariableIndex);
2573 }
2574 }
2575}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002576
Jamie Madill62d31cb2015-09-11 13:25:51 -04002577void Program::gatherInterfaceBlockInfo()
2578{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002579 ASSERT(mState.mUniformBlocks.empty());
2580
2581 if (mState.mAttachedComputeShader)
2582 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002583 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002584
2585 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2586 {
2587
2588 // Only 'packed' blocks are allowed to be considered inactive.
2589 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2590 continue;
2591
Jamie Madilla2c74982016-12-12 11:20:42 -05002592 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002593 {
2594 if (block.name == computeBlock.name)
2595 {
2596 block.computeStaticUse = computeBlock.staticUse;
2597 }
2598 }
2599
2600 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2601 }
2602 return;
2603 }
2604
Jamie Madill62d31cb2015-09-11 13:25:51 -04002605 std::set<std::string> visitedList;
2606
Jamie Madilla2c74982016-12-12 11:20:42 -05002607 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002608
Jamie Madill62d31cb2015-09-11 13:25:51 -04002609 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2610 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002611 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002612 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2613 continue;
2614
2615 if (visitedList.count(vertexBlock.name) > 0)
2616 continue;
2617
2618 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2619 visitedList.insert(vertexBlock.name);
2620 }
2621
Jamie Madilla2c74982016-12-12 11:20:42 -05002622 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002623
2624 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2625 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002626 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002627 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2628 continue;
2629
2630 if (visitedList.count(fragmentBlock.name) > 0)
2631 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002632 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002633 {
2634 if (block.name == fragmentBlock.name)
2635 {
2636 block.fragmentStaticUse = fragmentBlock.staticUse;
2637 }
2638 }
2639
2640 continue;
2641 }
2642
2643 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2644 visitedList.insert(fragmentBlock.name);
2645 }
2646}
2647
Jamie Madill4a3c2342015-10-08 12:58:45 -04002648template <typename VarT>
2649void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2650 const std::string &prefix,
2651 int blockIndex)
2652{
2653 for (const VarT &field : fields)
2654 {
2655 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2656
2657 if (field.isStruct())
2658 {
2659 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2660 {
2661 const std::string uniformElementName =
2662 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2663 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2664 }
2665 }
2666 else
2667 {
2668 // If getBlockMemberInfo returns false, the uniform is optimized out.
2669 sh::BlockMemberInfo memberInfo;
2670 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2671 {
2672 continue;
2673 }
2674
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002675 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04002676 blockIndex, memberInfo);
2677
2678 // Since block uniforms have no location, we don't need to store them in the uniform
2679 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002680 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002681 }
2682 }
2683}
2684
Jamie Madill62d31cb2015-09-11 13:25:51 -04002685void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2686{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002687 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002688 size_t blockSize = 0;
2689
2690 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002691 std::stringstream blockNameStr;
2692 blockNameStr << interfaceBlock.name;
2693 if (interfaceBlock.arraySize > 0)
2694 {
2695 blockNameStr << "[0]";
2696 }
2697 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002698 {
2699 return;
2700 }
2701
2702 // Track the first and last uniform index to determine the range of active uniforms in the
2703 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002704 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002705 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002706 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002707
2708 std::vector<unsigned int> blockUniformIndexes;
2709 for (size_t blockUniformIndex = firstBlockUniformIndex;
2710 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2711 {
2712 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2713 }
2714
2715 if (interfaceBlock.arraySize > 0)
2716 {
2717 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2718 {
2719 UniformBlock block(interfaceBlock.name, true, arrayElement);
2720 block.memberUniformIndexes = blockUniformIndexes;
2721
Martin Radev4c4c8e72016-08-04 12:25:34 +03002722 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002723 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002724 case GL_VERTEX_SHADER:
2725 {
2726 block.vertexStaticUse = interfaceBlock.staticUse;
2727 break;
2728 }
2729 case GL_FRAGMENT_SHADER:
2730 {
2731 block.fragmentStaticUse = interfaceBlock.staticUse;
2732 break;
2733 }
2734 case GL_COMPUTE_SHADER:
2735 {
2736 block.computeStaticUse = interfaceBlock.staticUse;
2737 break;
2738 }
2739 default:
2740 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002741 }
2742
Qin Jiajia0350a642016-11-01 17:01:51 +08002743 // Since all block elements in an array share the same active uniforms, they will all be
2744 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2745 // here we will add every block element in the array.
2746 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002747 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002748 }
2749 }
2750 else
2751 {
2752 UniformBlock block(interfaceBlock.name, false, 0);
2753 block.memberUniformIndexes = blockUniformIndexes;
2754
Martin Radev4c4c8e72016-08-04 12:25:34 +03002755 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002756 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002757 case GL_VERTEX_SHADER:
2758 {
2759 block.vertexStaticUse = interfaceBlock.staticUse;
2760 break;
2761 }
2762 case GL_FRAGMENT_SHADER:
2763 {
2764 block.fragmentStaticUse = interfaceBlock.staticUse;
2765 break;
2766 }
2767 case GL_COMPUTE_SHADER:
2768 {
2769 block.computeStaticUse = interfaceBlock.staticUse;
2770 break;
2771 }
2772 default:
2773 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002774 }
2775
Jamie Madill4a3c2342015-10-08 12:58:45 -04002776 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002777 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002778 }
2779}
2780
Jamie Madille7d84322017-01-10 18:21:59 -05002781template <>
2782void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2783 const uint8_t *destPointer,
2784 GLsizei clampedCount,
2785 const GLint *v)
2786{
2787 // Invalidate the validation cache only if we modify the sampler data.
2788 if (mState.isSamplerUniformIndex(locationInfo.index) &&
2789 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
2790 {
2791 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2792 std::vector<GLuint> *boundTextureUnits =
2793 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
2794
2795 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
2796 mCachedValidateSamplersResult.reset();
2797 }
2798}
2799
2800template <typename T>
2801void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2802 const uint8_t *destPointer,
2803 GLsizei clampedCount,
2804 const T *v)
2805{
2806}
2807
Jamie Madill62d31cb2015-09-11 13:25:51 -04002808template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002809GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002810{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002811 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2812 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002813 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2814
Corentin Wallez15ac5342016-11-03 17:06:39 -04002815 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2816 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2817 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002818 GLsizei maxElementCount =
2819 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2820
2821 GLsizei count = countIn;
2822 GLsizei clampedCount = count * vectorSize;
2823 if (clampedCount > maxElementCount)
2824 {
2825 clampedCount = maxElementCount;
2826 count = maxElementCount / vectorSize;
2827 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002828
Jamie Madill62d31cb2015-09-11 13:25:51 -04002829 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2830 {
2831 // Do a cast conversion for boolean types. From the spec:
2832 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2833 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002834 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002835 {
2836 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2837 }
2838 }
2839 else
2840 {
Jamie Madille7d84322017-01-10 18:21:59 -05002841 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002842 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002843 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002844
2845 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002846}
2847
2848template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002849GLsizei Program::setMatrixUniformInternal(GLint location,
2850 GLsizei count,
2851 GLboolean transpose,
2852 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002853{
2854 if (!transpose)
2855 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002856 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002857 }
2858
2859 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002860 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2861 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002862 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04002863
2864 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2865 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2866 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
2867 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
2868
2869 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002870 {
2871 size_t elementOffset = element * rows * cols;
2872
2873 for (size_t row = 0; row < rows; ++row)
2874 {
2875 for (size_t col = 0; col < cols; ++col)
2876 {
2877 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2878 }
2879 }
2880 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002881
2882 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002883}
2884
2885template <typename DestT>
2886void Program::getUniformInternal(GLint location, DestT *dataOut) const
2887{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002888 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2889 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002890
2891 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2892
2893 GLenum componentType = VariableComponentType(uniform.type);
2894 if (componentType == GLTypeToGLenum<DestT>::value)
2895 {
2896 memcpy(dataOut, srcPointer, uniform.getElementSize());
2897 return;
2898 }
2899
Corentin Wallez6596c462016-03-17 17:26:58 -04002900 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002901
2902 switch (componentType)
2903 {
2904 case GL_INT:
2905 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2906 break;
2907 case GL_UNSIGNED_INT:
2908 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2909 break;
2910 case GL_BOOL:
2911 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2912 break;
2913 case GL_FLOAT:
2914 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2915 break;
2916 default:
2917 UNREACHABLE();
2918 }
2919}
Jamie Madilla4595b82017-01-11 17:36:34 -05002920
2921bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
2922{
2923 // Must be called after samplers are validated.
2924 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
2925
2926 for (const auto &binding : mState.mSamplerBindings)
2927 {
2928 GLenum textureType = binding.textureType;
2929 for (const auto &unit : binding.boundTextureUnits)
2930 {
2931 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
2932 if (programTextureID == textureID)
2933 {
2934 // TODO(jmadill): Check for appropriate overlap.
2935 return true;
2936 }
2937 }
2938 }
2939
2940 return false;
2941}
2942
Jamie Madilla2c74982016-12-12 11:20:42 -05002943} // namespace gl