blob: e21c8f401e07555100922c69f1f13cb47a984db7 [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"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Data.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"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/renderer/Renderer.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill62d31cb2015-09-11 13:25:51 -040025#include "libANGLE/queryconversions.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050026
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027namespace gl
28{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000029
Geoff Lang7dd2e102014-11-10 15:19:26 -050030namespace
31{
32
Jamie Madill62d31cb2015-09-11 13:25:51 -040033void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
34{
35 stream->writeInt(var.type);
36 stream->writeInt(var.precision);
37 stream->writeString(var.name);
38 stream->writeString(var.mappedName);
39 stream->writeInt(var.arraySize);
40 stream->writeInt(var.staticUse);
41 stream->writeString(var.structName);
42 ASSERT(var.fields.empty());
Geoff Lang7dd2e102014-11-10 15:19:26 -050043}
44
Jamie Madill62d31cb2015-09-11 13:25:51 -040045void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
46{
47 var->type = stream->readInt<GLenum>();
48 var->precision = stream->readInt<GLenum>();
49 var->name = stream->readString();
50 var->mappedName = stream->readString();
51 var->arraySize = stream->readInt<unsigned int>();
52 var->staticUse = stream->readBool();
53 var->structName = stream->readString();
54}
55
Jamie Madill62d31cb2015-09-11 13:25:51 -040056// This simplified cast function doesn't need to worry about advanced concepts like
57// depth range values, or casting to bool.
58template <typename DestT, typename SrcT>
59DestT UniformStateQueryCast(SrcT value);
60
61// From-Float-To-Integer Casts
62template <>
63GLint UniformStateQueryCast(GLfloat value)
64{
65 return clampCast<GLint>(roundf(value));
66}
67
68template <>
69GLuint UniformStateQueryCast(GLfloat value)
70{
71 return clampCast<GLuint>(roundf(value));
72}
73
74// From-Integer-to-Integer Casts
75template <>
76GLint UniformStateQueryCast(GLuint value)
77{
78 return clampCast<GLint>(value);
79}
80
81template <>
82GLuint UniformStateQueryCast(GLint value)
83{
84 return clampCast<GLuint>(value);
85}
86
87// From-Boolean-to-Anything Casts
88template <>
89GLfloat UniformStateQueryCast(GLboolean value)
90{
91 return (value == GL_TRUE ? 1.0f : 0.0f);
92}
93
94template <>
95GLint UniformStateQueryCast(GLboolean value)
96{
97 return (value == GL_TRUE ? 1 : 0);
98}
99
100template <>
101GLuint UniformStateQueryCast(GLboolean value)
102{
103 return (value == GL_TRUE ? 1u : 0u);
104}
105
106// Default to static_cast
107template <typename DestT, typename SrcT>
108DestT UniformStateQueryCast(SrcT value)
109{
110 return static_cast<DestT>(value);
111}
112
113template <typename SrcT, typename DestT>
114void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
115{
116 for (int comp = 0; comp < components; ++comp)
117 {
118 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
119 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
120 size_t offset = comp * 4;
121 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
122 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
123 }
124}
125
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400126bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
127{
128 for (const LinkedUniform &uniform : list)
129 {
130 if (uniform.name == name)
131 return true;
132 }
133
134 return false;
135}
136
Jamie Madill62d31cb2015-09-11 13:25:51 -0400137} // anonymous namespace
138
Jamie Madill4a3c2342015-10-08 12:58:45 -0400139const char *const g_fakepath = "C:\\fakepath";
140
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000141AttributeBindings::AttributeBindings()
142{
143}
144
145AttributeBindings::~AttributeBindings()
146{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000147}
148
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400149InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000150{
151}
152
153InfoLog::~InfoLog()
154{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000155}
156
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400157size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000158{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400159 const std::string &logString = mStream.str();
160 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000161}
162
Geoff Lange1a27752015-10-05 13:16:04 -0400163void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000164{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400165 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000166
167 if (bufSize > 0)
168 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400169 const std::string str(mStream.str());
170
171 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000172 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400173 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
174 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000175 }
176
177 infoLog[index] = '\0';
178 }
179
180 if (length)
181 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000183 }
184}
185
186// append a santized message to the program info log.
187// The D3D compiler includes a fake file path in some of the warning or error
188// messages, so lets remove all occurrences of this fake file path from the log.
189void InfoLog::appendSanitized(const char *message)
190{
191 std::string msg(message);
192
193 size_t found;
194 do
195 {
196 found = msg.find(g_fakepath);
197 if (found != std::string::npos)
198 {
199 msg.erase(found, strlen(g_fakepath));
200 }
201 }
202 while (found != std::string::npos);
203
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400204 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000205}
206
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000207void InfoLog::reset()
208{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000209}
210
Geoff Lang7dd2e102014-11-10 15:19:26 -0500211VariableLocation::VariableLocation()
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400212 : name(),
213 element(0),
214 index(0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000215{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500216}
217
218VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400219 : name(name),
220 element(element),
221 index(index)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500222{
223}
224
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400225Program::Data::Data()
Geoff Lang70d0f492015-12-10 17:45:46 -0500226 : mLabel(),
227 mAttachedFragmentShader(nullptr),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400228 mAttachedVertexShader(nullptr),
Geoff Langc5629752015-12-07 16:29:04 -0500229 mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
230 mBinaryRetrieveableHint(false)
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400231{
232}
233
234Program::Data::~Data()
235{
236 if (mAttachedVertexShader != nullptr)
237 {
238 mAttachedVertexShader->release();
239 }
240
241 if (mAttachedFragmentShader != nullptr)
242 {
243 mAttachedFragmentShader->release();
244 }
245}
246
Geoff Lang70d0f492015-12-10 17:45:46 -0500247const std::string &Program::Data::getLabel()
248{
249 return mLabel;
250}
251
Jamie Madill62d31cb2015-09-11 13:25:51 -0400252const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const
253{
254 for (const LinkedUniform &linkedUniform : mUniforms)
255 {
256 if (linkedUniform.name == name)
257 {
258 return &linkedUniform;
259 }
260 }
261
262 return nullptr;
263}
264
265GLint Program::Data::getUniformLocation(const std::string &name) const
266{
267 size_t subscript = GL_INVALID_INDEX;
268 std::string baseName = gl::ParseUniformName(name, &subscript);
269
270 for (size_t location = 0; location < mUniformLocations.size(); ++location)
271 {
272 const VariableLocation &uniformLocation = mUniformLocations[location];
273 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
274
275 if (uniform.name == baseName)
276 {
277 if ((uniform.isArray() && uniformLocation.element == subscript) ||
278 (subscript == GL_INVALID_INDEX))
279 {
280 return static_cast<GLint>(location);
281 }
282 }
283 }
284
285 return -1;
286}
287
288GLuint Program::Data::getUniformIndex(const std::string &name) const
289{
290 size_t subscript = GL_INVALID_INDEX;
291 std::string baseName = gl::ParseUniformName(name, &subscript);
292
293 // The app is not allowed to specify array indices other than 0 for arrays of basic types
294 if (subscript != 0 && subscript != GL_INVALID_INDEX)
295 {
296 return GL_INVALID_INDEX;
297 }
298
299 for (size_t index = 0; index < mUniforms.size(); index++)
300 {
301 const LinkedUniform &uniform = mUniforms[index];
302 if (uniform.name == baseName)
303 {
304 if (uniform.isArray() || subscript == GL_INVALID_INDEX)
305 {
306 return static_cast<GLuint>(index);
307 }
308 }
309 }
310
311 return GL_INVALID_INDEX;
312}
313
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400314Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
315 : mProgram(factory->createProgram(mData)),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400316 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500317 mLinked(false),
318 mDeleteStatus(false),
319 mRefCount(0),
320 mResourceManager(manager),
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400321 mHandle(handle),
322 mSamplerUniformRange(0, 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500323{
324 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000325
326 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500327 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328}
329
330Program::~Program()
331{
332 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000333
Geoff Lang7dd2e102014-11-10 15:19:26 -0500334 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335}
336
Geoff Lang70d0f492015-12-10 17:45:46 -0500337void Program::setLabel(const std::string &label)
338{
339 mData.mLabel = label;
340}
341
342const std::string &Program::getLabel() const
343{
344 return mData.mLabel;
345}
346
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347bool Program::attachShader(Shader *shader)
348{
349 if (shader->getType() == GL_VERTEX_SHADER)
350 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400351 if (mData.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 {
353 return false;
354 }
355
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400356 mData.mAttachedVertexShader = shader;
357 mData.mAttachedVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358 }
359 else if (shader->getType() == GL_FRAGMENT_SHADER)
360 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400361 if (mData.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 {
363 return false;
364 }
365
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400366 mData.mAttachedFragmentShader = shader;
367 mData.mAttachedFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 }
369 else UNREACHABLE();
370
371 return true;
372}
373
374bool Program::detachShader(Shader *shader)
375{
376 if (shader->getType() == GL_VERTEX_SHADER)
377 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400378 if (mData.mAttachedVertexShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379 {
380 return false;
381 }
382
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400383 shader->release();
384 mData.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 }
386 else if (shader->getType() == GL_FRAGMENT_SHADER)
387 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400388 if (mData.mAttachedFragmentShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000389 {
390 return false;
391 }
392
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400393 shader->release();
394 mData.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000395 }
396 else UNREACHABLE();
397
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398 return true;
399}
400
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000401int Program::getAttachedShadersCount() const
402{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400403 return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000404}
405
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000406void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
407{
408 if (index < MAX_VERTEX_ATTRIBS)
409 {
410 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
411 {
412 mAttributeBinding[i].erase(name);
413 }
414
415 mAttributeBinding[index].insert(name);
416 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000417}
418
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419void Program::bindAttributeLocation(GLuint index, const char *name)
420{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000421 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422}
423
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
425// compiling them into binaries, determining the attribute mappings, and collecting
426// a list of uniforms
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400427Error Program::link(const gl::Data &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000428{
429 unlink(false);
430
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000431 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000432 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000433
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400434 if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500435 {
436 return Error(GL_NO_ERROR);
437 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400438 ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500439
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400440 if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500441 {
442 return Error(GL_NO_ERROR);
443 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400444 ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500445
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400446 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500447 {
448 return Error(GL_NO_ERROR);
449 }
450
Jamie Madillada9ecc2015-08-17 12:53:37 -0400451 if (!linkVaryings(mInfoLog, mData.mAttachedVertexShader, mData.mAttachedFragmentShader))
452 {
453 return Error(GL_NO_ERROR);
454 }
455
Jamie Madillea918db2015-08-18 14:48:59 -0400456 if (!linkUniforms(mInfoLog, *data.caps))
457 {
458 return Error(GL_NO_ERROR);
459 }
460
Jamie Madille473dee2015-08-18 14:49:01 -0400461 if (!linkUniformBlocks(mInfoLog, *data.caps))
462 {
463 return Error(GL_NO_ERROR);
464 }
465
Jamie Madillccdf74b2015-08-18 10:46:12 -0400466 const auto &mergedVaryings = getMergedVaryings();
467
468 if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps))
469 {
470 return Error(GL_NO_ERROR);
471 }
472
Jamie Madill80a6fc02015-08-21 16:53:16 -0400473 linkOutputVariables();
474
Jamie Madillf5f4ad22015-09-02 18:32:38 +0000475 rx::LinkResult result = mProgram->link(data, mInfoLog);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500476 if (result.error.isError() || !result.linkSuccess)
477 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500478 return result.error;
479 }
480
Jamie Madillccdf74b2015-08-18 10:46:12 -0400481 gatherTransformFeedbackVaryings(mergedVaryings);
Jamie Madill4a3c2342015-10-08 12:58:45 -0400482 gatherInterfaceBlockInfo();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400483
Geoff Lang7dd2e102014-11-10 15:19:26 -0500484 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400485 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000486}
487
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000488int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000489{
490 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
491 {
492 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
493 {
494 return location;
495 }
496 }
497
498 return -1;
499}
500
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000501// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502void Program::unlink(bool destroy)
503{
504 if (destroy) // Object being destructed
505 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400506 if (mData.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400508 mData.mAttachedFragmentShader->release();
509 mData.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000510 }
511
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400512 if (mData.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400514 mData.mAttachedVertexShader->release();
515 mData.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000516 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517 }
518
Jamie Madillc349ec02015-08-21 16:53:12 -0400519 mData.mAttributes.clear();
Jamie Madill63805b42015-08-25 13:17:39 -0400520 mData.mActiveAttribLocationsMask.reset();
Jamie Madillccdf74b2015-08-18 10:46:12 -0400521 mData.mTransformFeedbackVaryingVars.clear();
Jamie Madill62d31cb2015-09-11 13:25:51 -0400522 mData.mUniforms.clear();
523 mData.mUniformLocations.clear();
524 mData.mUniformBlocks.clear();
Jamie Madill80a6fc02015-08-21 16:53:16 -0400525 mData.mOutputVariables.clear();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500526
Geoff Lang7dd2e102014-11-10 15:19:26 -0500527 mValidated = false;
528
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000529 mLinked = false;
530}
531
Geoff Lange1a27752015-10-05 13:16:04 -0400532bool Program::isLinked() const
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000533{
534 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000535}
536
Geoff Lang7dd2e102014-11-10 15:19:26 -0500537Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000538{
539 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000540
Geoff Lang7dd2e102014-11-10 15:19:26 -0500541#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
542 return Error(GL_NO_ERROR);
543#else
Geoff Langc46cc2f2015-10-01 17:16:20 -0400544 ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
545 if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000546 {
Jamie Madillf6113162015-05-07 11:49:21 -0400547 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500548 return Error(GL_NO_ERROR);
549 }
550
Geoff Langc46cc2f2015-10-01 17:16:20 -0400551 BinaryInputStream stream(binary, length);
552
Geoff Lang7dd2e102014-11-10 15:19:26 -0500553 int majorVersion = stream.readInt<int>();
554 int minorVersion = stream.readInt<int>();
555 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
556 {
Jamie Madillf6113162015-05-07 11:49:21 -0400557 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500558 return Error(GL_NO_ERROR);
559 }
560
561 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
562 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
563 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
564 {
Jamie Madillf6113162015-05-07 11:49:21 -0400565 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500566 return Error(GL_NO_ERROR);
567 }
568
Jamie Madill63805b42015-08-25 13:17:39 -0400569 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
570 "Too many vertex attribs for mask");
571 mData.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500572
Jamie Madill3da79b72015-04-27 11:09:17 -0400573 unsigned int attribCount = stream.readInt<unsigned int>();
Jamie Madillc349ec02015-08-21 16:53:12 -0400574 ASSERT(mData.mAttributes.empty());
Jamie Madill3da79b72015-04-27 11:09:17 -0400575 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
576 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400577 sh::Attribute attrib;
Jamie Madill62d31cb2015-09-11 13:25:51 -0400578 LoadShaderVar(&stream, &attrib);
579 attrib.location = stream.readInt<int>();
Jamie Madillc349ec02015-08-21 16:53:12 -0400580 mData.mAttributes.push_back(attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400581 }
582
Jamie Madill62d31cb2015-09-11 13:25:51 -0400583 unsigned int uniformCount = stream.readInt<unsigned int>();
584 ASSERT(mData.mUniforms.empty());
585 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
586 {
587 LinkedUniform uniform;
588 LoadShaderVar(&stream, &uniform);
589
590 uniform.blockIndex = stream.readInt<int>();
591 uniform.blockInfo.offset = stream.readInt<int>();
592 uniform.blockInfo.arrayStride = stream.readInt<int>();
593 uniform.blockInfo.matrixStride = stream.readInt<int>();
594 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
595
596 mData.mUniforms.push_back(uniform);
597 }
598
599 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
600 ASSERT(mData.mUniformLocations.empty());
601 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
602 uniformIndexIndex++)
603 {
604 VariableLocation variable;
605 stream.readString(&variable.name);
606 stream.readInt(&variable.element);
607 stream.readInt(&variable.index);
608
609 mData.mUniformLocations.push_back(variable);
610 }
611
612 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
613 ASSERT(mData.mUniformBlocks.empty());
614 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
615 ++uniformBlockIndex)
616 {
617 UniformBlock uniformBlock;
618 stream.readString(&uniformBlock.name);
619 stream.readBool(&uniformBlock.isArray);
620 stream.readInt(&uniformBlock.arrayElement);
621 stream.readInt(&uniformBlock.dataSize);
622 stream.readBool(&uniformBlock.vertexStaticUse);
623 stream.readBool(&uniformBlock.fragmentStaticUse);
624
625 unsigned int numMembers = stream.readInt<unsigned int>();
626 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
627 {
628 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
629 }
630
Jamie Madill62d31cb2015-09-11 13:25:51 -0400631 mData.mUniformBlocks.push_back(uniformBlock);
632 }
633
Brandon Jones1048ea72015-10-06 15:34:52 -0700634 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
635 ASSERT(mData.mTransformFeedbackVaryingVars.empty());
636 for (unsigned int transformFeedbackVaryingIndex = 0;
637 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
638 ++transformFeedbackVaryingIndex)
639 {
640 sh::Varying varying;
641 stream.readInt(&varying.arraySize);
642 stream.readInt(&varying.type);
643 stream.readString(&varying.name);
644
645 mData.mTransformFeedbackVaryingVars.push_back(varying);
646 }
647
Jamie Madillada9ecc2015-08-17 12:53:37 -0400648 stream.readInt(&mData.mTransformFeedbackBufferMode);
649
Jamie Madill80a6fc02015-08-21 16:53:16 -0400650 unsigned int outputVarCount = stream.readInt<unsigned int>();
651 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
652 {
653 int locationIndex = stream.readInt<int>();
654 VariableLocation locationData;
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400655 stream.readInt(&locationData.element);
656 stream.readInt(&locationData.index);
657 stream.readString(&locationData.name);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400658 mData.mOutputVariables[locationIndex] = locationData;
659 }
660
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400661 stream.readInt(&mSamplerUniformRange.start);
662 stream.readInt(&mSamplerUniformRange.end);
663
Geoff Lang7dd2e102014-11-10 15:19:26 -0500664 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
665 if (result.error.isError() || !result.linkSuccess)
666 {
Geoff Langb543aff2014-09-30 14:52:54 -0400667 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000668 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000669
Geoff Lang7dd2e102014-11-10 15:19:26 -0500670 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400671 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500672#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
673}
674
675Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
676{
677 if (binaryFormat)
678 {
Geoff Langc46cc2f2015-10-01 17:16:20 -0400679 *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500680 }
681
682 BinaryOutputStream stream;
683
Geoff Lang7dd2e102014-11-10 15:19:26 -0500684 stream.writeInt(ANGLE_MAJOR_VERSION);
685 stream.writeInt(ANGLE_MINOR_VERSION);
686 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
687
Jamie Madill63805b42015-08-25 13:17:39 -0400688 stream.writeInt(mData.mActiveAttribLocationsMask.to_ulong());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500689
Jamie Madillc349ec02015-08-21 16:53:12 -0400690 stream.writeInt(mData.mAttributes.size());
691 for (const sh::Attribute &attrib : mData.mAttributes)
Jamie Madill3da79b72015-04-27 11:09:17 -0400692 {
Jamie Madill62d31cb2015-09-11 13:25:51 -0400693 WriteShaderVar(&stream, attrib);
Jamie Madill3da79b72015-04-27 11:09:17 -0400694 stream.writeInt(attrib.location);
Jamie Madill62d31cb2015-09-11 13:25:51 -0400695 }
696
697 stream.writeInt(mData.mUniforms.size());
698 for (const gl::LinkedUniform &uniform : mData.mUniforms)
699 {
700 WriteShaderVar(&stream, uniform);
701
702 // FIXME: referenced
703
704 stream.writeInt(uniform.blockIndex);
705 stream.writeInt(uniform.blockInfo.offset);
706 stream.writeInt(uniform.blockInfo.arrayStride);
707 stream.writeInt(uniform.blockInfo.matrixStride);
708 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
709 }
710
711 stream.writeInt(mData.mUniformLocations.size());
712 for (const auto &variable : mData.mUniformLocations)
713 {
714 stream.writeString(variable.name);
715 stream.writeInt(variable.element);
716 stream.writeInt(variable.index);
717 }
718
719 stream.writeInt(mData.mUniformBlocks.size());
720 for (const UniformBlock &uniformBlock : mData.mUniformBlocks)
721 {
722 stream.writeString(uniformBlock.name);
723 stream.writeInt(uniformBlock.isArray);
724 stream.writeInt(uniformBlock.arrayElement);
725 stream.writeInt(uniformBlock.dataSize);
726
727 stream.writeInt(uniformBlock.vertexStaticUse);
728 stream.writeInt(uniformBlock.fragmentStaticUse);
729
730 stream.writeInt(uniformBlock.memberUniformIndexes.size());
731 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
732 {
733 stream.writeInt(memberUniformIndex);
734 }
Jamie Madill3da79b72015-04-27 11:09:17 -0400735 }
736
Brandon Jones1048ea72015-10-06 15:34:52 -0700737 stream.writeInt(mData.mTransformFeedbackVaryingVars.size());
738 for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars)
739 {
740 stream.writeInt(varying.arraySize);
741 stream.writeInt(varying.type);
742 stream.writeString(varying.name);
743 }
744
Jamie Madillada9ecc2015-08-17 12:53:37 -0400745 stream.writeInt(mData.mTransformFeedbackBufferMode);
746
Jamie Madill80a6fc02015-08-21 16:53:16 -0400747 stream.writeInt(mData.mOutputVariables.size());
748 for (const auto &outputPair : mData.mOutputVariables)
749 {
750 stream.writeInt(outputPair.first);
751 stream.writeInt(outputPair.second.element);
752 stream.writeInt(outputPair.second.index);
753 stream.writeString(outputPair.second.name);
754 }
755
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400756 stream.writeInt(mSamplerUniformRange.start);
757 stream.writeInt(mSamplerUniformRange.end);
758
Geoff Lang7dd2e102014-11-10 15:19:26 -0500759 gl::Error error = mProgram->save(&stream);
760 if (error.isError())
761 {
762 return error;
763 }
764
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700765 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500766 const void *streamData = stream.data();
767
768 if (streamLength > bufSize)
769 {
770 if (length)
771 {
772 *length = 0;
773 }
774
775 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
776 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
777 // sizes and then copy it.
778 return Error(GL_INVALID_OPERATION);
779 }
780
781 if (binary)
782 {
783 char *ptr = reinterpret_cast<char*>(binary);
784
785 memcpy(ptr, streamData, streamLength);
786 ptr += streamLength;
787
788 ASSERT(ptr - streamLength == binary);
789 }
790
791 if (length)
792 {
793 *length = streamLength;
794 }
795
796 return Error(GL_NO_ERROR);
797}
798
799GLint Program::getBinaryLength() const
800{
801 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400802 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500803 if (error.isError())
804 {
805 return 0;
806 }
807
808 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000809}
810
Geoff Langc5629752015-12-07 16:29:04 -0500811void Program::setBinaryRetrievableHint(bool retrievable)
812{
813 // TODO(jmadill) : replace with dirty bits
814 mProgram->setBinaryRetrievableHint(retrievable);
815 mData.mBinaryRetrieveableHint = retrievable;
816}
817
818bool Program::getBinaryRetrievableHint() const
819{
820 return mData.mBinaryRetrieveableHint;
821}
822
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000823void Program::release()
824{
825 mRefCount--;
826
827 if (mRefCount == 0 && mDeleteStatus)
828 {
829 mResourceManager->deleteProgram(mHandle);
830 }
831}
832
833void Program::addRef()
834{
835 mRefCount++;
836}
837
838unsigned int Program::getRefCount() const
839{
840 return mRefCount;
841}
842
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000843int Program::getInfoLogLength() const
844{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400845 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000846}
847
Geoff Lange1a27752015-10-05 13:16:04 -0400848void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000849{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000850 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000851}
852
Geoff Lange1a27752015-10-05 13:16:04 -0400853void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000854{
855 int total = 0;
856
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400857 if (mData.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000858 {
859 if (total < maxCount)
860 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400861 shaders[total] = mData.mAttachedVertexShader->getHandle();
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000862 }
863
864 total++;
865 }
866
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400867 if (mData.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000868 {
869 if (total < maxCount)
870 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400871 shaders[total] = mData.mAttachedFragmentShader->getHandle();
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000872 }
873
874 total++;
875 }
876
877 if (count)
878 {
879 *count = total;
880 }
881}
882
Geoff Lange1a27752015-10-05 13:16:04 -0400883GLuint Program::getAttributeLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500884{
Jamie Madillc349ec02015-08-21 16:53:12 -0400885 for (const sh::Attribute &attribute : mData.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500886 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400887 if (attribute.name == name && attribute.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500888 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400889 return attribute.location;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500890 }
891 }
892
Austin Kinrossb8af7232015-03-16 22:33:25 -0700893 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500894}
895
Jamie Madill63805b42015-08-25 13:17:39 -0400896bool Program::isAttribLocationActive(size_t attribLocation) const
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400897{
Olli Etuaho401d9fe2015-08-26 10:19:59 +0300898 ASSERT(attribLocation < mData.mActiveAttribLocationsMask.size());
Jamie Madill63805b42015-08-25 13:17:39 -0400899 return mData.mActiveAttribLocationsMask[attribLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500900}
901
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000902void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
903{
Jamie Madillc349ec02015-08-21 16:53:12 -0400904 if (!mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000905 {
906 if (bufsize > 0)
907 {
908 name[0] = '\0';
909 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500910
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000911 if (length)
912 {
913 *length = 0;
914 }
915
916 *type = GL_NONE;
917 *size = 1;
Jamie Madillc349ec02015-08-21 16:53:12 -0400918 return;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000919 }
Jamie Madillc349ec02015-08-21 16:53:12 -0400920
921 size_t attributeIndex = 0;
922
923 for (const sh::Attribute &attribute : mData.mAttributes)
924 {
925 // Skip over inactive attributes
926 if (attribute.staticUse)
927 {
928 if (static_cast<size_t>(index) == attributeIndex)
929 {
930 break;
931 }
932 attributeIndex++;
933 }
934 }
935
936 ASSERT(index == attributeIndex && attributeIndex < mData.mAttributes.size());
937 const sh::Attribute &attrib = mData.mAttributes[attributeIndex];
938
939 if (bufsize > 0)
940 {
941 const char *string = attrib.name.c_str();
942
943 strncpy(name, string, bufsize);
944 name[bufsize - 1] = '\0';
945
946 if (length)
947 {
948 *length = static_cast<GLsizei>(strlen(name));
949 }
950 }
951
952 // Always a single 'type' instance
953 *size = 1;
954 *type = attrib.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000955}
956
Geoff Lange1a27752015-10-05 13:16:04 -0400957GLint Program::getActiveAttributeCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000958{
Jamie Madillc349ec02015-08-21 16:53:12 -0400959 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400960 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400961 return 0;
962 }
963
964 GLint count = 0;
965
966 for (const sh::Attribute &attrib : mData.mAttributes)
967 {
968 count += (attrib.staticUse ? 1 : 0);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000969 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500970
971 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000972}
973
Geoff Lange1a27752015-10-05 13:16:04 -0400974GLint Program::getActiveAttributeMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000975{
Jamie Madillc349ec02015-08-21 16:53:12 -0400976 if (!mLinked)
Jamie Madill2d773182015-08-18 10:27:28 -0400977 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400978 return 0;
979 }
980
981 size_t maxLength = 0;
982
983 for (const sh::Attribute &attrib : mData.mAttributes)
984 {
985 if (attrib.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500986 {
Jamie Madillc349ec02015-08-21 16:53:12 -0400987 maxLength = std::max(attrib.name.length() + 1, maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500988 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000989 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500990
Jamie Madillc349ec02015-08-21 16:53:12 -0400991 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500992}
993
Geoff Lang7dd2e102014-11-10 15:19:26 -0500994GLint Program::getFragDataLocation(const std::string &name) const
995{
996 std::string baseName(name);
997 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill80a6fc02015-08-21 16:53:16 -0400998 for (auto outputPair : mData.mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000999 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001000 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
1002 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001003 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001004 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001005 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001006 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001007}
1008
Geoff Lange1a27752015-10-05 13:16:04 -04001009void Program::getActiveUniform(GLuint index,
1010 GLsizei bufsize,
1011 GLsizei *length,
1012 GLint *size,
1013 GLenum *type,
1014 GLchar *name) const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001015{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001016 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001017 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001018 // index must be smaller than getActiveUniformCount()
1019 ASSERT(index < mData.mUniforms.size());
1020 const LinkedUniform &uniform = mData.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001021
1022 if (bufsize > 0)
1023 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001024 std::string string = uniform.name;
1025 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001026 {
1027 string += "[0]";
1028 }
1029
1030 strncpy(name, string.c_str(), bufsize);
1031 name[bufsize - 1] = '\0';
1032
1033 if (length)
1034 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001035 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001036 }
1037 }
1038
Jamie Madill62d31cb2015-09-11 13:25:51 -04001039 *size = uniform.elementCount();
1040 *type = uniform.type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001041 }
1042 else
1043 {
1044 if (bufsize > 0)
1045 {
1046 name[0] = '\0';
1047 }
1048
1049 if (length)
1050 {
1051 *length = 0;
1052 }
1053
1054 *size = 0;
1055 *type = GL_NONE;
1056 }
1057}
1058
Geoff Lange1a27752015-10-05 13:16:04 -04001059GLint Program::getActiveUniformCount() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001060{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001062 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001063 return static_cast<GLint>(mData.mUniforms.size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001064 }
1065 else
1066 {
1067 return 0;
1068 }
1069}
1070
Geoff Lange1a27752015-10-05 13:16:04 -04001071GLint Program::getActiveUniformMaxLength() const
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001072{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001073 size_t maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001074
1075 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001076 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001077 for (const LinkedUniform &uniform : mData.mUniforms)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001078 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001079 if (!uniform.name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001080 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001081 size_t length = uniform.name.length() + 1u;
1082 if (uniform.isArray())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001083 {
1084 length += 3; // Counting in "[0]".
1085 }
1086 maxLength = std::max(length, maxLength);
1087 }
1088 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001089 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001090
Jamie Madill62d31cb2015-09-11 13:25:51 -04001091 return static_cast<GLint>(maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001092}
1093
1094GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
1095{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001096 ASSERT(static_cast<size_t>(index) < mData.mUniforms.size());
1097 const gl::LinkedUniform &uniform = mData.mUniforms[index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001098 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001099 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001100 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
1101 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
1102 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
1103 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
1104 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
1105 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
1106 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
1107 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
1108 default:
1109 UNREACHABLE();
1110 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001111 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001112 return 0;
1113}
1114
1115bool Program::isValidUniformLocation(GLint location) const
1116{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001117 ASSERT(rx::IsIntegerCastSafe<GLint>(mData.mUniformLocations.size()));
1118 return (location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001119}
1120
Jamie Madill62d31cb2015-09-11 13:25:51 -04001121const LinkedUniform &Program::getUniformByLocation(GLint location) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001122{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001123 ASSERT(location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
1124 return mData.mUniforms[mData.mUniformLocations[location].index];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001125}
1126
Jamie Madill62d31cb2015-09-11 13:25:51 -04001127GLint Program::getUniformLocation(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001128{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001129 return mData.getUniformLocation(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130}
1131
Jamie Madill62d31cb2015-09-11 13:25:51 -04001132GLuint Program::getUniformIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001133{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001134 return mData.getUniformIndex(name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001135}
1136
1137void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1138{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001139 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001140 mProgram->setUniform1fv(location, count, v);
1141}
1142
1143void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1144{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001145 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001146 mProgram->setUniform2fv(location, count, v);
1147}
1148
1149void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1150{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001151 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001152 mProgram->setUniform3fv(location, count, v);
1153}
1154
1155void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1156{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001157 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001158 mProgram->setUniform4fv(location, count, v);
1159}
1160
1161void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
1162{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001163 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001164 mProgram->setUniform1iv(location, count, v);
1165}
1166
1167void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
1168{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001169 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001170 mProgram->setUniform2iv(location, count, v);
1171}
1172
1173void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
1174{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001175 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176 mProgram->setUniform3iv(location, count, v);
1177}
1178
1179void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
1180{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001181 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001182 mProgram->setUniform4iv(location, count, v);
1183}
1184
1185void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
1186{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001187 setUniformInternal(location, count * 1, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001188 mProgram->setUniform1uiv(location, count, v);
1189}
1190
1191void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
1192{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001193 setUniformInternal(location, count * 2, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001194 mProgram->setUniform2uiv(location, count, v);
1195}
1196
1197void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
1198{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001199 setUniformInternal(location, count * 3, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001200 mProgram->setUniform3uiv(location, count, v);
1201}
1202
1203void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
1204{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001205 setUniformInternal(location, count * 4, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001206 mProgram->setUniform4uiv(location, count, v);
1207}
1208
1209void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1210{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001211 setMatrixUniformInternal<2, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001212 mProgram->setUniformMatrix2fv(location, count, transpose, v);
1213}
1214
1215void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1216{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001217 setMatrixUniformInternal<3, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001218 mProgram->setUniformMatrix3fv(location, count, transpose, v);
1219}
1220
1221void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1222{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001223 setMatrixUniformInternal<4, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001224 mProgram->setUniformMatrix4fv(location, count, transpose, v);
1225}
1226
1227void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1228{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001229 setMatrixUniformInternal<2, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001230 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
1231}
1232
1233void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1234{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001235 setMatrixUniformInternal<2, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
1237}
1238
1239void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1240{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001241 setMatrixUniformInternal<3, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001242 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
1243}
1244
1245void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1246{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001247 setMatrixUniformInternal<3, 4>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001248 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
1249}
1250
1251void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1252{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001253 setMatrixUniformInternal<4, 2>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001254 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
1255}
1256
1257void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
1258{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001259 setMatrixUniformInternal<4, 3>(location, count, transpose, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001260 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
1261}
1262
Geoff Lange1a27752015-10-05 13:16:04 -04001263void Program::getUniformfv(GLint location, GLfloat *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001264{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001265 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001266}
1267
Geoff Lange1a27752015-10-05 13:16:04 -04001268void Program::getUniformiv(GLint location, GLint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001269{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001270 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001271}
1272
Geoff Lange1a27752015-10-05 13:16:04 -04001273void Program::getUniformuiv(GLint location, GLuint *v) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001274{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001275 getUniformInternal(location, v);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001276}
1277
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001278void Program::flagForDeletion()
1279{
1280 mDeleteStatus = true;
1281}
1282
1283bool Program::isFlaggedForDeletion() const
1284{
1285 return mDeleteStatus;
1286}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001287
Brandon Jones43a53e22014-08-28 16:23:22 -07001288void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001289{
1290 mInfoLog.reset();
1291
Geoff Lang7dd2e102014-11-10 15:19:26 -05001292 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001293 {
Jamie Madill36cfd6a2015-08-18 10:46:20 -04001294 mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001295 }
1296 else
1297 {
Jamie Madillf6113162015-05-07 11:49:21 -04001298 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001299 }
1300}
1301
Geoff Lang7dd2e102014-11-10 15:19:26 -05001302bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1303{
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001304 // Skip cache if we're using an infolog, so we get the full error.
1305 // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
1306 if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
1307 {
1308 return mCachedValidateSamplersResult.value();
1309 }
1310
1311 if (mTextureUnitTypesCache.empty())
1312 {
1313 mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
1314 }
1315 else
1316 {
1317 std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
1318 }
1319
1320 // if any two active samplers in a program are of different types, but refer to the same
1321 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1322 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1323 for (unsigned int samplerIndex = mSamplerUniformRange.start;
1324 samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
1325 {
1326 const LinkedUniform &uniform = mData.mUniforms[samplerIndex];
1327 ASSERT(uniform.isSampler());
1328
1329 if (!uniform.staticUse)
1330 continue;
1331
1332 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
1333 GLenum textureType = SamplerTypeToTextureType(uniform.type);
1334
1335 for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
1336 {
1337 GLuint textureUnit = dataPtr[arrayElement];
1338
1339 if (textureUnit >= caps.maxCombinedTextureImageUnits)
1340 {
1341 if (infoLog)
1342 {
1343 (*infoLog) << "Sampler uniform (" << textureUnit
1344 << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
1345 << caps.maxCombinedTextureImageUnits << ")";
1346 }
1347
1348 mCachedValidateSamplersResult = false;
1349 return false;
1350 }
1351
1352 if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
1353 {
1354 if (textureType != mTextureUnitTypesCache[textureUnit])
1355 {
1356 if (infoLog)
1357 {
1358 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1359 "image unit ("
1360 << textureUnit << ").";
1361 }
1362
1363 mCachedValidateSamplersResult = false;
1364 return false;
1365 }
1366 }
1367 else
1368 {
1369 mTextureUnitTypesCache[textureUnit] = textureType;
1370 }
1371 }
1372 }
1373
1374 mCachedValidateSamplersResult = true;
1375 return true;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001376}
1377
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001378bool Program::isValidated() const
1379{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001380 return mValidated;
1381}
1382
Geoff Lange1a27752015-10-05 13:16:04 -04001383GLuint Program::getActiveUniformBlockCount() const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001384{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001385 return static_cast<GLuint>(mData.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386}
1387
1388void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1389{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001390 ASSERT(uniformBlockIndex <
1391 mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392
Jamie Madill62d31cb2015-09-11 13:25:51 -04001393 const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394
1395 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001396 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001397 std::string string = uniformBlock.name;
1398
Jamie Madill62d31cb2015-09-11 13:25:51 -04001399 if (uniformBlock.isArray)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001401 string += ArrayString(uniformBlock.arrayElement);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001402 }
1403
1404 strncpy(uniformBlockName, string.c_str(), bufSize);
1405 uniformBlockName[bufSize - 1] = '\0';
1406
1407 if (length)
1408 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001409 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001410 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001411 }
1412}
1413
Geoff Lang7dd2e102014-11-10 15:19:26 -05001414void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001415{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001416 ASSERT(uniformBlockIndex <
1417 mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
Geoff Lang7dd2e102014-11-10 15:19:26 -05001418
Jamie Madill62d31cb2015-09-11 13:25:51 -04001419 const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001420
1421 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001422 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001423 case GL_UNIFORM_BLOCK_DATA_SIZE:
1424 *params = static_cast<GLint>(uniformBlock.dataSize);
1425 break;
1426 case GL_UNIFORM_BLOCK_NAME_LENGTH:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001427 *params =
1428 static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001429 break;
1430 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1431 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1432 break;
1433 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1434 {
1435 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1436 {
1437 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1438 }
1439 }
1440 break;
1441 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001442 *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001443 break;
1444 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
Jamie Madill62d31cb2015-09-11 13:25:51 -04001445 *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446 break;
1447 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001448 }
1449}
1450
Geoff Lange1a27752015-10-05 13:16:04 -04001451GLint Program::getActiveUniformBlockMaxLength() const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001452{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001453 int maxLength = 0;
1454
1455 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001456 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001457 unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001458 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1459 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001460 const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461 if (!uniformBlock.name.empty())
1462 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001463 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001464
1465 // Counting in "[0]".
Jamie Madill62d31cb2015-09-11 13:25:51 -04001466 const int arrayLength = (uniformBlock.isArray ? 3 : 0);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467
1468 maxLength = std::max(length + arrayLength, maxLength);
1469 }
1470 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001471 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001472
1473 return maxLength;
1474}
1475
Geoff Lange1a27752015-10-05 13:16:04 -04001476GLuint Program::getUniformBlockIndex(const std::string &name) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05001477{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001478 size_t subscript = GL_INVALID_INDEX;
1479 std::string baseName = gl::ParseUniformName(name, &subscript);
1480
1481 unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
1482 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
1483 {
1484 const gl::UniformBlock &uniformBlock = mData.mUniformBlocks[blockIndex];
1485 if (uniformBlock.name == baseName)
1486 {
1487 const bool arrayElementZero =
1488 (subscript == GL_INVALID_INDEX &&
1489 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
1490 if (subscript == uniformBlock.arrayElement || arrayElementZero)
1491 {
1492 return blockIndex;
1493 }
1494 }
1495 }
1496
1497 return GL_INVALID_INDEX;
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001498}
1499
Jamie Madill62d31cb2015-09-11 13:25:51 -04001500const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001501{
Jamie Madill62d31cb2015-09-11 13:25:51 -04001502 ASSERT(index < static_cast<GLuint>(mData.mUniformBlocks.size()));
1503 return mData.mUniformBlocks[index];
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001504}
1505
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001506void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1507{
Jamie Madilld1fe1642015-08-21 16:26:04 -04001508 mData.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
Geoff Lang5d124a62015-09-15 13:03:27 -04001509 mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001510}
1511
1512GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1513{
Jamie Madilld1fe1642015-08-21 16:26:04 -04001514 return mData.getUniformBlockBinding(uniformBlockIndex);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001515}
1516
1517void Program::resetUniformBlockBindings()
1518{
1519 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1520 {
Jamie Madilld1fe1642015-08-21 16:26:04 -04001521 mData.mUniformBlockBindings[blockId] = 0;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001522 }
Geoff Lang5d124a62015-09-15 13:03:27 -04001523 mData.mActiveUniformBlockBindings.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001524}
1525
Geoff Lang48dcae72014-02-05 16:28:24 -05001526void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1527{
Jamie Madillccdf74b2015-08-18 10:46:12 -04001528 mData.mTransformFeedbackVaryingNames.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001529 for (GLsizei i = 0; i < count; i++)
1530 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001531 mData.mTransformFeedbackVaryingNames[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001532 }
1533
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001534 mData.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001535}
1536
1537void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1538{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001540 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001541 ASSERT(index < mData.mTransformFeedbackVaryingVars.size());
1542 const sh::Varying &varying = mData.mTransformFeedbackVaryingVars[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001543 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1544 if (length)
1545 {
1546 *length = lastNameIdx;
1547 }
1548 if (size)
1549 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001550 *size = varying.elementCount();
Geoff Lang48dcae72014-02-05 16:28:24 -05001551 }
1552 if (type)
1553 {
1554 *type = varying.type;
1555 }
1556 if (name)
1557 {
1558 memcpy(name, varying.name.c_str(), lastNameIdx);
1559 name[lastNameIdx] = '\0';
1560 }
1561 }
1562}
1563
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001564GLsizei Program::getTransformFeedbackVaryingCount() const
1565{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001566 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001567 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04001568 return static_cast<GLsizei>(mData.mTransformFeedbackVaryingVars.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001569 }
1570 else
1571 {
1572 return 0;
1573 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001574}
1575
1576GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1577{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001578 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001579 {
1580 GLsizei maxSize = 0;
Jamie Madillccdf74b2015-08-18 10:46:12 -04001581 for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars)
Geoff Lang48dcae72014-02-05 16:28:24 -05001582 {
Geoff Lang48dcae72014-02-05 16:28:24 -05001583 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1584 }
1585
1586 return maxSize;
1587 }
1588 else
1589 {
1590 return 0;
1591 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001592}
1593
1594GLenum Program::getTransformFeedbackBufferMode() const
1595{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001596 return mData.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001597}
1598
Jamie Madillada9ecc2015-08-17 12:53:37 -04001599// static
1600bool Program::linkVaryings(InfoLog &infoLog,
1601 const Shader *vertexShader,
1602 const Shader *fragmentShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001603{
Jamie Madill4cff2472015-08-21 16:53:18 -04001604 const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1605 const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001606
Jamie Madill4cff2472015-08-21 16:53:18 -04001607 for (const sh::Varying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001608 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001609 bool matched = false;
1610
1611 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001612 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001613 {
1614 continue;
1615 }
1616
Jamie Madill4cff2472015-08-21 16:53:18 -04001617 for (const sh::Varying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001618 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001619 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001621 ASSERT(!input.isBuiltIn());
1622 if (!linkValidateVaryings(infoLog, output.name, input, output))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001623 {
1624 return false;
1625 }
1626
Geoff Lang7dd2e102014-11-10 15:19:26 -05001627 matched = true;
1628 break;
1629 }
1630 }
1631
1632 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001633 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001634 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001635 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001636 return false;
1637 }
1638 }
1639
Jamie Madillada9ecc2015-08-17 12:53:37 -04001640 // TODO(jmadill): verify no unmatched vertex varyings?
1641
Geoff Lang7dd2e102014-11-10 15:19:26 -05001642 return true;
1643}
1644
Jamie Madill62d31cb2015-09-11 13:25:51 -04001645bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
Jamie Madillea918db2015-08-18 14:48:59 -04001646{
1647 const std::vector<sh::Uniform> &vertexUniforms = mData.mAttachedVertexShader->getUniforms();
1648 const std::vector<sh::Uniform> &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms();
1649
1650 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill62d31cb2015-09-11 13:25:51 -04001651 std::map<std::string, LinkedUniform> linkedUniforms;
Jamie Madillea918db2015-08-18 14:48:59 -04001652
1653 for (const sh::Uniform &vertexUniform : vertexUniforms)
1654 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001655 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
Jamie Madillea918db2015-08-18 14:48:59 -04001656 }
1657
1658 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
1659 {
1660 auto entry = linkedUniforms.find(fragmentUniform.name);
1661 if (entry != linkedUniforms.end())
1662 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001663 LinkedUniform *vertexUniform = &entry->second;
1664 const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
1665 if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
Jamie Madillea918db2015-08-18 14:48:59 -04001666 {
1667 return false;
1668 }
1669 }
1670 }
1671
Jamie Madill62d31cb2015-09-11 13:25:51 -04001672 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1673 // Also check the maximum uniform vector and sampler counts.
1674 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1675 {
1676 return false;
1677 }
1678
1679 indexUniforms();
1680
Jamie Madillea918db2015-08-18 14:48:59 -04001681 return true;
1682}
1683
Jamie Madill62d31cb2015-09-11 13:25:51 -04001684void Program::indexUniforms()
1685{
1686 for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++)
1687 {
1688 const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex];
1689
1690 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
1691 {
1692 if (!uniform.isBuiltIn())
1693 {
1694 // Assign in-order uniform locations
1695 mData.mUniformLocations.push_back(gl::VariableLocation(
1696 uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex)));
1697 }
1698 }
1699 }
1700}
1701
Geoff Lang7dd2e102014-11-10 15:19:26 -05001702bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1703{
Jamie Madillc4c744222015-11-04 09:39:47 -05001704 // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
1705 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001706 {
1707 return false;
1708 }
1709
1710 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1711 {
Jamie Madillf6113162015-05-07 11:49:21 -04001712 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001713 return false;
1714 }
1715
1716 return true;
1717}
1718
1719// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001720bool Program::linkAttributes(const gl::Data &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001721 InfoLog &infoLog,
1722 const AttributeBindings &attributeBindings,
1723 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001724{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001725 unsigned int usedLocations = 0;
Jamie Madillc349ec02015-08-21 16:53:12 -04001726 mData.mAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001727 GLuint maxAttribs = data.caps->maxVertexAttributes;
1728
1729 // TODO(jmadill): handle aliasing robustly
Jamie Madillc349ec02015-08-21 16:53:12 -04001730 if (mData.mAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001731 {
Jamie Madillf6113162015-05-07 11:49:21 -04001732 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001733 return false;
1734 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001735
Jamie Madillc349ec02015-08-21 16:53:12 -04001736 std::vector<sh::Attribute *> usedAttribMap(data.caps->maxVertexAttributes, nullptr);
Jamie Madill4e107222015-08-24 14:12:17 +00001737
Jamie Madillc349ec02015-08-21 16:53:12 -04001738 // Link attributes that have a binding location
1739 for (sh::Attribute &attribute : mData.mAttributes)
1740 {
1741 // TODO(jmadill): do staticUse filtering step here, or not at all
Geoff Lang7dd2e102014-11-10 15:19:26 -05001742 ASSERT(attribute.staticUse);
1743
Jamie Madillc349ec02015-08-21 16:53:12 -04001744 int bindingLocation = attributeBindings.getAttributeBinding(attribute.name);
1745 if (attribute.location == -1 && bindingLocation != -1)
Jamie Madill2d773182015-08-18 10:27:28 -04001746 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001747 attribute.location = bindingLocation;
1748 }
1749
1750 if (attribute.location != -1)
1751 {
1752 // Location is set by glBindAttribLocation or by location layout qualifier
Jamie Madill63805b42015-08-25 13:17:39 -04001753 const int regs = VariableRegisterCount(attribute.type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001754
Jamie Madill63805b42015-08-25 13:17:39 -04001755 if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001756 {
Jamie Madillf6113162015-05-07 11:49:21 -04001757 infoLog << "Active attribute (" << attribute.name << ") at location "
Jamie Madillc349ec02015-08-21 16:53:12 -04001758 << attribute.location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001759
1760 return false;
1761 }
1762
Jamie Madill63805b42015-08-25 13:17:39 -04001763 for (int reg = 0; reg < regs; reg++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001764 {
Jamie Madill63805b42015-08-25 13:17:39 -04001765 const int regLocation = attribute.location + reg;
1766 sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001767
1768 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001769 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
Jamie Madillc349ec02015-08-21 16:53:12 -04001770 if (linkedAttribute)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001771 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001772 // TODO(jmadill): fix aliasing on ES2
1773 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001774 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001775 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
Jamie Madill63805b42015-08-25 13:17:39 -04001776 << linkedAttribute->name << "' at location " << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001777 return false;
1778 }
1779 }
Jamie Madillc349ec02015-08-21 16:53:12 -04001780 else
1781 {
Jamie Madill63805b42015-08-25 13:17:39 -04001782 usedAttribMap[regLocation] = &attribute;
Jamie Madillc349ec02015-08-21 16:53:12 -04001783 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001784
Jamie Madill63805b42015-08-25 13:17:39 -04001785 usedLocations |= 1 << regLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001786 }
1787 }
1788 }
1789
1790 // Link attributes that don't have a binding location
Jamie Madillc349ec02015-08-21 16:53:12 -04001791 for (sh::Attribute &attribute : mData.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001792 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001793 ASSERT(attribute.staticUse);
1794
Jamie Madillc349ec02015-08-21 16:53:12 -04001795 // Not set by glBindAttribLocation or by location layout qualifier
1796 if (attribute.location == -1)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001797 {
Jamie Madill63805b42015-08-25 13:17:39 -04001798 int regs = VariableRegisterCount(attribute.type);
1799 int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001800
Jamie Madill63805b42015-08-25 13:17:39 -04001801 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001802 {
Jamie Madillf6113162015-05-07 11:49:21 -04001803 infoLog << "Too many active attributes (" << attribute.name << ")";
Jamie Madillc349ec02015-08-21 16:53:12 -04001804 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001805 }
1806
Jamie Madillc349ec02015-08-21 16:53:12 -04001807 attribute.location = availableIndex;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001808 }
1809 }
1810
Jamie Madillc349ec02015-08-21 16:53:12 -04001811 for (const sh::Attribute &attribute : mData.mAttributes)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001812 {
Jamie Madillc349ec02015-08-21 16:53:12 -04001813 ASSERT(attribute.staticUse);
Jamie Madill63805b42015-08-25 13:17:39 -04001814 ASSERT(attribute.location != -1);
1815 int regs = VariableRegisterCount(attribute.type);
Jamie Madillc349ec02015-08-21 16:53:12 -04001816
Jamie Madill63805b42015-08-25 13:17:39 -04001817 for (int r = 0; r < regs; r++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001818 {
Jamie Madill63805b42015-08-25 13:17:39 -04001819 mData.mActiveAttribLocationsMask.set(attribute.location + r);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001820 }
1821 }
1822
Geoff Lang7dd2e102014-11-10 15:19:26 -05001823 return true;
1824}
1825
Jamie Madille473dee2015-08-18 14:49:01 -04001826bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001827{
Jamie Madille473dee2015-08-18 14:49:01 -04001828 const Shader &vertexShader = *mData.mAttachedVertexShader;
1829 const Shader &fragmentShader = *mData.mAttachedFragmentShader;
1830
Geoff Lang7dd2e102014-11-10 15:19:26 -05001831 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1832 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madille473dee2015-08-18 14:49:01 -04001833
Geoff Lang7dd2e102014-11-10 15:19:26 -05001834 // Check that interface blocks defined in the vertex and fragment shaders are identical
1835 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1836 UniformBlockMap linkedUniformBlocks;
Jamie Madille473dee2015-08-18 14:49:01 -04001837
1838 GLuint vertexBlockCount = 0;
1839 for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001840 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
Jamie Madille473dee2015-08-18 14:49:01 -04001842
1843 // Note: shared and std140 layouts are always considered active
1844 if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1845 {
1846 if (++vertexBlockCount > caps.maxVertexUniformBlocks)
1847 {
1848 infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
1849 << caps.maxVertexUniformBlocks << ")";
1850 return false;
1851 }
1852 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001853 }
Jamie Madille473dee2015-08-18 14:49:01 -04001854
1855 GLuint fragmentBlockCount = 0;
1856 for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001857 {
Jamie Madille473dee2015-08-18 14:49:01 -04001858 auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001859 if (entry != linkedUniformBlocks.end())
1860 {
1861 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1862 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1863 {
1864 return false;
1865 }
1866 }
Jamie Madille473dee2015-08-18 14:49:01 -04001867
Geoff Lang7dd2e102014-11-10 15:19:26 -05001868 // Note: shared and std140 layouts are always considered active
Jamie Madille473dee2015-08-18 14:49:01 -04001869 if (fragmentInterfaceBlock.staticUse ||
1870 fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871 {
Jamie Madille473dee2015-08-18 14:49:01 -04001872 if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001873 {
Jamie Madille473dee2015-08-18 14:49:01 -04001874 infoLog
1875 << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
1876 << caps.maxFragmentUniformBlocks << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001877 return false;
1878 }
1879 }
1880 }
Jamie Madille473dee2015-08-18 14:49:01 -04001881
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 return true;
1883}
1884
1885bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1886 const sh::InterfaceBlock &fragmentInterfaceBlock)
1887{
1888 const char* blockName = vertexInterfaceBlock.name.c_str();
1889 // validate blocks for the same member types
1890 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1891 {
Jamie Madillf6113162015-05-07 11:49:21 -04001892 infoLog << "Types for interface block '" << blockName
1893 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 return false;
1895 }
1896 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1897 {
Jamie Madillf6113162015-05-07 11:49:21 -04001898 infoLog << "Array sizes differ for interface block '" << blockName
1899 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001900 return false;
1901 }
1902 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1903 {
Jamie Madillf6113162015-05-07 11:49:21 -04001904 infoLog << "Layout qualifiers differ for interface block '" << blockName
1905 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001906 return false;
1907 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001908 const unsigned int numBlockMembers =
1909 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001910 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1911 {
1912 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1913 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
1914 if (vertexMember.name != fragmentMember.name)
1915 {
Jamie Madillf6113162015-05-07 11:49:21 -04001916 infoLog << "Name mismatch for field " << blockMemberIndex
1917 << " of interface block '" << blockName
1918 << "': (in vertex: '" << vertexMember.name
1919 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001920 return false;
1921 }
1922 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1923 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
1924 {
1925 return false;
1926 }
1927 }
1928 return true;
1929}
1930
1931bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1932 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
1933{
1934 if (vertexVariable.type != fragmentVariable.type)
1935 {
Jamie Madillf6113162015-05-07 11:49:21 -04001936 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001937 return false;
1938 }
1939 if (vertexVariable.arraySize != fragmentVariable.arraySize)
1940 {
Jamie Madillf6113162015-05-07 11:49:21 -04001941 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001942 return false;
1943 }
1944 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
1945 {
Jamie Madillf6113162015-05-07 11:49:21 -04001946 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001947 return false;
1948 }
1949
1950 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
1951 {
Jamie Madillf6113162015-05-07 11:49:21 -04001952 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001953 return false;
1954 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001955 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001956 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1957 {
1958 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1959 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
1960
1961 if (vertexMember.name != fragmentMember.name)
1962 {
Jamie Madillf6113162015-05-07 11:49:21 -04001963 infoLog << "Name mismatch for field '" << memberIndex
1964 << "' of " << variableName
1965 << ": (in vertex: '" << vertexMember.name
1966 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001967 return false;
1968 }
1969
1970 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1971 vertexMember.name + "'";
1972
1973 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
1974 {
1975 return false;
1976 }
1977 }
1978
1979 return true;
1980}
1981
1982bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1983{
Cooper Partin1acf4382015-06-12 12:38:57 -07001984#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
1985 const bool validatePrecision = true;
1986#else
1987 const bool validatePrecision = false;
1988#endif
1989
1990 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001991 {
1992 return false;
1993 }
1994
1995 return true;
1996}
1997
1998bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1999{
2000 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
2001 {
2002 return false;
2003 }
2004
Jamie Madille9cc4692015-02-19 16:00:13 -05002005 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05002006 {
Jamie Madillf6113162015-05-07 11:49:21 -04002007 infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002008 return false;
2009 }
2010
2011 return true;
2012}
2013
Jamie Madillccdf74b2015-08-18 10:46:12 -04002014bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
2015 const std::vector<const sh::Varying *> &varyings,
2016 const Caps &caps) const
Geoff Lang7dd2e102014-11-10 15:19:26 -05002017{
2018 size_t totalComponents = 0;
2019
Jamie Madillccdf74b2015-08-18 10:46:12 -04002020 std::set<std::string> uniqueNames;
2021
2022 for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002023 {
2024 bool found = false;
Jamie Madillccdf74b2015-08-18 10:46:12 -04002025 for (const sh::Varying *varying : varyings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002026 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002027 if (tfVaryingName == varying->name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002028 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002029 if (uniqueNames.count(tfVaryingName) > 0)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002030 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002031 infoLog << "Two transform feedback varyings specify the same output variable ("
2032 << tfVaryingName << ").";
2033 return false;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002034 }
Jamie Madillccdf74b2015-08-18 10:46:12 -04002035 uniqueNames.insert(tfVaryingName);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002036
Geoff Lang1a683462015-09-29 15:09:59 -04002037 if (varying->isArray())
2038 {
2039 infoLog << "Capture of arrays is undefined and not supported.";
2040 return false;
2041 }
2042
Jamie Madillccdf74b2015-08-18 10:46:12 -04002043 // TODO(jmadill): Investigate implementation limits on D3D11
2044 size_t componentCount = gl::VariableComponentCount(varying->type);
Jamie Madillada9ecc2015-08-17 12:53:37 -04002045 if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05002046 componentCount > caps.maxTransformFeedbackSeparateComponents)
2047 {
Jamie Madillccdf74b2015-08-18 10:46:12 -04002048 infoLog << "Transform feedback varying's " << varying->name << " components ("
2049 << componentCount << ") exceed the maximum separate components ("
Jamie Madillf6113162015-05-07 11:49:21 -04002050 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002051 return false;
2052 }
2053
2054 totalComponents += componentCount;
Geoff Lang7dd2e102014-11-10 15:19:26 -05002055 found = true;
2056 break;
2057 }
2058 }
2059
Jamie Madill89bb70e2015-08-31 14:18:39 -04002060 if (tfVaryingName.find('[') != std::string::npos)
2061 {
Geoff Lang1a683462015-09-29 15:09:59 -04002062 infoLog << "Capture of array elements is undefined and not supported.";
Jamie Madill89bb70e2015-08-31 14:18:39 -04002063 return false;
2064 }
2065
Geoff Lang7dd2e102014-11-10 15:19:26 -05002066 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2067 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04002068 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05002069 }
2070
Jamie Madillada9ecc2015-08-17 12:53:37 -04002071 if (mData.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04002072 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05002073 {
Jamie Madillf6113162015-05-07 11:49:21 -04002074 infoLog << "Transform feedback varying total components (" << totalComponents
2075 << ") exceed the maximum interleaved components ("
2076 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05002077 return false;
2078 }
2079
2080 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05002081}
2082
Jamie Madillccdf74b2015-08-18 10:46:12 -04002083void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
2084{
2085 // Gather the linked varyings that are used for transform feedback, they should all exist.
2086 mData.mTransformFeedbackVaryingVars.clear();
2087 for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
2088 {
2089 for (const sh::Varying *varying : varyings)
2090 {
2091 if (tfVaryingName == varying->name)
2092 {
2093 mData.mTransformFeedbackVaryingVars.push_back(*varying);
2094 break;
2095 }
2096 }
2097 }
2098}
2099
2100std::vector<const sh::Varying *> Program::getMergedVaryings() const
2101{
2102 std::set<std::string> uniqueNames;
2103 std::vector<const sh::Varying *> varyings;
2104
2105 for (const sh::Varying &varying : mData.mAttachedVertexShader->getVaryings())
2106 {
2107 if (uniqueNames.count(varying.name) == 0)
2108 {
2109 uniqueNames.insert(varying.name);
2110 varyings.push_back(&varying);
2111 }
2112 }
2113
2114 for (const sh::Varying &varying : mData.mAttachedFragmentShader->getVaryings())
2115 {
2116 if (uniqueNames.count(varying.name) == 0)
2117 {
2118 uniqueNames.insert(varying.name);
2119 varyings.push_back(&varying);
2120 }
2121 }
2122
2123 return varyings;
2124}
Jamie Madill80a6fc02015-08-21 16:53:16 -04002125
2126void Program::linkOutputVariables()
2127{
2128 const Shader *fragmentShader = mData.mAttachedFragmentShader;
2129 ASSERT(fragmentShader != nullptr);
2130
2131 // Skip this step for GLES2 shaders.
2132 if (fragmentShader->getShaderVersion() == 100)
2133 return;
2134
Jamie Madilla0a9e122015-09-02 15:54:30 -04002135 const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
Jamie Madill80a6fc02015-08-21 16:53:16 -04002136
2137 // TODO(jmadill): any caps validation here?
2138
2139 for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
2140 outputVariableIndex++)
2141 {
Jamie Madilla0a9e122015-09-02 15:54:30 -04002142 const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
Jamie Madill80a6fc02015-08-21 16:53:16 -04002143
2144 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
2145 if (outputVariable.isBuiltIn())
2146 continue;
2147
2148 // Since multiple output locations must be specified, use 0 for non-specified locations.
2149 int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
2150
2151 ASSERT(outputVariable.staticUse);
2152
2153 for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
2154 elementIndex++)
2155 {
2156 const int location = baseLocation + elementIndex;
2157 ASSERT(mData.mOutputVariables.count(location) == 0);
2158 unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
2159 mData.mOutputVariables[location] =
2160 VariableLocation(outputVariable.name, element, outputVariableIndex);
2161 }
2162 }
2163}
Jamie Madill62d31cb2015-09-11 13:25:51 -04002164
2165bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
2166{
2167 const gl::Shader *vertexShader = mData.getAttachedVertexShader();
2168 VectorAndSamplerCount vsCounts;
2169
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002170 std::vector<LinkedUniform> samplerUniforms;
2171
Jamie Madill62d31cb2015-09-11 13:25:51 -04002172 for (const sh::Uniform &uniform : vertexShader->getUniforms())
2173 {
2174 if (uniform.staticUse)
2175 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002176 vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002177 }
2178 }
2179
2180 if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
2181 {
2182 infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
2183 << caps.maxVertexUniformVectors << ").";
2184 return false;
2185 }
2186
2187 if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
2188 {
2189 infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
2190 << caps.maxVertexTextureImageUnits << ").";
2191 return false;
2192 }
2193
2194 const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
2195 VectorAndSamplerCount fsCounts;
2196
2197 for (const sh::Uniform &uniform : fragmentShader->getUniforms())
2198 {
2199 if (uniform.staticUse)
2200 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002201 fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002202 }
2203 }
2204
2205 if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
2206 {
2207 infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
2208 << caps.maxFragmentUniformVectors << ").";
2209 return false;
2210 }
2211
2212 if (fsCounts.samplerCount > caps.maxTextureImageUnits)
2213 {
2214 infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
2215 << caps.maxTextureImageUnits << ").";
2216 return false;
2217 }
2218
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002219 mSamplerUniformRange.start = static_cast<unsigned int>(mData.mUniforms.size());
2220 mSamplerUniformRange.end =
2221 mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
2222
2223 mData.mUniforms.insert(mData.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
2224
Jamie Madill62d31cb2015-09-11 13:25:51 -04002225 return true;
2226}
2227
2228Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002229 const std::string &fullName,
2230 std::vector<LinkedUniform> *samplerUniforms)
Jamie Madill62d31cb2015-09-11 13:25:51 -04002231{
2232 VectorAndSamplerCount vectorAndSamplerCount;
2233
2234 if (uniform.isStruct())
2235 {
2236 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
2237 {
2238 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
2239
2240 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2241 {
2242 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
2243 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
2244
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002245 vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002246 }
2247 }
2248
2249 return vectorAndSamplerCount;
2250 }
2251
2252 // Not a struct
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002253 bool isSampler = IsSamplerType(uniform.type);
2254 if (!UniformInList(mData.getUniforms(), fullName) && !UniformInList(*samplerUniforms, fullName))
Jamie Madill62d31cb2015-09-11 13:25:51 -04002255 {
2256 gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
2257 uniform.arraySize, -1,
2258 sh::BlockMemberInfo::getDefaultBlockInfo());
2259 linkedUniform.staticUse = true;
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002260
2261 // Store sampler uniforms separately, so we'll append them to the end of the list.
2262 if (isSampler)
2263 {
2264 samplerUniforms->push_back(linkedUniform);
2265 }
2266 else
2267 {
2268 mData.mUniforms.push_back(linkedUniform);
2269 }
Jamie Madill62d31cb2015-09-11 13:25:51 -04002270 }
2271
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002272 unsigned int elementCount = uniform.elementCount();
Austin Kinross7a3e8e22015-10-08 15:50:06 -07002273
2274 // Samplers aren't "real" uniforms, so they don't count towards register usage.
2275 // Likewise, don't count "real" uniforms towards sampler count.
2276 vectorAndSamplerCount.vectorCount =
2277 (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002278 vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002279
2280 return vectorAndSamplerCount;
2281}
2282
2283void Program::gatherInterfaceBlockInfo()
2284{
2285 std::set<std::string> visitedList;
2286
2287 const gl::Shader *vertexShader = mData.getAttachedVertexShader();
2288
2289 ASSERT(mData.mUniformBlocks.empty());
2290 for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
2291 {
2292 // Only 'packed' blocks are allowed to be considered inacive.
2293 if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
2294 continue;
2295
2296 if (visitedList.count(vertexBlock.name) > 0)
2297 continue;
2298
2299 defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
2300 visitedList.insert(vertexBlock.name);
2301 }
2302
2303 const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
2304
2305 for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
2306 {
2307 // Only 'packed' blocks are allowed to be considered inacive.
2308 if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
2309 continue;
2310
2311 if (visitedList.count(fragmentBlock.name) > 0)
2312 {
2313 for (gl::UniformBlock &block : mData.mUniformBlocks)
2314 {
2315 if (block.name == fragmentBlock.name)
2316 {
2317 block.fragmentStaticUse = fragmentBlock.staticUse;
2318 }
2319 }
2320
2321 continue;
2322 }
2323
2324 defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
2325 visitedList.insert(fragmentBlock.name);
2326 }
2327}
2328
Jamie Madill4a3c2342015-10-08 12:58:45 -04002329template <typename VarT>
2330void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
2331 const std::string &prefix,
2332 int blockIndex)
2333{
2334 for (const VarT &field : fields)
2335 {
2336 const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
2337
2338 if (field.isStruct())
2339 {
2340 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
2341 {
2342 const std::string uniformElementName =
2343 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
2344 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
2345 }
2346 }
2347 else
2348 {
2349 // If getBlockMemberInfo returns false, the uniform is optimized out.
2350 sh::BlockMemberInfo memberInfo;
2351 if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
2352 {
2353 continue;
2354 }
2355
2356 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
2357 blockIndex, memberInfo);
2358
2359 // Since block uniforms have no location, we don't need to store them in the uniform
2360 // locations list.
2361 mData.mUniforms.push_back(newUniform);
2362 }
2363 }
2364}
2365
Jamie Madill62d31cb2015-09-11 13:25:51 -04002366void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
2367{
Jamie Madill4a3c2342015-10-08 12:58:45 -04002368 int blockIndex = static_cast<int>(mData.mUniformBlocks.size());
2369 size_t blockSize = 0;
2370
2371 // Don't define this block at all if it's not active in the implementation.
2372 if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
2373 {
2374 return;
2375 }
2376
2377 // Track the first and last uniform index to determine the range of active uniforms in the
2378 // block.
Jamie Madill62d31cb2015-09-11 13:25:51 -04002379 size_t firstBlockUniformIndex = mData.mUniforms.size();
Jamie Madill4a3c2342015-10-08 12:58:45 -04002380 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002381 size_t lastBlockUniformIndex = mData.mUniforms.size();
2382
2383 std::vector<unsigned int> blockUniformIndexes;
2384 for (size_t blockUniformIndex = firstBlockUniformIndex;
2385 blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
2386 {
2387 blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
2388 }
2389
2390 if (interfaceBlock.arraySize > 0)
2391 {
2392 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
2393 {
2394 UniformBlock block(interfaceBlock.name, true, arrayElement);
2395 block.memberUniformIndexes = blockUniformIndexes;
2396
2397 if (shaderType == GL_VERTEX_SHADER)
2398 {
2399 block.vertexStaticUse = interfaceBlock.staticUse;
2400 }
2401 else
2402 {
2403 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2404 block.fragmentStaticUse = interfaceBlock.staticUse;
2405 }
2406
Jamie Madill4a3c2342015-10-08 12:58:45 -04002407 // TODO(jmadill): Determine if we can ever have an inactive array element block.
2408 size_t blockElementSize = 0;
2409 if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
2410 {
2411 continue;
2412 }
2413
2414 ASSERT(blockElementSize == blockSize);
2415 block.dataSize = static_cast<unsigned int>(blockElementSize);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002416 mData.mUniformBlocks.push_back(block);
2417 }
2418 }
2419 else
2420 {
2421 UniformBlock block(interfaceBlock.name, false, 0);
2422 block.memberUniformIndexes = blockUniformIndexes;
2423
2424 if (shaderType == GL_VERTEX_SHADER)
2425 {
2426 block.vertexStaticUse = interfaceBlock.staticUse;
2427 }
2428 else
2429 {
2430 ASSERT(shaderType == GL_FRAGMENT_SHADER);
2431 block.fragmentStaticUse = interfaceBlock.staticUse;
2432 }
2433
Jamie Madill4a3c2342015-10-08 12:58:45 -04002434 block.dataSize = static_cast<unsigned int>(blockSize);
Jamie Madill62d31cb2015-09-11 13:25:51 -04002435 mData.mUniformBlocks.push_back(block);
2436 }
2437}
2438
2439template <typename T>
2440void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
2441{
2442 const VariableLocation &locationInfo = mData.mUniformLocations[location];
2443 LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
2444 uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
2445
2446 if (VariableComponentType(linkedUniform->type) == GL_BOOL)
2447 {
2448 // Do a cast conversion for boolean types. From the spec:
2449 // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
2450 GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
2451 for (GLsizei component = 0; component < count; ++component)
2452 {
2453 destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
2454 }
2455 }
2456 else
2457 {
Jamie Madill3d3d2f22015-09-23 16:47:51 -04002458 // Invalide the validation cache if we modify the sampler data.
2459 if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
2460 {
2461 mCachedValidateSamplersResult.reset();
2462 }
2463
Jamie Madill62d31cb2015-09-11 13:25:51 -04002464 memcpy(destPointer, v, sizeof(T) * count);
2465 }
2466}
2467
2468template <size_t cols, size_t rows, typename T>
2469void Program::setMatrixUniformInternal(GLint location,
2470 GLsizei count,
2471 GLboolean transpose,
2472 const T *v)
2473{
2474 if (!transpose)
2475 {
2476 setUniformInternal(location, count * cols * rows, v);
2477 return;
2478 }
2479
2480 // Perform a transposing copy.
2481 const VariableLocation &locationInfo = mData.mUniformLocations[location];
2482 LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
2483 T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
2484 for (GLsizei element = 0; element < count; ++element)
2485 {
2486 size_t elementOffset = element * rows * cols;
2487
2488 for (size_t row = 0; row < rows; ++row)
2489 {
2490 for (size_t col = 0; col < cols; ++col)
2491 {
2492 destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
2493 }
2494 }
2495 }
2496}
2497
2498template <typename DestT>
2499void Program::getUniformInternal(GLint location, DestT *dataOut) const
2500{
2501 const VariableLocation &locationInfo = mData.mUniformLocations[location];
2502 const LinkedUniform &uniform = mData.mUniforms[locationInfo.index];
2503
2504 const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
2505
2506 GLenum componentType = VariableComponentType(uniform.type);
2507 if (componentType == GLTypeToGLenum<DestT>::value)
2508 {
2509 memcpy(dataOut, srcPointer, uniform.getElementSize());
2510 return;
2511 }
2512
2513 int components = VariableComponentCount(uniform.type) * uniform.elementCount();
2514
2515 switch (componentType)
2516 {
2517 case GL_INT:
2518 UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
2519 break;
2520 case GL_UNSIGNED_INT:
2521 UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
2522 break;
2523 case GL_BOOL:
2524 UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
2525 break;
2526 case GL_FLOAT:
2527 UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
2528 break;
2529 default:
2530 UNREACHABLE();
2531 }
2532}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002533}