blob: 567e1d9fdd7ed028dbac5bf4af2b9bfc0ca64cf1 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
Jamie Madill80a6fc02015-08-21 16:53:16 -040014#include "common/BitSetIterator.h"
Jamie Madill9e0478f2015-01-13 11:13:54 -050015#include "common/debug.h"
16#include "common/platform.h"
17#include "common/utilities.h"
18#include "common/version.h"
19#include "compiler/translator/blocklayout.h"
Jamie Madilla2c74982016-12-12 11:20:42 -050020#include "libANGLE/Context.h"
Jamie Madill437d2662014-12-05 14:23:35 -050021#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050022#include "libANGLE/features.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040023#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill192745a2016-12-22 15:58:21 -050025#include "libANGLE/VaryingPacking.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040026#include "libANGLE/queryconversions.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040027#include "libANGLE/Uniform.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000028#include "libANGLE/UniformLinker.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050029
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030namespace gl
31{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000032
Geoff Lang7dd2e102014-11-10 15:19:26 -050033namespace
34{
35
Jamie Madill62d31cb2015-09-11 13:25:51 -040036void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
37{
38 stream->writeInt(var.type);
39 stream->writeInt(var.precision);
40 stream->writeString(var.name);
41 stream->writeString(var.mappedName);
42 stream->writeInt(var.arraySize);
43 stream->writeInt(var.staticUse);
44 stream->writeString(var.structName);
45 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050046}
47
Jamie Madill62d31cb2015-09-11 13:25:51 -040048void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
49{
50 var->type = stream->readInt<GLenum>();
51 var->precision = stream->readInt<GLenum>();
52 var->name = stream->readString();
53 var->mappedName = stream->readString();
54 var->arraySize = stream->readInt<unsigned int>();
55 var->staticUse = stream->readBool();
56 var->structName = stream->readString();
57}
58
Jamie Madill62d31cb2015-09-11 13:25:51 -040059// This simplified cast function doesn't need to worry about advanced concepts like
60// depth range values, or casting to bool.
61template <typename DestT, typename SrcT>
62DestT UniformStateQueryCast(SrcT value);
63
64// From-Float-To-Integer Casts
65template <>
66GLint UniformStateQueryCast(GLfloat value)
67{
68 return clampCast<GLint>(roundf(value));
69}
70
71template <>
72GLuint UniformStateQueryCast(GLfloat value)
73{
74 return clampCast<GLuint>(roundf(value));
75}
76
77// From-Integer-to-Integer Casts
78template <>
79GLint UniformStateQueryCast(GLuint value)
80{
81 return clampCast<GLint>(value);
82}
83
84template <>
85GLuint UniformStateQueryCast(GLint value)
86{
87 return clampCast<GLuint>(value);
88}
89
90// From-Boolean-to-Anything Casts
91template <>
92GLfloat UniformStateQueryCast(GLboolean value)
93{
94 return (value == GL_TRUE ? 1.0f : 0.0f);
95}
96
97template <>
98GLint UniformStateQueryCast(GLboolean value)
99{
100 return (value == GL_TRUE ? 1 : 0);
101}
102
103template <>
104GLuint UniformStateQueryCast(GLboolean value)
105{
106 return (value == GL_TRUE ? 1u : 0u);
107}
108
109// Default to static_cast
110template <typename DestT, typename SrcT>
111DestT UniformStateQueryCast(SrcT value)
112{
113 return static_cast<DestT>(value);
114}
115
116template <typename SrcT, typename DestT>
117void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
118{
119 for (int comp = 0; comp < components; ++comp)
120 {
121 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
122 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
123 size_t offset = comp * 4;
124 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
125 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
126 }
127}
128
Jamie Madill192745a2016-12-22 15:58:21 -0500129// true if varying x has a higher priority in packing than y
130bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
131{
132 return gl::CompareShaderVar(*x.varying, *y.varying);
133}
134
jchen1015015f72017-03-16 13:54:21 +0800135template <typename VarT>
136GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
137{
138 size_t subscript = GL_INVALID_INDEX;
139 std::string baseName = ParseResourceName(name, &subscript);
140
141 // The app is not allowed to specify array indices other than 0 for arrays of basic types
142 if (subscript != 0 && subscript != GL_INVALID_INDEX)
143 {
144 return GL_INVALID_INDEX;
145 }
146
147 for (size_t index = 0; index < list.size(); index++)
148 {
149 const VarT &resource = list[index];
150 if (resource.name == baseName)
151 {
152 if (resource.isArray() || subscript == GL_INVALID_INDEX)
153 {
154 return static_cast<GLuint>(index);
155 }
156 }
157 }
158
159 return GL_INVALID_INDEX;
160}
161
Jamie Madill62d31cb2015-09-11 13:25:51 -0400162} // anonymous namespace
163
Jamie Madill4a3c2342015-10-08 12:58:45 -0400164const char *const g_fakepath = "C:\\fakepath";
165
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400166InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000167{
168}
169
170InfoLog::~InfoLog()
171{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000172}
173
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400174size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000175{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400176 const std::string &logString = mStream.str();
177 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000178}
179
Geoff Lange1a27752015-10-05 13:16:04 -0400180void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000181{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000183
184 if (bufSize > 0)
185 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400186 const std::string str(mStream.str());
187
188 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000189 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400190 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
191 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000192 }
193
194 infoLog[index] = '\0';
195 }
196
197 if (length)
198 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400199 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000200 }
201}
202
203// append a santized message to the program info log.
Sami Väisänen46eaa942016-06-29 10:26:37 +0300204// The D3D compiler includes a fake file path in some of the warning or error
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000205// messages, so lets remove all occurrences of this fake file path from the log.
206void InfoLog::appendSanitized(const char *message)
207{
208 std::string msg(message);
209
210 size_t found;
211 do
212 {
213 found = msg.find(g_fakepath);
214 if (found != std::string::npos)
215 {
216 msg.erase(found, strlen(g_fakepath));
217 }
218 }
219 while (found != std::string::npos);
220
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400221 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000222}
223
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000224void InfoLog::reset()
225{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000226}
227
Geoff Langd8605522016-04-13 10:19:12 -0400228VariableLocation::VariableLocation() : name(), element(0), index(0), used(false), ignored(false)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000229{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500230}
231
Geoff Langd8605522016-04-13 10:19:12 -0400232VariableLocation::VariableLocation(const std::string &name,
233 unsigned int element,
234 unsigned int index)
235 : name(name), element(element), index(index), used(true), ignored(false)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500236{
237}
238
Geoff Langd8605522016-04-13 10:19:12 -0400239void Program::Bindings::bindLocation(GLuint index, const std::string &name)
240{
241 mBindings[name] = index;
242}
243
244int Program::Bindings::getBinding(const std::string &name) const
245{
246 auto iter = mBindings.find(name);
247 return (iter != mBindings.end()) ? iter->second : -1;
248}
249
250Program::Bindings::const_iterator Program::Bindings::begin() const
251{
252 return mBindings.begin();
253}
254
255Program::Bindings::const_iterator Program::Bindings::end() const
256{
257 return mBindings.end();
258}
259
Jamie Madill48ef11b2016-04-27 15:21:52 -0400260ProgramState::ProgramState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500261 : mLabel(),
262 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400263 mAttachedVertexShader(nullptr),
Martin Radev4c4c8e72016-08-04 12:25:34 +0300264 mAttachedComputeShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500265 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
Jamie Madille7d84322017-01-10 18:21:59 -0500266 mSamplerUniformRange(0, 0),
Geoff Langc5629752015-12-07 16:29:04 -0500267 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400268{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300269 mComputeShaderLocalSize.fill(1);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400270}
271
Jamie Madill48ef11b2016-04-27 15:21:52 -0400272ProgramState::~ProgramState()
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400273{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500274 ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400275}
276
Jamie Madill48ef11b2016-04-27 15:21:52 -0400277const std::string &ProgramState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500278{
279 return mLabel;
280}
281
Jamie Madill48ef11b2016-04-27 15:21:52 -0400282GLint ProgramState::getUniformLocation(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400283{
284 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +0800285 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400286
287 for (size_t location = 0; location < mUniformLocations.size(); ++location)
288 {
289 const VariableLocation &uniformLocation = mUniformLocations[location];
Geoff Langd8605522016-04-13 10:19:12 -0400290 if (!uniformLocation.used)
291 {
292 continue;
293 }
294
295 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -0400296
297 if (uniform.name == baseName)
298 {
Geoff Langd8605522016-04-13 10:19:12 -0400299 if (uniform.isArray())
Jamie Madill62d31cb2015-09-11 13:25:51 -0400300 {
Geoff Langd8605522016-04-13 10:19:12 -0400301 if (uniformLocation.element == subscript ||
302 (uniformLocation.element == 0 && subscript == GL_INVALID_INDEX))
303 {
304 return static_cast<GLint>(location);
305 }
306 }
307 else
308 {
309 if (subscript == GL_INVALID_INDEX)
310 {
311 return static_cast<GLint>(location);
312 }
Jamie Madill62d31cb2015-09-11 13:25:51 -0400313 }
314 }
315 }
316
317 return -1;
318}
319
Jamie Madille7d84322017-01-10 18:21:59 -0500320GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
Jamie Madill62d31cb2015-09-11 13:25:51 -0400321{
jchen1015015f72017-03-16 13:54:21 +0800322 return GetResourceIndexFromName(mUniforms, name);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400323}
324
Jamie Madille7d84322017-01-10 18:21:59 -0500325GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
326{
327 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformLocations.size());
328 return mUniformLocations[location].index;
329}
330
331Optional<GLuint> ProgramState::getSamplerIndex(GLint location) const
332{
333 GLuint index = getUniformIndexFromLocation(location);
334 if (!isSamplerUniformIndex(index))
335 {
336 return Optional<GLuint>::Invalid();
337 }
338
339 return getSamplerIndexFromUniformIndex(index);
340}
341
342bool ProgramState::isSamplerUniformIndex(GLuint index) const
343{
344 return index >= mSamplerUniformRange.start && index < mSamplerUniformRange.end;
345}
346
347GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
348{
349 ASSERT(isSamplerUniformIndex(uniformIndex));
350 return uniformIndex - mSamplerUniformRange.start;
351}
352
Geoff Lang4ddf5af2016-12-01 14:30:44 -0500353Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle)
Jamie Madill48ef11b2016-04-27 15:21:52 -0400354 : mProgram(factory->createProgram(mState)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400355 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500356 mLinked(false),
357 mDeleteStatus(false),
358 mRefCount(0),
359 mResourceManager(manager),
Jamie Madille7d84322017-01-10 18:21:59 -0500360 mHandle(handle)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500361{
362 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000363
364 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500365 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366}
367
368Program::~Program()
369{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500370 ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader &&
371 !mState.mAttachedComputeShader);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500372 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373}
374
Jamie Madill6c1f6712017-02-14 19:08:04 -0500375void Program::destroy(const Context *context)
376{
377 if (mState.mAttachedVertexShader != nullptr)
378 {
379 mState.mAttachedVertexShader->release(context);
380 mState.mAttachedVertexShader = nullptr;
381 }
382
383 if (mState.mAttachedFragmentShader != nullptr)
384 {
385 mState.mAttachedFragmentShader->release(context);
386 mState.mAttachedFragmentShader = nullptr;
387 }
388
389 if (mState.mAttachedComputeShader != nullptr)
390 {
391 mState.mAttachedComputeShader->release(context);
392 mState.mAttachedComputeShader = nullptr;
393 }
394
395 mProgram->destroy(rx::SafeGetImpl(context));
396}
397
Geoff Lang70d0f492015-12-10 17:45:46 -0500398void Program::setLabel(const std::string &label)
399{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400400 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500401}
402
403const std::string &Program::getLabel() const
404{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400405 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500406}
407
Jamie Madillef300b12016-10-07 15:12:09 -0400408void Program::attachShader(Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000409{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300410 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300412 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 {
Jamie Madillef300b12016-10-07 15:12:09 -0400414 ASSERT(!mState.mAttachedVertexShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300415 mState.mAttachedVertexShader = shader;
416 mState.mAttachedVertexShader->addRef();
417 break;
418 }
419 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 {
Jamie Madillef300b12016-10-07 15:12:09 -0400421 ASSERT(!mState.mAttachedFragmentShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300422 mState.mAttachedFragmentShader = shader;
423 mState.mAttachedFragmentShader->addRef();
424 break;
425 }
426 case GL_COMPUTE_SHADER:
427 {
Jamie Madillef300b12016-10-07 15:12:09 -0400428 ASSERT(!mState.mAttachedComputeShader);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300429 mState.mAttachedComputeShader = shader;
430 mState.mAttachedComputeShader->addRef();
431 break;
432 }
433 default:
434 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436}
437
Jamie Madill6c1f6712017-02-14 19:08:04 -0500438bool Program::detachShader(const Context *context, Shader *shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300440 switch (shader->getType())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300442 case GL_VERTEX_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300444 if (mState.mAttachedVertexShader != shader)
445 {
446 return false;
447 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448
Jamie Madill6c1f6712017-02-14 19:08:04 -0500449 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300450 mState.mAttachedVertexShader = nullptr;
451 break;
452 }
453 case GL_FRAGMENT_SHADER:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300455 if (mState.mAttachedFragmentShader != shader)
456 {
457 return false;
458 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459
Jamie Madill6c1f6712017-02-14 19:08:04 -0500460 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300461 mState.mAttachedFragmentShader = nullptr;
462 break;
463 }
464 case GL_COMPUTE_SHADER:
465 {
466 if (mState.mAttachedComputeShader != shader)
467 {
468 return false;
469 }
470
Jamie Madill6c1f6712017-02-14 19:08:04 -0500471 shader->release(context);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300472 mState.mAttachedComputeShader = nullptr;
473 break;
474 }
475 default:
476 UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479 return true;
480}
481
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000482int Program::getAttachedShadersCount() const
483{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300484 return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
485 (mState.mAttachedComputeShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000486}
487
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000488void Program::bindAttributeLocation(GLuint index, const char *name)
489{
Geoff Langd8605522016-04-13 10:19:12 -0400490 mAttributeBindings.bindLocation(index, name);
491}
492
493void Program::bindUniformLocation(GLuint index, const char *name)
494{
495 // Bind the base uniform name only since array indices other than 0 cannot be bound
jchen1015015f72017-03-16 13:54:21 +0800496 mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497}
498
Sami Väisänen46eaa942016-06-29 10:26:37 +0300499void Program::bindFragmentInputLocation(GLint index, const char *name)
500{
501 mFragmentInputBindings.bindLocation(index, name);
502}
503
504BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
505{
506 BindingInfo ret;
507 ret.type = GL_NONE;
508 ret.valid = false;
509
510 const Shader *fragmentShader = mState.getAttachedFragmentShader();
511 ASSERT(fragmentShader);
512
513 // Find the actual fragment shader varying we're interested in
514 const std::vector<sh::Varying> &inputs = fragmentShader->getVaryings();
515
516 for (const auto &binding : mFragmentInputBindings)
517 {
518 if (binding.second != static_cast<GLuint>(index))
519 continue;
520
521 ret.valid = true;
522
523 std::string originalName = binding.first;
Geoff Lang3f6a3982016-07-15 15:20:45 -0400524 unsigned int arrayIndex = ParseAndStripArrayIndex(&originalName);
Sami Väisänen46eaa942016-06-29 10:26:37 +0300525
526 for (const auto &in : inputs)
527 {
528 if (in.name == originalName)
529 {
530 if (in.isArray())
531 {
532 // The client wants to bind either "name" or "name[0]".
533 // GL ES 3.1 spec refers to active array names with language such as:
534 // "if the string identifies the base name of an active array, where the
535 // string would exactly match the name of the variable if the suffix "[0]"
536 // were appended to the string".
Geoff Lang3f6a3982016-07-15 15:20:45 -0400537 if (arrayIndex == GL_INVALID_INDEX)
538 arrayIndex = 0;
Sami Väisänen46eaa942016-06-29 10:26:37 +0300539
Corentin Wallez054f7ed2016-09-20 17:15:59 -0400540 ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]";
Sami Väisänen46eaa942016-06-29 10:26:37 +0300541 }
542 else
543 {
544 ret.name = in.mappedName;
545 }
546 ret.type = in.type;
547 return ret;
548 }
549 }
550 }
551
552 return ret;
553}
554
555void Program::pathFragmentInputGen(GLint index,
556 GLenum genMode,
557 GLint components,
558 const GLfloat *coeffs)
559{
560 // If the location is -1 then the command is silently ignored
561 if (index == -1)
562 return;
563
564 const auto &binding = getFragmentInputBindingInfo(index);
565
566 // If the input doesn't exist then then the command is silently ignored
567 // This could happen through optimization for example, the shader translator
568 // decides that a variable is not actually being used and optimizes it away.
569 if (binding.name.empty())
570 return;
571
572 mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
573}
574
Martin Radev4c4c8e72016-08-04 12:25:34 +0300575// The attached shaders are checked for linking errors by matching up their variables.
576// Uniform, input and output variables get collected.
577// The code gets compiled into binaries.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500578Error Program::link(const gl::Context *context)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000579{
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500580 const auto &data = context->getContextState();
581
Jamie Madill6c1f6712017-02-14 19:08:04 -0500582 unlink();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000583
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000584 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000585 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000586
Martin Radev4c4c8e72016-08-04 12:25:34 +0300587 const Caps &caps = data.getCaps();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500588
Jamie Madill192745a2016-12-22 15:58:21 -0500589 auto vertexShader = mState.mAttachedVertexShader;
590 auto fragmentShader = mState.mAttachedFragmentShader;
591 auto computeShader = mState.mAttachedComputeShader;
592
593 bool isComputeShaderAttached = (computeShader != nullptr);
594 bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300595 // Check whether we both have a compute and non-compute shaders attached.
596 // If there are of both types attached, then linking should fail.
597 // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
598 if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500599 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300600 mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
601 return NoError();
Yuly Novikovcfa48d32016-06-15 22:14:36 -0400602 }
603
Jamie Madill192745a2016-12-22 15:58:21 -0500604 if (computeShader)
Jamie Madill437d2662014-12-05 14:23:35 -0500605 {
Jamie Madill192745a2016-12-22 15:58:21 -0500606 if (!computeShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300607 {
608 mInfoLog << "Attached compute shader is not compiled.";
609 return NoError();
610 }
Jamie Madill192745a2016-12-22 15:58:21 -0500611 ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300612
Jamie Madill192745a2016-12-22 15:58:21 -0500613 mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300614
615 // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
616 // If the work group size is not specified, a link time error should occur.
617 if (!mState.mComputeShaderLocalSize.isDeclared())
618 {
619 mInfoLog << "Work group size is not specified.";
620 return NoError();
621 }
622
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000623 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300624 {
625 return NoError();
626 }
627
628 if (!linkUniformBlocks(mInfoLog, caps))
629 {
630 return NoError();
631 }
632
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500633 gl::VaryingPacking noPacking(0, PackMode::ANGLE_RELAXED);
634 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), noPacking, mInfoLog),
635 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500636 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300637 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500638 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300639 }
640 }
641 else
642 {
Jamie Madill192745a2016-12-22 15:58:21 -0500643 if (!fragmentShader || !fragmentShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300644 {
645 return NoError();
646 }
Jamie Madill192745a2016-12-22 15:58:21 -0500647 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300648
Jamie Madill192745a2016-12-22 15:58:21 -0500649 if (!vertexShader || !vertexShader->isCompiled())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300650 {
651 return NoError();
652 }
Jamie Madill192745a2016-12-22 15:58:21 -0500653 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300654
Jamie Madill192745a2016-12-22 15:58:21 -0500655 if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
Martin Radev4c4c8e72016-08-04 12:25:34 +0300656 {
657 mInfoLog << "Fragment shader version does not match vertex shader version.";
658 return NoError();
659 }
660
Jamie Madilleb979bf2016-11-15 12:28:46 -0500661 if (!linkAttributes(data, mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300662 {
663 return NoError();
664 }
665
Jamie Madill192745a2016-12-22 15:58:21 -0500666 if (!linkVaryings(mInfoLog))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300667 {
668 return NoError();
669 }
670
Olli Etuaho4a92ceb2017-02-19 17:51:24 +0000671 if (!linkUniforms(mInfoLog, caps, mUniformLocationBindings))
Martin Radev4c4c8e72016-08-04 12:25:34 +0300672 {
673 return NoError();
674 }
675
676 if (!linkUniformBlocks(mInfoLog, caps))
677 {
678 return NoError();
679 }
680
681 const auto &mergedVaryings = getMergedVaryings();
682
683 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
684 {
685 return NoError();
686 }
687
688 linkOutputVariables();
689
Jamie Madill192745a2016-12-22 15:58:21 -0500690 // Validate we can pack the varyings.
691 std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
692
693 // Map the varyings to the register file
694 // In WebGL, we use a slightly different handling for packing variables.
695 auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
696 : PackMode::ANGLE_RELAXED;
697 VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
698 if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
699 mState.getTransformFeedbackVaryingNames()))
700 {
701 return NoError();
702 }
703
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500704 ANGLE_TRY_RESULT(mProgram->link(context->getImplementation(), varyingPacking, mInfoLog),
705 mLinked);
Jamie Madillb0a838b2016-11-13 20:02:12 -0500706 if (!mLinked)
Martin Radev4c4c8e72016-08-04 12:25:34 +0300707 {
Jamie Madillb0a838b2016-11-13 20:02:12 -0500708 return NoError();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300709 }
710
711 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill437d2662014-12-05 14:23:35 -0500712 }
713
Olli Etuaho48fed632017-03-16 12:05:30 +0000714 setUniformValuesFromBindingQualifiers();
715
Jamie Madill4a3c2342015-10-08 12:58:45 -0400716 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400717
Martin Radev4c4c8e72016-08-04 12:25:34 +0300718 return NoError();
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000719}
720
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000721// Returns the program object to an unlinked state, before re-linking, or at destruction
Jamie Madill6c1f6712017-02-14 19:08:04 -0500722void Program::unlink()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400724 mState.mAttributes.clear();
725 mState.mActiveAttribLocationsMask.reset();
726 mState.mTransformFeedbackVaryingVars.clear();
727 mState.mUniforms.clear();
728 mState.mUniformLocations.clear();
729 mState.mUniformBlocks.clear();
730 mState.mOutputVariables.clear();
jchen1015015f72017-03-16 13:54:21 +0800731 mState.mOutputLocations.clear();
Martin Radev4c4c8e72016-08-04 12:25:34 +0300732 mState.mComputeShaderLocalSize.fill(1);
Jamie Madille7d84322017-01-10 18:21:59 -0500733 mState.mSamplerBindings.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500734
Geoff Lang7dd2e102014-11-10 15:19:26 -0500735 mValidated = false;
736
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000737 mLinked = false;
738}
739
Geoff Lange1a27752015-10-05 13:16:04 -0400740bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000741{
742 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743}
744
Jamie Madilla2c74982016-12-12 11:20:42 -0500745Error Program::loadBinary(const Context *context,
746 GLenum binaryFormat,
747 const void *binary,
748 GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000749{
Jamie Madill6c1f6712017-02-14 19:08:04 -0500750 unlink();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000751
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
He Yunchaoacd18982017-01-04 10:46:42 +0800753 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500754#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400755 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
756 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000757 {
Jamie Madillf6113162015-05-07 11:49:21 -0400758 mInfoLog << "Invalid program binary format.";
He Yunchaoacd18982017-01-04 10:46:42 +0800759 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500760 }
761
Geoff Langc46cc2f2015-10-01 17:16:20 -0400762 BinaryInputStream stream(binary, length);
763
Jamie Madilla2c74982016-12-12 11:20:42 -0500764 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
765 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
766 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
767 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500768 {
Jamie Madillf6113162015-05-07 11:49:21 -0400769 mInfoLog << "Invalid program binary version.";
He Yunchaoacd18982017-01-04 10:46:42 +0800770 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500771 }
772
Jamie Madilla2c74982016-12-12 11:20:42 -0500773 int majorVersion = stream.readInt<int>();
774 int minorVersion = stream.readInt<int>();
775 if (majorVersion != context->getClientMajorVersion() ||
776 minorVersion != context->getClientMinorVersion())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777 {
Jamie Madilla2c74982016-12-12 11:20:42 -0500778 mInfoLog << "Cannot load program binaries across different ES context versions.";
He Yunchaoacd18982017-01-04 10:46:42 +0800779 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500780 }
781
Martin Radev4c4c8e72016-08-04 12:25:34 +0300782 mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
783 mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
784 mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
785
Jamie Madill63805b42015-08-25 13:17:39 -0400786 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
787 "Too many vertex attribs for mask");
Jamie Madill48ef11b2016-04-27 15:21:52 -0400788 mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500789
Jamie Madill3da79b72015-04-27 11:09:17 -0400790 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400791 ASSERT(mState.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400792 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
793 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400794 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400795 LoadShaderVar(&stream, &attrib);
796 attrib.location = stream.readInt<int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400797 mState.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400798 }
799
Jamie Madill62d31cb2015-09-11 13:25:51 -0400800 unsigned int uniformCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400801 ASSERT(mState.mUniforms.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400802 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
803 {
804 LinkedUniform uniform;
805 LoadShaderVar(&stream, &uniform);
806
807 uniform.blockIndex = stream.readInt<int>();
808 uniform.blockInfo.offset = stream.readInt<int>();
809 uniform.blockInfo.arrayStride = stream.readInt<int>();
810 uniform.blockInfo.matrixStride = stream.readInt<int>();
811 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
812
Jamie Madill48ef11b2016-04-27 15:21:52 -0400813 mState.mUniforms.push_back(uniform);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400814 }
815
816 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400817 ASSERT(mState.mUniformLocations.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400818 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
819 uniformIndexIndex++)
820 {
821 VariableLocation variable;
822 stream.readString(&variable.name);
823 stream.readInt(&variable.element);
824 stream.readInt(&variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400825 stream.readBool(&variable.used);
826 stream.readBool(&variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400827
Jamie Madill48ef11b2016-04-27 15:21:52 -0400828 mState.mUniformLocations.push_back(variable);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400829 }
830
831 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400832 ASSERT(mState.mUniformBlocks.empty());
Jamie Madill62d31cb2015-09-11 13:25:51 -0400833 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
834 ++uniformBlockIndex)
835 {
836 UniformBlock uniformBlock;
837 stream.readString(&uniformBlock.name);
838 stream.readBool(&uniformBlock.isArray);
839 stream.readInt(&uniformBlock.arrayElement);
840 stream.readInt(&uniformBlock.dataSize);
841 stream.readBool(&uniformBlock.vertexStaticUse);
842 stream.readBool(&uniformBlock.fragmentStaticUse);
843
844 unsigned int numMembers = stream.readInt<unsigned int>();
845 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
846 {
847 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
848 }
849
Jamie Madill48ef11b2016-04-27 15:21:52 -0400850 mState.mUniformBlocks.push_back(uniformBlock);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400851 }
852
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500853 for (GLuint bindingIndex = 0; bindingIndex < mState.mUniformBlockBindings.size();
854 ++bindingIndex)
855 {
856 stream.readInt(&mState.mUniformBlockBindings[bindingIndex]);
857 mState.mActiveUniformBlockBindings.set(bindingIndex,
858 mState.mUniformBlockBindings[bindingIndex] != 0);
859 }
860
Brandon Jones1048ea72015-10-06 15:34:52 -0700861 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madill48ef11b2016-04-27 15:21:52 -0400862 ASSERT(mState.mTransformFeedbackVaryingVars.empty());
Brandon Jones1048ea72015-10-06 15:34:52 -0700863 for (unsigned int transformFeedbackVaryingIndex = 0;
864 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
865 ++transformFeedbackVaryingIndex)
866 {
867 sh::Varying varying;
868 stream.readInt(&varying.arraySize);
869 stream.readInt(&varying.type);
870 stream.readString(&varying.name);
871
Jamie Madill48ef11b2016-04-27 15:21:52 -0400872 mState.mTransformFeedbackVaryingVars.push_back(varying);
Brandon Jones1048ea72015-10-06 15:34:52 -0700873 }
874
Jamie Madill48ef11b2016-04-27 15:21:52 -0400875 stream.readInt(&mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -0400876
jchen1015015f72017-03-16 13:54:21 +0800877 unsigned int outputCount = stream.readInt<unsigned int>();
878 ASSERT(mState.mOutputVariables.empty());
879 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
880 {
881 sh::OutputVariable output;
882 LoadShaderVar(&stream, &output);
883 output.location = stream.readInt<int>();
884 mState.mOutputVariables.push_back(output);
885 }
886
Jamie Madill80a6fc02015-08-21 16:53:16 -0400887 unsigned int outputVarCount = stream.readInt<unsigned int>();
888 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
889 {
890 int locationIndex = stream.readInt<int>();
891 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400892 stream.readInt(&locationData.element);
893 stream.readInt(&locationData.index);
894 stream.readString(&locationData.name);
jchen1015015f72017-03-16 13:54:21 +0800895 mState.mOutputLocations[locationIndex] = locationData;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400896 }
897
Jamie Madille7d84322017-01-10 18:21:59 -0500898 stream.readInt(&mState.mSamplerUniformRange.start);
899 stream.readInt(&mState.mSamplerUniformRange.end);
900
901 unsigned int samplerCount = stream.readInt<unsigned int>();
902 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
903 {
904 GLenum textureType = stream.readInt<GLenum>();
905 size_t bindingCount = stream.readInt<size_t>();
906 mState.mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
907 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400908
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500909 ANGLE_TRY_RESULT(mProgram->load(context->getImplementation(), mInfoLog, &stream), mLinked);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000910
Jamie Madillb0a838b2016-11-13 20:02:12 -0500911 return NoError();
Jamie Madilla2c74982016-12-12 11:20:42 -0500912#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
Geoff Lang7dd2e102014-11-10 15:19:26 -0500913}
914
Jamie Madilla2c74982016-12-12 11:20:42 -0500915Error Program::saveBinary(const Context *context,
916 GLenum *binaryFormat,
917 void *binary,
918 GLsizei bufSize,
919 GLsizei *length) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500920{
921 if (binaryFormat)
922 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400923 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500924 }
925
926 BinaryOutputStream stream;
927
Geoff Lang7dd2e102014-11-10 15:19:26 -0500928 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
929
Jamie Madilla2c74982016-12-12 11:20:42 -0500930 // nullptr context is supported when computing binary length.
931 if (context)
932 {
933 stream.writeInt(context->getClientVersion().major);
934 stream.writeInt(context->getClientVersion().minor);
935 }
936 else
937 {
938 stream.writeInt(2);
939 stream.writeInt(0);
940 }
941
Martin Radev4c4c8e72016-08-04 12:25:34 +0300942 stream.writeInt(mState.mComputeShaderLocalSize[0]);
943 stream.writeInt(mState.mComputeShaderLocalSize[1]);
944 stream.writeInt(mState.mComputeShaderLocalSize[2]);
945
Jamie Madill48ef11b2016-04-27 15:21:52 -0400946 stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500947
Jamie Madill48ef11b2016-04-27 15:21:52 -0400948 stream.writeInt(mState.mAttributes.size());
949 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400950 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400951 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400952 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400953 }
954
Jamie Madill48ef11b2016-04-27 15:21:52 -0400955 stream.writeInt(mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -0500956 for (const LinkedUniform &uniform : mState.mUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400957 {
958 WriteShaderVar(&stream, uniform);
959
960 // FIXME: referenced
961
962 stream.writeInt(uniform.blockIndex);
963 stream.writeInt(uniform.blockInfo.offset);
964 stream.writeInt(uniform.blockInfo.arrayStride);
965 stream.writeInt(uniform.blockInfo.matrixStride);
966 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
967 }
968
Jamie Madill48ef11b2016-04-27 15:21:52 -0400969 stream.writeInt(mState.mUniformLocations.size());
970 for (const auto &variable : mState.mUniformLocations)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400971 {
972 stream.writeString(variable.name);
973 stream.writeInt(variable.element);
974 stream.writeInt(variable.index);
Geoff Langd8605522016-04-13 10:19:12 -0400975 stream.writeInt(variable.used);
976 stream.writeInt(variable.ignored);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400977 }
978
Jamie Madill48ef11b2016-04-27 15:21:52 -0400979 stream.writeInt(mState.mUniformBlocks.size());
980 for (const UniformBlock &uniformBlock : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -0400981 {
982 stream.writeString(uniformBlock.name);
983 stream.writeInt(uniformBlock.isArray);
984 stream.writeInt(uniformBlock.arrayElement);
985 stream.writeInt(uniformBlock.dataSize);
986
987 stream.writeInt(uniformBlock.vertexStaticUse);
988 stream.writeInt(uniformBlock.fragmentStaticUse);
989
990 stream.writeInt(uniformBlock.memberUniformIndexes.size());
991 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
992 {
993 stream.writeInt(memberUniformIndex);
994 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400995 }
996
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500997 for (GLuint binding : mState.mUniformBlockBindings)
998 {
999 stream.writeInt(binding);
1000 }
1001
Jamie Madill48ef11b2016-04-27 15:21:52 -04001002 stream.writeInt(mState.mTransformFeedbackVaryingVars.size());
1003 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Brandon Jones1048ea72015-10-06 15:34:52 -07001004 {
1005 stream.writeInt(varying.arraySize);
1006 stream.writeInt(varying.type);
1007 stream.writeString(varying.name);
1008 }
1009
Jamie Madill48ef11b2016-04-27 15:21:52 -04001010 stream.writeInt(mState.mTransformFeedbackBufferMode);
Jamie Madillada9ecc2015-08-17 12:53:37 -04001011
Jamie Madill48ef11b2016-04-27 15:21:52 -04001012 stream.writeInt(mState.mOutputVariables.size());
jchen1015015f72017-03-16 13:54:21 +08001013 for (const sh::OutputVariable &output : mState.mOutputVariables)
1014 {
1015 WriteShaderVar(&stream, output);
1016 stream.writeInt(output.location);
1017 }
1018
1019 stream.writeInt(mState.mOutputLocations.size());
1020 for (const auto &outputPair : mState.mOutputLocations)
Jamie Madill80a6fc02015-08-21 16:53:16 -04001021 {
1022 stream.writeInt(outputPair.first);
Jamie Madille2e406c2016-06-02 13:04:10 -04001023 stream.writeIntOrNegOne(outputPair.second.element);
Jamie Madill80a6fc02015-08-21 16:53:16 -04001024 stream.writeInt(outputPair.second.index);
1025 stream.writeString(outputPair.second.name);
1026 }
1027
Jamie Madille7d84322017-01-10 18:21:59 -05001028 stream.writeInt(mState.mSamplerUniformRange.start);
1029 stream.writeInt(mState.mSamplerUniformRange.end);
1030
1031 stream.writeInt(mState.mSamplerBindings.size());
1032 for (const auto &samplerBinding : mState.mSamplerBindings)
1033 {
1034 stream.writeInt(samplerBinding.textureType);
1035 stream.writeInt(samplerBinding.boundTextureUnits.size());
1036 }
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001037
Jamie Madilla2c74982016-12-12 11:20:42 -05001038 ANGLE_TRY(mProgram->save(&stream));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001039
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001040 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Jamie Madill48ef11b2016-04-27 15:21:52 -04001041 const void *streamState = stream.data();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042
1043 if (streamLength > bufSize)
1044 {
1045 if (length)
1046 {
1047 *length = 0;
1048 }
1049
1050 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1051 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1052 // sizes and then copy it.
1053 return Error(GL_INVALID_OPERATION);
1054 }
1055
1056 if (binary)
1057 {
1058 char *ptr = reinterpret_cast<char*>(binary);
1059
Jamie Madill48ef11b2016-04-27 15:21:52 -04001060 memcpy(ptr, streamState, streamLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061 ptr += streamLength;
1062
1063 ASSERT(ptr - streamLength == binary);
1064 }
1065
1066 if (length)
1067 {
1068 *length = streamLength;
1069 }
1070
He Yunchaoacd18982017-01-04 10:46:42 +08001071 return NoError();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001072}
1073
1074GLint Program::getBinaryLength() const
1075{
1076 GLint length;
Jamie Madilla2c74982016-12-12 11:20:42 -05001077 Error error = saveBinary(nullptr, nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001078 if (error.isError())
1079 {
1080 return 0;
1081 }
1082
1083 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +00001084}
1085
Geoff Langc5629752015-12-07 16:29:04 -05001086void Program::setBinaryRetrievableHint(bool retrievable)
1087{
1088 // TODO(jmadill) : replace with dirty bits
1089 mProgram->setBinaryRetrievableHint(retrievable);
Jamie Madill48ef11b2016-04-27 15:21:52 -04001090 mState.mBinaryRetrieveableHint = retrievable;
Geoff Langc5629752015-12-07 16:29:04 -05001091}
1092
1093bool Program::getBinaryRetrievableHint() const
1094{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001095 return mState.mBinaryRetrieveableHint;
Geoff Langc5629752015-12-07 16:29:04 -05001096}
1097
Yunchao He61afff12017-03-14 15:34:03 +08001098void Program::setSeparable(bool separable)
1099{
1100 // TODO(yunchao) : replace with dirty bits
1101 if (mState.mSeparable != separable)
1102 {
1103 mProgram->setSeparable(separable);
1104 mState.mSeparable = separable;
1105 }
1106}
1107
1108bool Program::isSeparable() const
1109{
1110 return mState.mSeparable;
1111}
1112
Jamie Madill6c1f6712017-02-14 19:08:04 -05001113void Program::release(const Context *context)
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001114{
1115 mRefCount--;
1116
1117 if (mRefCount == 0 && mDeleteStatus)
1118 {
Jamie Madill6c1f6712017-02-14 19:08:04 -05001119 mResourceManager->deleteProgram(context, mHandle);
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +00001120 }
1121}
1122
1123void Program::addRef()
1124{
1125 mRefCount++;
1126}
1127
1128unsigned int Program::getRefCount() const
1129{
1130 return mRefCount;
1131}
1132
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001133int Program::getInfoLogLength() const
1134{
Jamie Madill71c3b2c2015-05-07 11:49:20 -04001135 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001136}
1137
Geoff Lange1a27752015-10-05 13:16:04 -04001138void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001139{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001140 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001141}
1142
Geoff Lange1a27752015-10-05 13:16:04 -04001143void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001144{
1145 int total = 0;
1146
Martin Radev4c4c8e72016-08-04 12:25:34 +03001147 if (mState.mAttachedComputeShader)
1148 {
1149 if (total < maxCount)
1150 {
1151 shaders[total] = mState.mAttachedComputeShader->getHandle();
1152 total++;
1153 }
1154 }
1155
Jamie Madill48ef11b2016-04-27 15:21:52 -04001156 if (mState.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001157 {
1158 if (total < maxCount)
1159 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001160 shaders[total] = mState.mAttachedVertexShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001161 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001162 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001163 }
1164
Jamie Madill48ef11b2016-04-27 15:21:52 -04001165 if (mState.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001166 {
1167 if (total < maxCount)
1168 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001169 shaders[total] = mState.mAttachedFragmentShader->getHandle();
Olli Etuaho586bc552016-03-04 11:46:03 +02001170 total++;
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001171 }
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001172 }
1173
1174 if (count)
1175 {
1176 *count = total;
1177 }
1178}
1179
Geoff Lange1a27752015-10-05 13:16:04 -04001180GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001181{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001182 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001183 {
jchen1036e120e2017-03-14 14:53:58 +08001184 if (attribute.name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001185 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001186 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001187 }
1188 }
1189
Austin Kinrossb8af7232015-03-16 22:33:25 -07001190 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001191}
1192
Jamie Madill63805b42015-08-25 13:17:39 -04001193bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001194{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001195 ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size());
1196 return mState.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001197}
1198
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001199void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
1200{
Jamie Madillc349ec02015-08-21 16:53:12 -04001201 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001202 {
1203 if (bufsize > 0)
1204 {
1205 name[0] = '\0';
1206 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001207
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001208 if (length)
1209 {
1210 *length = 0;
1211 }
1212
1213 *type = GL_NONE;
1214 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -04001215 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001216 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001217
jchen1036e120e2017-03-14 14:53:58 +08001218 ASSERT(index < mState.mAttributes.size());
1219 const sh::Attribute &attrib = mState.mAttributes[index];
Jamie Madillc349ec02015-08-21 16:53:12 -04001220
1221 if (bufsize > 0)
1222 {
1223 const char *string = attrib.name.c_str();
1224
1225 strncpy(name, string, bufsize);
1226 name[bufsize - 1] = '\0';
1227
1228 if (length)
1229 {
1230 *length = static_cast<GLsizei>(strlen(name));
1231 }
1232 }
1233
1234 // Always a single 'type' instance
1235 *size = 1;
1236 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001237}
1238
Geoff Lange1a27752015-10-05 13:16:04 -04001239GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001240{
Jamie Madillc349ec02015-08-21 16:53:12 -04001241 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001242 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001243 return 0;
1244 }
1245
jchen1036e120e2017-03-14 14:53:58 +08001246 return static_cast<GLint>(mState.mAttributes.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001247}
1248
Geoff Lange1a27752015-10-05 13:16:04 -04001249GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001250{
Jamie Madillc349ec02015-08-21 16:53:12 -04001251 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -04001252 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001253 return 0;
1254 }
1255
1256 size_t maxLength = 0;
1257
Jamie Madill48ef11b2016-04-27 15:21:52 -04001258 for (const sh::Attribute &attrib : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04001259 {
jchen1036e120e2017-03-14 14:53:58 +08001260 maxLength = std::max(attrib.name.length() + 1, maxLength);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001261 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001262
Jamie Madillc349ec02015-08-21 16:53:12 -04001263 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001264}
1265
jchen1015015f72017-03-16 13:54:21 +08001266GLuint Program::getInputResourceIndex(const GLchar *name) const
1267{
1268 for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
1269 {
1270 const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
1271 if (attribute.name == name)
1272 {
1273 return attributeIndex;
1274 }
1275 }
1276 return GL_INVALID_INDEX;
1277}
1278
1279GLuint Program::getOutputResourceIndex(const GLchar *name) const
1280{
1281 return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
1282}
1283
Geoff Lang7dd2e102014-11-10 15:19:26 -05001284GLint Program::getFragDataLocation(const std::string &name) const
1285{
1286 std::string baseName(name);
1287 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
jchen1015015f72017-03-16 13:54:21 +08001288 for (auto outputPair : mState.mOutputLocations)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001289 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001290 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001291 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1292 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001293 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001294 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001295 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001296 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001297}
1298
Geoff Lange1a27752015-10-05 13:16:04 -04001299void Program::getActiveUniform(GLuint index,
1300 GLsizei bufsize,
1301 GLsizei *length,
1302 GLint *size,
1303 GLenum *type,
1304 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001305{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001306 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001307 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001308 // index must be smaller than getActiveUniformCount()
Jamie Madill48ef11b2016-04-27 15:21:52 -04001309 ASSERT(index < mState.mUniforms.size());
1310 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001311
1312 if (bufsize > 0)
1313 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001314 std::string string = uniform.name;
1315 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001316 {
1317 string += "[0]";
1318 }
1319
1320 strncpy(name, string.c_str(), bufsize);
1321 name[bufsize - 1] = '\0';
1322
1323 if (length)
1324 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001325 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001326 }
1327 }
1328
Jamie Madill62d31cb2015-09-11 13:25:51 -04001329 *size = uniform.elementCount();
1330 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001331 }
1332 else
1333 {
1334 if (bufsize > 0)
1335 {
1336 name[0] = '\0';
1337 }
1338
1339 if (length)
1340 {
1341 *length = 0;
1342 }
1343
1344 *size = 0;
1345 *type = GL_NONE;
1346 }
1347}
1348
Geoff Lange1a27752015-10-05 13:16:04 -04001349GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001350{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001351 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001352 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001353 return static_cast<GLint>(mState.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001354 }
1355 else
1356 {
1357 return 0;
1358 }
1359}
1360
Geoff Lange1a27752015-10-05 13:16:04 -04001361GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001362{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001363 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001364
1365 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001366 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001367 for (const LinkedUniform &uniform : mState.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001368 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001369 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001370 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001371 size_t length = uniform.name.length() + 1u;
1372 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373 {
1374 length += 3; // Counting in "[0]".
1375 }
1376 maxLength = std::max(length, maxLength);
1377 }
1378 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001379 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380
Jamie Madill62d31cb2015-09-11 13:25:51 -04001381 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001382}
1383
1384GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1385{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001386 ASSERT(static_cast<size_t>(index) < mState.mUniforms.size());
Jamie Madilla2c74982016-12-12 11:20:42 -05001387 const LinkedUniform &uniform = mState.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001388 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001389 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1391 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1392 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1393 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1394 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1395 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1396 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1397 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1398 default:
1399 UNREACHABLE();
1400 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001401 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001402 return 0;
1403}
1404
1405bool Program::isValidUniformLocation(GLint location) const
1406{
Jamie Madille2e406c2016-06-02 13:04:10 -04001407 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mState.mUniformLocations.size()));
Jamie Madill48ef11b2016-04-27 15:21:52 -04001408 return (location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size() &&
1409 mState.mUniformLocations[static_cast<size_t>(location)].used);
Geoff Langd8605522016-04-13 10:19:12 -04001410}
1411
Jamie Madill62d31cb2015-09-11 13:25:51 -04001412const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001413{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001414 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
Jamie Madille7d84322017-01-10 18:21:59 -05001415 return mState.mUniforms[mState.getUniformIndexFromLocation(location)];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001416}
1417
Jamie Madillac4e9c32017-01-13 14:07:12 -05001418const VariableLocation &Program::getUniformLocation(GLint location) const
1419{
1420 ASSERT(location >= 0 && static_cast<size_t>(location) < mState.mUniformLocations.size());
1421 return mState.mUniformLocations[location];
1422}
1423
1424const std::vector<VariableLocation> &Program::getUniformLocations() const
1425{
1426 return mState.mUniformLocations;
1427}
1428
1429const LinkedUniform &Program::getUniformByIndex(GLuint index) const
1430{
1431 ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
1432 return mState.mUniforms[index];
1433}
1434
Jamie Madill62d31cb2015-09-11 13:25:51 -04001435GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001436{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001437 return mState.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438}
1439
Jamie Madill62d31cb2015-09-11 13:25:51 -04001440GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001441{
Jamie Madille7d84322017-01-10 18:21:59 -05001442 return mState.getUniformIndexFromName(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443}
1444
1445void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1446{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001447 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1448 mProgram->setUniform1fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001449}
1450
1451void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1452{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001453 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1454 mProgram->setUniform2fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001455}
1456
1457void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1458{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001459 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1460 mProgram->setUniform3fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461}
1462
1463void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1464{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001465 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1466 mProgram->setUniform4fv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467}
1468
1469void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1470{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001471 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1472 mProgram->setUniform1iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001473}
1474
1475void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1476{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001477 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1478 mProgram->setUniform2iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479}
1480
1481void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1482{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001483 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1484 mProgram->setUniform3iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001485}
1486
1487void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1488{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001489 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1490 mProgram->setUniform4iv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491}
1492
1493void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1494{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001495 GLsizei clampedCount = setUniformInternal(location, count, 1, v);
1496 mProgram->setUniform1uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001497}
1498
1499void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1500{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001501 GLsizei clampedCount = setUniformInternal(location, count, 2, v);
1502 mProgram->setUniform2uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503}
1504
1505void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1506{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001507 GLsizei clampedCount = setUniformInternal(location, count, 3, v);
1508 mProgram->setUniform3uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001509}
1510
1511void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1512{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001513 GLsizei clampedCount = setUniformInternal(location, count, 4, v);
1514 mProgram->setUniform4uiv(location, clampedCount, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515}
1516
1517void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1518{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001519 GLsizei clampedCount = setMatrixUniformInternal<2, 2>(location, count, transpose, v);
1520 mProgram->setUniformMatrix2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001521}
1522
1523void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1524{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001525 GLsizei clampedCount = setMatrixUniformInternal<3, 3>(location, count, transpose, v);
1526 mProgram->setUniformMatrix3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001527}
1528
1529void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1530{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001531 GLsizei clampedCount = setMatrixUniformInternal<4, 4>(location, count, transpose, v);
1532 mProgram->setUniformMatrix4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001533}
1534
1535void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1536{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001537 GLsizei clampedCount = setMatrixUniformInternal<2, 3>(location, count, transpose, v);
1538 mProgram->setUniformMatrix2x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539}
1540
1541void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1542{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001543 GLsizei clampedCount = setMatrixUniformInternal<2, 4>(location, count, transpose, v);
1544 mProgram->setUniformMatrix2x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545}
1546
1547void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1548{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001549 GLsizei clampedCount = setMatrixUniformInternal<3, 2>(location, count, transpose, v);
1550 mProgram->setUniformMatrix3x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001551}
1552
1553void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1554{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001555 GLsizei clampedCount = setMatrixUniformInternal<3, 4>(location, count, transpose, v);
1556 mProgram->setUniformMatrix3x4fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557}
1558
1559void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1560{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001561 GLsizei clampedCount = setMatrixUniformInternal<4, 2>(location, count, transpose, v);
1562 mProgram->setUniformMatrix4x2fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001563}
1564
1565void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1566{
Corentin Wallez8b7d8142016-11-15 13:40:37 -05001567 GLsizei clampedCount = setMatrixUniformInternal<4, 3>(location, count, transpose, v);
1568 mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569}
1570
Geoff Lange1a27752015-10-05 13:16:04 -04001571void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001572{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001573 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001574}
1575
Geoff Lange1a27752015-10-05 13:16:04 -04001576void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001577{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001578 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001579}
1580
Geoff Lange1a27752015-10-05 13:16:04 -04001581void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001582{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001583 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001584}
1585
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001586void Program::flagForDeletion()
1587{
1588 mDeleteStatus = true;
1589}
1590
1591bool Program::isFlaggedForDeletion() const
1592{
1593 return mDeleteStatus;
1594}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001595
Brandon Jones43a53e22014-08-28 16:23:22 -07001596void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001597{
1598 mInfoLog.reset();
1599
Geoff Lang7dd2e102014-11-10 15:19:26 -05001600 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001601 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001602 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001603 }
1604 else
1605 {
Jamie Madillf6113162015-05-07 11:49:21 -04001606 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001607 }
1608}
1609
Geoff Lang7dd2e102014-11-10 15:19:26 -05001610bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1611{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001612 // Skip cache if we're using an infolog, so we get the full error.
1613 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1614 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1615 {
1616 return mCachedValidateSamplersResult.value();
1617 }
1618
1619 if (mTextureUnitTypesCache.empty())
1620 {
1621 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1622 }
1623 else
1624 {
1625 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1626 }
1627
1628 // if any two active samplers in a program are of different types, but refer to the same
1629 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1630 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madille7d84322017-01-10 18:21:59 -05001631 for (const auto &samplerBinding : mState.mSamplerBindings)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001632 {
Jamie Madille7d84322017-01-10 18:21:59 -05001633 GLenum textureType = samplerBinding.textureType;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001634
Jamie Madille7d84322017-01-10 18:21:59 -05001635 for (GLuint textureUnit : samplerBinding.boundTextureUnits)
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001636 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001637 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1638 {
1639 if (infoLog)
1640 {
1641 (*infoLog) << "Sampler uniform (" << textureUnit
1642 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1643 << caps.maxCombinedTextureImageUnits << ")";
1644 }
1645
1646 mCachedValidateSamplersResult = false;
1647 return false;
1648 }
1649
1650 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1651 {
1652 if (textureType != mTextureUnitTypesCache[textureUnit])
1653 {
1654 if (infoLog)
1655 {
1656 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1657 "image unit ("
1658 << textureUnit << ").";
1659 }
1660
1661 mCachedValidateSamplersResult = false;
1662 return false;
1663 }
1664 }
1665 else
1666 {
1667 mTextureUnitTypesCache[textureUnit] = textureType;
1668 }
1669 }
1670 }
1671
1672 mCachedValidateSamplersResult = true;
1673 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001674}
1675
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001676bool Program::isValidated() const
1677{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001678 return mValidated;
1679}
1680
Geoff Lange1a27752015-10-05 13:16:04 -04001681GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001682{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001683 return static_cast<GLuint>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001684}
1685
1686void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1687{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001688 ASSERT(
1689 uniformBlockIndex <
1690 mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001691
Jamie Madill48ef11b2016-04-27 15:21:52 -04001692 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001693
1694 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001695 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001696 std::string string = uniformBlock.name;
1697
Jamie Madill62d31cb2015-09-11 13:25:51 -04001698 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001699 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001700 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001701 }
1702
1703 strncpy(uniformBlockName, string.c_str(), bufSize);
1704 uniformBlockName[bufSize - 1] = '\0';
1705
1706 if (length)
1707 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001708 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001709 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001710 }
1711}
1712
Geoff Lange1a27752015-10-05 13:16:04 -04001713GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001714{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001715 int maxLength = 0;
1716
1717 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001718 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001719 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001720 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1721 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001722 const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001723 if (!uniformBlock.name.empty())
1724 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001725 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001726
1727 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001728 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001729
1730 maxLength = std::max(length + arrayLength, maxLength);
1731 }
1732 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001733 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001734
1735 return maxLength;
1736}
1737
Geoff Lange1a27752015-10-05 13:16:04 -04001738GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001739{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001740 size_t subscript = GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08001741 std::string baseName = ParseResourceName(name, &subscript);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001742
Jamie Madill48ef11b2016-04-27 15:21:52 -04001743 unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
Jamie Madill62d31cb2015-09-11 13:25:51 -04001744 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1745 {
Jamie Madilla2c74982016-12-12 11:20:42 -05001746 const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
Jamie Madill62d31cb2015-09-11 13:25:51 -04001747 if (uniformBlock.name == baseName)
1748 {
1749 const bool arrayElementZero =
1750 (subscript == GL_INVALID_INDEX &&
1751 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1752 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1753 {
1754 return blockIndex;
1755 }
1756 }
1757 }
1758
1759 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001760}
1761
Jamie Madill62d31cb2015-09-11 13:25:51 -04001762const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001763{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001764 ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
1765 return mState.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001766}
1767
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001768void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1769{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001770 mState.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Jamie Madilla7d12dc2016-12-13 15:08:19 -05001771 mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
Geoff Lang5d124a62015-09-15 13:03:27 -04001772 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001773}
1774
1775GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1776{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001777 return mState.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001778}
1779
1780void Program::resetUniformBlockBindings()
1781{
1782 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1783 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001784 mState.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001785 }
Jamie Madill48ef11b2016-04-27 15:21:52 -04001786 mState.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001787}
1788
Geoff Lang48dcae72014-02-05 16:28:24 -05001789void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1790{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001791 mState.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001792 for (GLsizei i = 0; i < count; i++)
1793 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001794 mState.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001795 }
1796
Jamie Madill48ef11b2016-04-27 15:21:52 -04001797 mState.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001798}
1799
1800void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1801{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001803 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001804 ASSERT(index < mState.mTransformFeedbackVaryingVars.size());
1805 const sh::Varying &varying = mState.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001806 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1807 if (length)
1808 {
1809 *length = lastNameIdx;
1810 }
1811 if (size)
1812 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001813 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001814 }
1815 if (type)
1816 {
1817 *type = varying.type;
1818 }
1819 if (name)
1820 {
1821 memcpy(name, varying.name.c_str(), lastNameIdx);
1822 name[lastNameIdx] = '\0';
1823 }
1824 }
1825}
1826
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001827GLsizei Program::getTransformFeedbackVaryingCount() const
1828{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001830 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04001831 return static_cast<GLsizei>(mState.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001832 }
1833 else
1834 {
1835 return 0;
1836 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001837}
1838
1839GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1840{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001842 {
1843 GLsizei maxSize = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04001844 for (const sh::Varying &varying : mState.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001845 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001846 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1847 }
1848
1849 return maxSize;
1850 }
1851 else
1852 {
1853 return 0;
1854 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001855}
1856
1857GLenum Program::getTransformFeedbackBufferMode() const
1858{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001859 return mState.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860}
1861
Jamie Madill192745a2016-12-22 15:58:21 -05001862bool Program::linkVaryings(InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863{
Jamie Madill192745a2016-12-22 15:58:21 -05001864 const Shader *vertexShader = mState.mAttachedVertexShader;
1865 const Shader *fragmentShader = mState.mAttachedFragmentShader;
1866
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001867 ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
1868
Jamie Madill4cff2472015-08-21 16:53:18 -04001869 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1870 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871
Sami Väisänen46eaa942016-06-29 10:26:37 +03001872 std::map<GLuint, std::string> staticFragmentInputLocations;
1873
Jamie Madill4cff2472015-08-21 16:53:18 -04001874 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001876 bool matched = false;
1877
1878 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001879 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001880 {
1881 continue;
1882 }
1883
Jamie Madill4cff2472015-08-21 16:53:18 -04001884 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001885 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001886 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001887 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001888 ASSERT(!input.isBuiltIn());
Yuly Novikova1f6dc92016-06-15 23:27:04 -04001889 if (!linkValidateVaryings(infoLog, output.name, input, output,
1890 vertexShader->getShaderVersion()))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001891 {
1892 return false;
1893 }
1894
Geoff Lang7dd2e102014-11-10 15:19:26 -05001895 matched = true;
1896 break;
1897 }
1898 }
1899
1900 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001901 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001902 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001903 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904 return false;
1905 }
Sami Väisänen46eaa942016-06-29 10:26:37 +03001906
1907 // Check for aliased path rendering input bindings (if any).
1908 // If more than one binding refer statically to the same
1909 // location the link must fail.
1910
1911 if (!output.staticUse)
1912 continue;
1913
1914 const auto inputBinding = mFragmentInputBindings.getBinding(output.name);
1915 if (inputBinding == -1)
1916 continue;
1917
1918 const auto it = staticFragmentInputLocations.find(inputBinding);
1919 if (it == std::end(staticFragmentInputLocations))
1920 {
1921 staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name));
1922 }
1923 else
1924 {
1925 infoLog << "Binding for fragment input " << output.name << " conflicts with "
1926 << it->second;
1927 return false;
1928 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001929 }
1930
Yuly Novikov817232e2017-02-22 18:36:10 -05001931 if (!linkValidateBuiltInVaryings(infoLog))
1932 {
1933 return false;
1934 }
1935
Jamie Madillada9ecc2015-08-17 12:53:37 -04001936 // TODO(jmadill): verify no unmatched vertex varyings?
1937
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938 return true;
1939}
1940
Olli Etuaho4a92ceb2017-02-19 17:51:24 +00001941bool Program::linkUniforms(InfoLog &infoLog,
1942 const Caps &caps,
1943 const Bindings &uniformLocationBindings)
Martin Radev4c4c8e72016-08-04 12:25:34 +03001944{
Olli Etuahob78707c2017-03-09 15:03:11 +00001945 UniformLinker linker(mState);
1946 if (!linker.link(infoLog, caps, uniformLocationBindings))
Jamie Madill62d31cb2015-09-11 13:25:51 -04001947 {
1948 return false;
1949 }
1950
Olli Etuahob78707c2017-03-09 15:03:11 +00001951 linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
Jamie Madill62d31cb2015-09-11 13:25:51 -04001952
Olli Etuaho48fed632017-03-16 12:05:30 +00001953 linkSamplerBindings();
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001954
1955 return true;
1956}
1957
Olli Etuaho48fed632017-03-16 12:05:30 +00001958void Program::linkSamplerBindings()
Olli Etuaho6ca2b652017-02-19 18:05:10 +00001959{
1960 mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
1961 mState.mSamplerUniformRange.start = mState.mSamplerUniformRange.end;
1962 auto samplerIter = mState.mUniforms.rbegin();
1963 while (samplerIter != mState.mUniforms.rend() && samplerIter->isSampler())
1964 {
1965 --mState.mSamplerUniformRange.start;
1966 ++samplerIter;
1967 }
1968 // If uniform is a sampler type, insert it into the mSamplerBindings array.
1969 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
1970 samplerIndex < mState.mUniforms.size(); ++samplerIndex)
1971 {
1972 const auto &samplerUniform = mState.mUniforms[samplerIndex];
1973 GLenum textureType = SamplerTypeToTextureType(samplerUniform.type);
1974 mState.mSamplerBindings.emplace_back(
1975 SamplerBinding(textureType, samplerUniform.elementCount()));
1976 }
1977}
1978
Martin Radev4c4c8e72016-08-04 12:25:34 +03001979bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
1980 const std::string &uniformName,
1981 const sh::InterfaceBlockField &vertexUniform,
1982 const sh::InterfaceBlockField &fragmentUniform)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983{
Jamie Madillc4c744222015-11-04 09:39:47 -05001984 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1985 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001986 {
1987 return false;
1988 }
1989
1990 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1991 {
Jamie Madillf6113162015-05-07 11:49:21 -04001992 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001993 return false;
1994 }
1995
1996 return true;
1997}
1998
Jamie Madilleb979bf2016-11-15 12:28:46 -05001999// Assigns locations to all attributes from the bindings and program locations.
2000bool Program::linkAttributes(const ContextState &data, InfoLog &infoLog)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002001{
Jamie Madilleb979bf2016-11-15 12:28:46 -05002002 const auto *vertexShader = mState.getAttachedVertexShader();
2003
Geoff Lang7dd2e102014-11-10 15:19:26 -05002004 unsigned int usedLocations = 0;
Jamie Madill48ef11b2016-04-27 15:21:52 -04002005 mState.mAttributes = vertexShader->getActiveAttributes();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002006 GLuint maxAttribs = data.getCaps().maxVertexAttributes;
Jamie Madill3da79b72015-04-27 11:09:17 -04002007
2008 // TODO(jmadill): handle aliasing robustly
Jamie Madill48ef11b2016-04-27 15:21:52 -04002009 if (mState.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04002010 {
Jamie Madillf6113162015-05-07 11:49:21 -04002011 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04002012 return false;
2013 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002014
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002015 std::vector<sh::Attribute *> usedAttribMap(maxAttribs, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00002016
Jamie Madillc349ec02015-08-21 16:53:12 -04002017 // Link attributes that have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002018 for (sh::Attribute &attribute : mState.mAttributes)
Jamie Madillc349ec02015-08-21 16:53:12 -04002019 {
Jamie Madilleb979bf2016-11-15 12:28:46 -05002020 int bindingLocation = mAttributeBindings.getBinding(attribute.name);
Jamie Madillc349ec02015-08-21 16:53:12 -04002021 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04002022 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002023 attribute.location = bindingLocation;
2024 }
2025
2026 if (attribute.location != -1)
2027 {
2028 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04002029 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002030
Jamie Madill63805b42015-08-25 13:17:39 -04002031 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002032 {
Jamie Madillf6113162015-05-07 11:49:21 -04002033 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04002034 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002035
2036 return false;
2037 }
2038
Jamie Madill63805b42015-08-25 13:17:39 -04002039 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002040 {
Jamie Madill63805b42015-08-25 13:17:39 -04002041 const int regLocation = attribute.location + reg;
2042 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05002043
2044 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04002045 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04002046 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002047 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002048 // TODO(jmadill): fix aliasing on ES2
2049 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002050 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04002051 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04002052 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002053 return false;
2054 }
2055 }
Jamie Madillc349ec02015-08-21 16:53:12 -04002056 else
2057 {
Jamie Madill63805b42015-08-25 13:17:39 -04002058 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04002059 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002060
Jamie Madill63805b42015-08-25 13:17:39 -04002061 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002062 }
2063 }
2064 }
2065
2066 // Link attributes that don't have a binding location
Jamie Madill48ef11b2016-04-27 15:21:52 -04002067 for (sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002068 {
Jamie Madillc349ec02015-08-21 16:53:12 -04002069 // Not set by glBindAttribLocation or by location layout qualifier
2070 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002071 {
Jamie Madill63805b42015-08-25 13:17:39 -04002072 int regs = VariableRegisterCount(attribute.type);
2073 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002074
Jamie Madill63805b42015-08-25 13:17:39 -04002075 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002076 {
Jamie Madillf6113162015-05-07 11:49:21 -04002077 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04002078 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002079 }
2080
Jamie Madillc349ec02015-08-21 16:53:12 -04002081 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002082 }
2083 }
2084
Jamie Madill48ef11b2016-04-27 15:21:52 -04002085 for (const sh::Attribute &attribute : mState.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002086 {
Jamie Madill63805b42015-08-25 13:17:39 -04002087 ASSERT(attribute.location != -1);
2088 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04002089
Jamie Madill63805b42015-08-25 13:17:39 -04002090 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002091 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002092 mState.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002093 }
2094 }
2095
Geoff Lang7dd2e102014-11-10 15:19:26 -05002096 return true;
2097}
2098
Martin Radev4c4c8e72016-08-04 12:25:34 +03002099bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
2100 const std::vector<sh::InterfaceBlock> &intefaceBlocks,
2101 const std::string &errorMessage,
2102 InfoLog &infoLog) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002103{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002104 GLuint blockCount = 0;
2105 for (const sh::InterfaceBlock &block : intefaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002106 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002107 if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
Jamie Madille473dee2015-08-18 14:49:01 -04002108 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002109 if (++blockCount > maxUniformBlocks)
Jamie Madille473dee2015-08-18 14:49:01 -04002110 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002111 infoLog << errorMessage << maxUniformBlocks << ")";
Jamie Madille473dee2015-08-18 14:49:01 -04002112 return false;
2113 }
2114 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05002115 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002116 return true;
2117}
Jamie Madille473dee2015-08-18 14:49:01 -04002118
Martin Radev4c4c8e72016-08-04 12:25:34 +03002119bool Program::validateVertexAndFragmentInterfaceBlocks(
2120 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
2121 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
2122 InfoLog &infoLog) const
2123{
2124 // Check that interface blocks defined in the vertex and fragment shaders are identical
2125 typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
2126 UniformBlockMap linkedUniformBlocks;
2127
2128 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
2129 {
2130 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2131 }
2132
Jamie Madille473dee2015-08-18 14:49:01 -04002133 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002134 {
Jamie Madille473dee2015-08-18 14:49:01 -04002135 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002136 if (entry != linkedUniformBlocks.end())
2137 {
2138 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2139 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2140 {
2141 return false;
2142 }
2143 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002144 }
2145 return true;
2146}
Jamie Madille473dee2015-08-18 14:49:01 -04002147
Martin Radev4c4c8e72016-08-04 12:25:34 +03002148bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
2149{
2150 if (mState.mAttachedComputeShader)
2151 {
2152 const Shader &computeShader = *mState.mAttachedComputeShader;
2153 const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
2154
2155 if (!validateUniformBlocksCount(
2156 caps.maxComputeUniformBlocks, computeInterfaceBlocks,
2157 "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
2158 infoLog))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002159 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002160 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002161 }
Martin Radev4c4c8e72016-08-04 12:25:34 +03002162 return true;
2163 }
2164
2165 const Shader &vertexShader = *mState.mAttachedVertexShader;
2166 const Shader &fragmentShader = *mState.mAttachedFragmentShader;
2167
2168 const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2169 const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
2170
2171 if (!validateUniformBlocksCount(
2172 caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
2173 "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
2174 {
2175 return false;
2176 }
2177 if (!validateUniformBlocksCount(
2178 caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
2179 "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
2180 infoLog))
2181 {
2182
2183 return false;
2184 }
2185 if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
2186 infoLog))
2187 {
2188 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002189 }
Jamie Madille473dee2015-08-18 14:49:01 -04002190
Geoff Lang7dd2e102014-11-10 15:19:26 -05002191 return true;
2192}
2193
Jamie Madilla2c74982016-12-12 11:20:42 -05002194bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog,
Martin Radev4c4c8e72016-08-04 12:25:34 +03002195 const sh::InterfaceBlock &vertexInterfaceBlock,
2196 const sh::InterfaceBlock &fragmentInterfaceBlock) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002197{
2198 const char* blockName = vertexInterfaceBlock.name.c_str();
2199 // validate blocks for the same member types
2200 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
2201 {
Jamie Madillf6113162015-05-07 11:49:21 -04002202 infoLog << "Types for interface block '" << blockName
2203 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002204 return false;
2205 }
2206 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2207 {
Jamie Madillf6113162015-05-07 11:49:21 -04002208 infoLog << "Array sizes differ for interface block '" << blockName
2209 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002210 return false;
2211 }
2212 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2213 {
Jamie Madillf6113162015-05-07 11:49:21 -04002214 infoLog << "Layout qualifiers differ for interface block '" << blockName
2215 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002216 return false;
2217 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002218 const unsigned int numBlockMembers =
2219 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002220 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2221 {
2222 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2223 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
2224 if (vertexMember.name != fragmentMember.name)
2225 {
Jamie Madillf6113162015-05-07 11:49:21 -04002226 infoLog << "Name mismatch for field " << blockMemberIndex
2227 << " of interface block '" << blockName
2228 << "': (in vertex: '" << vertexMember.name
2229 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002230 return false;
2231 }
2232 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2233 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
2234 {
2235 return false;
2236 }
2237 }
2238 return true;
2239}
2240
2241bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
2242 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
2243{
2244 if (vertexVariable.type != fragmentVariable.type)
2245 {
Jamie Madillf6113162015-05-07 11:49:21 -04002246 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002247 return false;
2248 }
2249 if (vertexVariable.arraySize != fragmentVariable.arraySize)
2250 {
Jamie Madillf6113162015-05-07 11:49:21 -04002251 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002252 return false;
2253 }
2254 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
2255 {
Jamie Madillf6113162015-05-07 11:49:21 -04002256 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002257 return false;
2258 }
2259
2260 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
2261 {
Jamie Madillf6113162015-05-07 11:49:21 -04002262 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002263 return false;
2264 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002265 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05002266 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2267 {
2268 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
2269 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
2270
2271 if (vertexMember.name != fragmentMember.name)
2272 {
Jamie Madillf6113162015-05-07 11:49:21 -04002273 infoLog << "Name mismatch for field '" << memberIndex
2274 << "' of " << variableName
2275 << ": (in vertex: '" << vertexMember.name
2276 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002277 return false;
2278 }
2279
2280 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
2281 vertexMember.name + "'";
2282
2283 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
2284 {
2285 return false;
2286 }
2287 }
2288
2289 return true;
2290}
2291
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002292bool Program::linkValidateVaryings(InfoLog &infoLog,
2293 const std::string &varyingName,
2294 const sh::Varying &vertexVarying,
2295 const sh::Varying &fragmentVarying,
2296 int shaderVersion)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002297{
2298 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2299 {
2300 return false;
2301 }
2302
Jamie Madille9cc4692015-02-19 16:00:13 -05002303 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002304 {
Yuly Novikova1f6dc92016-06-15 23:27:04 -04002305 infoLog << "Interpolation types for " << varyingName
2306 << " differ between vertex and fragment shaders.";
2307 return false;
2308 }
2309
2310 if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant)
2311 {
2312 infoLog << "Invariance for " << varyingName
2313 << " differs between vertex and fragment shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002314 return false;
2315 }
2316
2317 return true;
2318}
2319
Yuly Novikov817232e2017-02-22 18:36:10 -05002320bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
2321{
2322 const Shader *vertexShader = mState.mAttachedVertexShader;
2323 const Shader *fragmentShader = mState.mAttachedFragmentShader;
2324 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
2325 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
2326 int shaderVersion = vertexShader->getShaderVersion();
2327
2328 if (shaderVersion != 100)
2329 {
2330 // Only ESSL 1.0 has restrictions on matching input and output invariance
2331 return true;
2332 }
2333
2334 bool glPositionIsInvariant = false;
2335 bool glPointSizeIsInvariant = false;
2336 bool glFragCoordIsInvariant = false;
2337 bool glPointCoordIsInvariant = false;
2338
2339 for (const sh::Varying &varying : vertexVaryings)
2340 {
2341 if (!varying.isBuiltIn())
2342 {
2343 continue;
2344 }
2345 if (varying.name.compare("gl_Position") == 0)
2346 {
2347 glPositionIsInvariant = varying.isInvariant;
2348 }
2349 else if (varying.name.compare("gl_PointSize") == 0)
2350 {
2351 glPointSizeIsInvariant = varying.isInvariant;
2352 }
2353 }
2354
2355 for (const sh::Varying &varying : fragmentVaryings)
2356 {
2357 if (!varying.isBuiltIn())
2358 {
2359 continue;
2360 }
2361 if (varying.name.compare("gl_FragCoord") == 0)
2362 {
2363 glFragCoordIsInvariant = varying.isInvariant;
2364 }
2365 else if (varying.name.compare("gl_PointCoord") == 0)
2366 {
2367 glPointCoordIsInvariant = varying.isInvariant;
2368 }
2369 }
2370
2371 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2372 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2373 // Not requiring invariance to match is supported by:
2374 // dEQP, WebGL CTS, Nexus 5X GLES
2375 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2376 {
2377 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2378 "declared invariant.";
2379 return false;
2380 }
2381 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2382 {
2383 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2384 "declared invariant.";
2385 return false;
2386 }
2387
2388 return true;
2389}
2390
Jamie Madillccdf74b2015-08-18 10:46:12 -04002391bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
Jamie Madill192745a2016-12-22 15:58:21 -05002392 const Program::MergedVaryings &varyings,
Jamie Madillccdf74b2015-08-18 10:46:12 -04002393 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002394{
2395 size_t totalComponents = 0;
2396
Jamie Madillccdf74b2015-08-18 10:46:12 -04002397 std::set<std::string> uniqueNames;
2398
Jamie Madill48ef11b2016-04-27 15:21:52 -04002399 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002400 {
2401 bool found = false;
Jamie Madill192745a2016-12-22 15:58:21 -05002402 for (const auto &ref : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002403 {
Jamie Madill192745a2016-12-22 15:58:21 -05002404 const sh::Varying *varying = ref.second.get();
2405
Jamie Madillccdf74b2015-08-18 10:46:12 -04002406 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002407 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002408 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002409 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002410 infoLog << "Two transform feedback varyings specify the same output variable ("
2411 << tfVaryingName << ").";
2412 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002413 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002414 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002415
Geoff Lang1a683462015-09-29 15:09:59 -04002416 if (varying->isArray())
2417 {
2418 infoLog << "Capture of arrays is undefined and not supported.";
2419 return false;
2420 }
2421
Jamie Madillccdf74b2015-08-18 10:46:12 -04002422 // TODO(jmadill): Investigate implementation limits on D3D11
Jamie Madilla2c74982016-12-12 11:20:42 -05002423 size_t componentCount = VariableComponentCount(varying->type);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002424 if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002425 componentCount > caps.maxTransformFeedbackSeparateComponents)
2426 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002427 infoLog << "Transform feedback varying's " << varying->name << " components ("
2428 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002429 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002430 return false;
2431 }
2432
2433 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002434 found = true;
2435 break;
2436 }
2437 }
2438
Jamie Madill89bb70e2015-08-31 14:18:39 -04002439 if (tfVaryingName.find('[') != std::string::npos)
2440 {
Geoff Lang1a683462015-09-29 15:09:59 -04002441 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002442 return false;
2443 }
2444
Geoff Lang7dd2e102014-11-10 15:19:26 -05002445 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2446 ASSERT(found);
2447 }
2448
Jamie Madill48ef11b2016-04-27 15:21:52 -04002449 if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002450 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002451 {
Jamie Madillf6113162015-05-07 11:49:21 -04002452 infoLog << "Transform feedback varying total components (" << totalComponents
2453 << ") exceed the maximum interleaved components ("
2454 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002455 return false;
2456 }
2457
2458 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002459}
2460
Jamie Madill192745a2016-12-22 15:58:21 -05002461void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002462{
2463 // Gather the linked varyings that are used for transform feedback, they should all exist.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002464 mState.mTransformFeedbackVaryingVars.clear();
2465 for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002466 {
Jamie Madill192745a2016-12-22 15:58:21 -05002467 for (const auto &ref : varyings)
Jamie Madillccdf74b2015-08-18 10:46:12 -04002468 {
Jamie Madill192745a2016-12-22 15:58:21 -05002469 const sh::Varying *varying = ref.second.get();
Jamie Madillccdf74b2015-08-18 10:46:12 -04002470 if (tfVaryingName == varying->name)
2471 {
Jamie Madill48ef11b2016-04-27 15:21:52 -04002472 mState.mTransformFeedbackVaryingVars.push_back(*varying);
Jamie Madillccdf74b2015-08-18 10:46:12 -04002473 break;
2474 }
2475 }
2476 }
2477}
2478
Jamie Madill192745a2016-12-22 15:58:21 -05002479Program::MergedVaryings Program::getMergedVaryings() const
Jamie Madillccdf74b2015-08-18 10:46:12 -04002480{
Jamie Madill192745a2016-12-22 15:58:21 -05002481 MergedVaryings merged;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002482
Jamie Madill48ef11b2016-04-27 15:21:52 -04002483 for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002484 {
Jamie Madill192745a2016-12-22 15:58:21 -05002485 merged[varying.name].vertex = &varying;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002486 }
2487
Jamie Madill48ef11b2016-04-27 15:21:52 -04002488 for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
Jamie Madillccdf74b2015-08-18 10:46:12 -04002489 {
Jamie Madill192745a2016-12-22 15:58:21 -05002490 merged[varying.name].fragment = &varying;
2491 }
2492
2493 return merged;
2494}
2495
2496std::vector<PackedVarying> Program::getPackedVaryings(
2497 const Program::MergedVaryings &mergedVaryings) const
2498{
2499 const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
2500 std::vector<PackedVarying> packedVaryings;
2501
2502 for (const auto &ref : mergedVaryings)
2503 {
2504 const sh::Varying *input = ref.second.vertex;
2505 const sh::Varying *output = ref.second.fragment;
2506
2507 // Only pack varyings that have a matched input or output, plus special builtins.
2508 if ((input && output) || (output && output->isBuiltIn()))
Jamie Madillccdf74b2015-08-18 10:46:12 -04002509 {
Jamie Madill192745a2016-12-22 15:58:21 -05002510 // Will get the vertex shader interpolation by default.
2511 auto interpolation = ref.second.get()->interpolation;
2512
2513 // Interpolation qualifiers must match.
2514 if (output->isStruct())
2515 {
2516 ASSERT(!output->isArray());
2517 for (const auto &field : output->fields)
2518 {
2519 ASSERT(!field.isStruct() && !field.isArray());
2520 packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
2521 }
2522 }
2523 else
2524 {
2525 packedVaryings.push_back(PackedVarying(*output, interpolation));
2526 }
2527 continue;
2528 }
2529
2530 // Keep Transform FB varyings in the merged list always.
2531 if (!input)
2532 {
2533 continue;
2534 }
2535
2536 for (const std::string &tfVarying : tfVaryings)
2537 {
2538 if (tfVarying == input->name)
2539 {
2540 // Transform feedback for varying structs is underspecified.
2541 // See Khronos bug 9856.
2542 // TODO(jmadill): Figure out how to be spec-compliant here.
2543 if (!input->isStruct())
2544 {
2545 packedVaryings.push_back(PackedVarying(*input, input->interpolation));
2546 packedVaryings.back().vertexOnly = true;
2547 }
2548 break;
2549 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002550 }
2551 }
2552
Jamie Madill192745a2016-12-22 15:58:21 -05002553 std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
2554
2555 return packedVaryings;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002556}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002557
2558void Program::linkOutputVariables()
2559{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002560 const Shader *fragmentShader = mState.mAttachedFragmentShader;
Jamie Madill80a6fc02015-08-21 16:53:16 -04002561 ASSERT(fragmentShader != nullptr);
2562
2563 // Skip this step for GLES2 shaders.
2564 if (fragmentShader->getShaderVersion() == 100)
2565 return;
2566
jchen1015015f72017-03-16 13:54:21 +08002567 mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002568 // TODO(jmadill): any caps validation here?
2569
jchen1015015f72017-03-16 13:54:21 +08002570 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002571 outputVariableIndex++)
2572 {
jchen1015015f72017-03-16 13:54:21 +08002573 const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002574
2575 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2576 if (outputVariable.isBuiltIn())
2577 continue;
2578
2579 // Since multiple output locations must be specified, use 0 for non-specified locations.
2580 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2581
Jamie Madill80a6fc02015-08-21 16:53:16 -04002582 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2583 elementIndex++)
2584 {
2585 const int location = baseLocation + elementIndex;
jchen1015015f72017-03-16 13:54:21 +08002586 ASSERT(mState.mOutputLocations.count(location) == 0);
Jamie Madill80a6fc02015-08-21 16:53:16 -04002587 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
jchen1015015f72017-03-16 13:54:21 +08002588 mState.mOutputLocations[location] =
Jamie Madill80a6fc02015-08-21 16:53:16 -04002589 VariableLocation(outputVariable.name, element, outputVariableIndex);
2590 }
2591 }
2592}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002593
Olli Etuaho48fed632017-03-16 12:05:30 +00002594void Program::setUniformValuesFromBindingQualifiers()
2595{
2596 for (unsigned int samplerIndex = mState.mSamplerUniformRange.start;
2597 samplerIndex < mState.mSamplerUniformRange.end; ++samplerIndex)
2598 {
2599 const auto &samplerUniform = mState.mUniforms[samplerIndex];
2600 if (samplerUniform.binding != -1)
2601 {
2602 GLint location = mState.getUniformLocation(samplerUniform.name);
2603 ASSERT(location != -1);
2604 std::vector<GLint> boundTextureUnits;
2605 for (unsigned int elementIndex = 0; elementIndex < samplerUniform.elementCount();
2606 ++elementIndex)
2607 {
2608 boundTextureUnits.push_back(samplerUniform.binding + elementIndex);
2609 }
2610 setUniform1iv(location, static_cast<GLsizei>(boundTextureUnits.size()),
2611 boundTextureUnits.data());
2612 }
2613 }
2614}
2615
Jamie Madill62d31cb2015-09-11 13:25:51 -04002616void Program::gatherInterfaceBlockInfo()
2617{
Martin Radev4c4c8e72016-08-04 12:25:34 +03002618 ASSERT(mState.mUniformBlocks.empty());
2619
2620 if (mState.mAttachedComputeShader)
2621 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002622 const Shader *computeShader = mState.getAttachedComputeShader();
Martin Radev4c4c8e72016-08-04 12:25:34 +03002623
2624 for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
2625 {
2626
2627 // Only 'packed' blocks are allowed to be considered inactive.
2628 if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
2629 continue;
2630
Jamie Madilla2c74982016-12-12 11:20:42 -05002631 for (UniformBlock &block : mState.mUniformBlocks)
Martin Radev4c4c8e72016-08-04 12:25:34 +03002632 {
2633 if (block.name == computeBlock.name)
2634 {
2635 block.computeStaticUse = computeBlock.staticUse;
2636 }
2637 }
2638
2639 defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
2640 }
2641 return;
2642 }
2643
Jamie Madill62d31cb2015-09-11 13:25:51 -04002644 std::set<std::string> visitedList;
2645
Jamie Madilla2c74982016-12-12 11:20:42 -05002646 const Shader *vertexShader = mState.getAttachedVertexShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002647
Jamie Madill62d31cb2015-09-11 13:25:51 -04002648 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2649 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002650 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002651 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2652 continue;
2653
2654 if (visitedList.count(vertexBlock.name) > 0)
2655 continue;
2656
2657 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2658 visitedList.insert(vertexBlock.name);
2659 }
2660
Jamie Madilla2c74982016-12-12 11:20:42 -05002661 const Shader *fragmentShader = mState.getAttachedFragmentShader();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002662
2663 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2664 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002665 // Only 'packed' blocks are allowed to be considered inactive.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002666 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2667 continue;
2668
2669 if (visitedList.count(fragmentBlock.name) > 0)
2670 {
Jamie Madilla2c74982016-12-12 11:20:42 -05002671 for (UniformBlock &block : mState.mUniformBlocks)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002672 {
2673 if (block.name == fragmentBlock.name)
2674 {
2675 block.fragmentStaticUse = fragmentBlock.staticUse;
2676 }
2677 }
2678
2679 continue;
2680 }
2681
2682 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2683 visitedList.insert(fragmentBlock.name);
2684 }
2685}
2686
Jamie Madill4a3c2342015-10-08 12:58:45 -04002687template <typename VarT>
2688void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2689 const std::string &prefix,
2690 int blockIndex)
2691{
2692 for (const VarT &field : fields)
2693 {
2694 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2695
2696 if (field.isStruct())
2697 {
2698 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2699 {
2700 const std::string uniformElementName =
2701 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2702 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2703 }
2704 }
2705 else
2706 {
2707 // If getBlockMemberInfo returns false, the uniform is optimized out.
2708 sh::BlockMemberInfo memberInfo;
2709 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2710 {
2711 continue;
2712 }
2713
Olli Etuaho6ca2b652017-02-19 18:05:10 +00002714 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
Jamie Madill4a3c2342015-10-08 12:58:45 -04002715 blockIndex, memberInfo);
2716
2717 // Since block uniforms have no location, we don't need to store them in the uniform
2718 // locations list.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002719 mState.mUniforms.push_back(newUniform);
Jamie Madill4a3c2342015-10-08 12:58:45 -04002720 }
2721 }
2722}
2723
Jamie Madill62d31cb2015-09-11 13:25:51 -04002724void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2725{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002726 int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
Jamie Madill4a3c2342015-10-08 12:58:45 -04002727 size_t blockSize = 0;
2728
2729 // Don't define this block at all if it's not active in the implementation.
Qin Jiajia0350a642016-11-01 17:01:51 +08002730 std::stringstream blockNameStr;
2731 blockNameStr << interfaceBlock.name;
2732 if (interfaceBlock.arraySize > 0)
2733 {
2734 blockNameStr << "[0]";
2735 }
2736 if (!mProgram->getUniformBlockSize(blockNameStr.str(), &blockSize))
Jamie Madill4a3c2342015-10-08 12:58:45 -04002737 {
2738 return;
2739 }
2740
2741 // Track the first and last uniform index to determine the range of active uniforms in the
2742 // block.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002743 size_t firstBlockUniformIndex = mState.mUniforms.size();
Jamie Madill39046162016-02-08 15:05:17 -05002744 defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002745 size_t lastBlockUniformIndex = mState.mUniforms.size();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002746
2747 std::vector<unsigned int> blockUniformIndexes;
2748 for (size_t blockUniformIndex = firstBlockUniformIndex;
2749 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2750 {
2751 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2752 }
2753
2754 if (interfaceBlock.arraySize > 0)
2755 {
2756 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2757 {
2758 UniformBlock block(interfaceBlock.name, true, arrayElement);
2759 block.memberUniformIndexes = blockUniformIndexes;
2760
Martin Radev4c4c8e72016-08-04 12:25:34 +03002761 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002762 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002763 case GL_VERTEX_SHADER:
2764 {
2765 block.vertexStaticUse = interfaceBlock.staticUse;
2766 break;
2767 }
2768 case GL_FRAGMENT_SHADER:
2769 {
2770 block.fragmentStaticUse = interfaceBlock.staticUse;
2771 break;
2772 }
2773 case GL_COMPUTE_SHADER:
2774 {
2775 block.computeStaticUse = interfaceBlock.staticUse;
2776 break;
2777 }
2778 default:
2779 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002780 }
2781
Qin Jiajia0350a642016-11-01 17:01:51 +08002782 // Since all block elements in an array share the same active uniforms, they will all be
2783 // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
2784 // here we will add every block element in the array.
2785 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002786 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002787 }
2788 }
2789 else
2790 {
2791 UniformBlock block(interfaceBlock.name, false, 0);
2792 block.memberUniformIndexes = blockUniformIndexes;
2793
Martin Radev4c4c8e72016-08-04 12:25:34 +03002794 switch (shaderType)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002795 {
Martin Radev4c4c8e72016-08-04 12:25:34 +03002796 case GL_VERTEX_SHADER:
2797 {
2798 block.vertexStaticUse = interfaceBlock.staticUse;
2799 break;
2800 }
2801 case GL_FRAGMENT_SHADER:
2802 {
2803 block.fragmentStaticUse = interfaceBlock.staticUse;
2804 break;
2805 }
2806 case GL_COMPUTE_SHADER:
2807 {
2808 block.computeStaticUse = interfaceBlock.staticUse;
2809 break;
2810 }
2811 default:
2812 UNREACHABLE();
Jamie Madill62d31cb2015-09-11 13:25:51 -04002813 }
2814
Jamie Madill4a3c2342015-10-08 12:58:45 -04002815 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill48ef11b2016-04-27 15:21:52 -04002816 mState.mUniformBlocks.push_back(block);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002817 }
2818}
2819
Jamie Madille7d84322017-01-10 18:21:59 -05002820template <>
2821void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2822 const uint8_t *destPointer,
2823 GLsizei clampedCount,
2824 const GLint *v)
2825{
2826 // Invalidate the validation cache only if we modify the sampler data.
2827 if (mState.isSamplerUniformIndex(locationInfo.index) &&
2828 memcmp(destPointer, v, sizeof(GLint) * clampedCount) != 0)
2829 {
2830 GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
2831 std::vector<GLuint> *boundTextureUnits =
2832 &mState.mSamplerBindings[samplerIndex].boundTextureUnits;
2833
2834 std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
2835 mCachedValidateSamplersResult.reset();
2836 }
2837}
2838
2839template <typename T>
2840void Program::updateSamplerUniform(const VariableLocation &locationInfo,
2841 const uint8_t *destPointer,
2842 GLsizei clampedCount,
2843 const T *v)
2844{
2845}
2846
Jamie Madill62d31cb2015-09-11 13:25:51 -04002847template <typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002848GLsizei Program::setUniformInternal(GLint location, GLsizei countIn, int vectorSize, const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002849{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002850 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2851 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002852 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2853
Corentin Wallez15ac5342016-11-03 17:06:39 -04002854 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2855 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2856 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002857 GLsizei maxElementCount =
2858 static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents());
2859
2860 GLsizei count = countIn;
2861 GLsizei clampedCount = count * vectorSize;
2862 if (clampedCount > maxElementCount)
2863 {
2864 clampedCount = maxElementCount;
2865 count = maxElementCount / vectorSize;
2866 }
Corentin Wallez15ac5342016-11-03 17:06:39 -04002867
Jamie Madill62d31cb2015-09-11 13:25:51 -04002868 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2869 {
2870 // Do a cast conversion for boolean types. From the spec:
2871 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2872 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002873 for (GLsizei component = 0; component < clampedCount; ++component)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002874 {
2875 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2876 }
2877 }
2878 else
2879 {
Jamie Madille7d84322017-01-10 18:21:59 -05002880 updateSamplerUniform(locationInfo, destPointer, clampedCount, v);
Corentin Wallez15ac5342016-11-03 17:06:39 -04002881 memcpy(destPointer, v, sizeof(T) * clampedCount);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002882 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002883
2884 return count;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002885}
2886
2887template <size_t cols, size_t rows, typename T>
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002888GLsizei Program::setMatrixUniformInternal(GLint location,
2889 GLsizei count,
2890 GLboolean transpose,
2891 const T *v)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002892{
2893 if (!transpose)
2894 {
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002895 return setUniformInternal(location, count, cols * rows, v);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002896 }
2897
2898 // Perform a transposing copy.
Jamie Madill48ef11b2016-04-27 15:21:52 -04002899 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2900 LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002901 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
Corentin Wallez15ac5342016-11-03 17:06:39 -04002902
2903 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2904 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2905 unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
2906 GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
2907
2908 for (GLsizei element = 0; element < clampedCount; ++element)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002909 {
2910 size_t elementOffset = element * rows * cols;
2911
2912 for (size_t row = 0; row < rows; ++row)
2913 {
2914 for (size_t col = 0; col < cols; ++col)
2915 {
2916 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2917 }
2918 }
2919 }
Corentin Wallez8b7d8142016-11-15 13:40:37 -05002920
2921 return clampedCount;
Jamie Madill62d31cb2015-09-11 13:25:51 -04002922}
2923
2924template <typename DestT>
2925void Program::getUniformInternal(GLint location, DestT *dataOut) const
2926{
Jamie Madill48ef11b2016-04-27 15:21:52 -04002927 const VariableLocation &locationInfo = mState.mUniformLocations[location];
2928 const LinkedUniform &uniform = mState.mUniforms[locationInfo.index];
Jamie Madill62d31cb2015-09-11 13:25:51 -04002929
2930 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2931
2932 GLenum componentType = VariableComponentType(uniform.type);
2933 if (componentType == GLTypeToGLenum<DestT>::value)
2934 {
2935 memcpy(dataOut, srcPointer, uniform.getElementSize());
2936 return;
2937 }
2938
Corentin Wallez6596c462016-03-17 17:26:58 -04002939 int components = VariableComponentCount(uniform.type);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002940
2941 switch (componentType)
2942 {
2943 case GL_INT:
2944 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2945 break;
2946 case GL_UNSIGNED_INT:
2947 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2948 break;
2949 case GL_BOOL:
2950 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2951 break;
2952 case GL_FLOAT:
2953 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2954 break;
2955 default:
2956 UNREACHABLE();
2957 }
2958}
Jamie Madilla4595b82017-01-11 17:36:34 -05002959
2960bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const
2961{
2962 // Must be called after samplers are validated.
2963 ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value());
2964
2965 for (const auto &binding : mState.mSamplerBindings)
2966 {
2967 GLenum textureType = binding.textureType;
2968 for (const auto &unit : binding.boundTextureUnits)
2969 {
2970 GLenum programTextureID = state.getSamplerTextureId(unit, textureType);
2971 if (programTextureID == textureID)
2972 {
2973 // TODO(jmadill): Check for appropriate overlap.
2974 return true;
2975 }
2976 }
2977 }
2978
2979 return false;
2980}
2981
Jamie Madilla2c74982016-12-12 11:20:42 -05002982} // namespace gl