blob: 690088873acc500fc44122519abd411a581eb507 [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
14#include "common/debug.h"
15#include "common/platform.h"
16#include "common/utilities.h"
17#include "common/version.h"
18#include "compiler/translator/blocklayout.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050019#include "libANGLE/Data.h"
Jamie Madill437d2662014-12-05 14:23:35 -050020#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/features.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/renderer/Renderer.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050023#include "libANGLE/renderer/ProgramImpl.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025namespace gl
26{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000027const char * const g_fakepath = "C:\\fakepath";
28
Geoff Lang7dd2e102014-11-10 15:19:26 -050029namespace
30{
31
32unsigned int ParseAndStripArrayIndex(std::string* name)
33{
34 unsigned int subscript = GL_INVALID_INDEX;
35
36 // Strip any trailing array operator and retrieve the subscript
37 size_t open = name->find_last_of('[');
38 size_t close = name->find_last_of(']');
39 if (open != std::string::npos && close == name->length() - 1)
40 {
41 subscript = atoi(name->substr(open + 1).c_str());
42 name->erase(open);
43 }
44
45 return subscript;
46}
47
48}
49
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000050AttributeBindings::AttributeBindings()
51{
52}
53
54AttributeBindings::~AttributeBindings()
55{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000056}
57
Jamie Madill71c3b2c2015-05-07 11:49:20 -040058InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000059{
60}
61
62InfoLog::~InfoLog()
63{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000064}
65
Jamie Madill71c3b2c2015-05-07 11:49:20 -040066size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000067{
Jamie Madill71c3b2c2015-05-07 11:49:20 -040068 const std::string &logString = mStream.str();
69 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000070}
71
72void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
73{
Jamie Madill71c3b2c2015-05-07 11:49:20 -040074 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000075
76 if (bufSize > 0)
77 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040078 const std::string str(mStream.str());
79
80 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000081 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040082 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
83 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000084 }
85
86 infoLog[index] = '\0';
87 }
88
89 if (length)
90 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040091 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000092 }
93}
94
95// append a santized message to the program info log.
96// The D3D compiler includes a fake file path in some of the warning or error
97// messages, so lets remove all occurrences of this fake file path from the log.
98void InfoLog::appendSanitized(const char *message)
99{
100 std::string msg(message);
101
102 size_t found;
103 do
104 {
105 found = msg.find(g_fakepath);
106 if (found != std::string::npos)
107 {
108 msg.erase(found, strlen(g_fakepath));
109 }
110 }
111 while (found != std::string::npos);
112
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400113 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000114}
115
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000116void InfoLog::reset()
117{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000118}
119
Geoff Lang7dd2e102014-11-10 15:19:26 -0500120VariableLocation::VariableLocation()
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400121 : name(),
122 element(0),
123 index(0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000124{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500125}
126
127VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400128 : name(name),
129 element(element),
130 index(index)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500131{
132}
133
134LinkedVarying::LinkedVarying()
135{
136}
137
138LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
139 unsigned int semanticIndex, unsigned int semanticIndexCount)
140 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
141{
142}
143
144Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
145 : mProgram(impl),
146 mValidated(false),
Geoff Langce5d66e2015-01-07 14:06:12 -0500147 mTransformFeedbackVaryings(),
148 mTransformFeedbackBufferMode(GL_NONE),
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400149 mFragmentShader(nullptr),
150 mVertexShader(nullptr),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500151 mLinked(false),
152 mDeleteStatus(false),
153 mRefCount(0),
154 mResourceManager(manager),
155 mHandle(handle)
156{
157 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000158
159 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500160 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161}
162
163Program::~Program()
164{
165 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000166
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400167 if (mVertexShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000168 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000169 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000170 }
171
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400172 if (mFragmentShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000173 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000174 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000175 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500176
177 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178}
179
180bool Program::attachShader(Shader *shader)
181{
182 if (shader->getType() == GL_VERTEX_SHADER)
183 {
184 if (mVertexShader)
185 {
186 return false;
187 }
188
Brandon Jones71620962014-08-20 14:04:59 -0700189 mVertexShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000190 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191 }
192 else if (shader->getType() == GL_FRAGMENT_SHADER)
193 {
194 if (mFragmentShader)
195 {
196 return false;
197 }
198
Brandon Jones71620962014-08-20 14:04:59 -0700199 mFragmentShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000200 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 }
202 else UNREACHABLE();
203
204 return true;
205}
206
207bool Program::detachShader(Shader *shader)
208{
209 if (shader->getType() == GL_VERTEX_SHADER)
210 {
211 if (mVertexShader != shader)
212 {
213 return false;
214 }
215
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000216 mVertexShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400217 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000218 }
219 else if (shader->getType() == GL_FRAGMENT_SHADER)
220 {
221 if (mFragmentShader != shader)
222 {
223 return false;
224 }
225
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000226 mFragmentShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400227 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228 }
229 else UNREACHABLE();
230
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231 return true;
232}
233
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000234int Program::getAttachedShadersCount() const
235{
236 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
237}
238
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000239void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
240{
241 if (index < MAX_VERTEX_ATTRIBS)
242 {
243 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
244 {
245 mAttributeBinding[i].erase(name);
246 }
247
248 mAttributeBinding[index].insert(name);
249 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000250}
251
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252void Program::bindAttributeLocation(GLuint index, const char *name)
253{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000254 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255}
256
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
258// compiling them into binaries, determining the attribute mappings, and collecting
259// a list of uniforms
Jamie Madillde8892b2014-11-11 13:00:22 -0500260Error Program::link(const Data &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000261{
262 unlink(false);
263
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000264 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000265 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000266
Geoff Lang7dd2e102014-11-10 15:19:26 -0500267 if (!mFragmentShader || !mFragmentShader->isCompiled())
268 {
269 return Error(GL_NO_ERROR);
270 }
271 ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
272
273 if (!mVertexShader || !mVertexShader->isCompiled())
274 {
275 return Error(GL_NO_ERROR);
276 }
277 ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
278
Jamie Madill3da79b72015-04-27 11:09:17 -0400279 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500280 {
281 return Error(GL_NO_ERROR);
282 }
283
Geoff Lang7dd2e102014-11-10 15:19:26 -0500284 int registers;
285 std::vector<LinkedVarying> linkedVaryings;
286 rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
287 &registers, &linkedVaryings, &mOutputVariables);
288 if (result.error.isError() || !result.linkSuccess)
Geoff Langb543aff2014-09-30 14:52:54 -0400289 {
290 return result.error;
291 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000292
Geoff Lang7dd2e102014-11-10 15:19:26 -0500293 if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
294 {
295 return Error(GL_NO_ERROR);
296 }
297
298 if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
299 {
300 return Error(GL_NO_ERROR);
301 }
302
303 if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
304 mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
305 {
306 return Error(GL_NO_ERROR);
307 }
308
309 // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
310 // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
311 result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers);
312 if (result.error.isError() || !result.linkSuccess)
313 {
Jamie Madillf6113162015-05-07 11:49:21 -0400314 mInfoLog << "Failed to create D3D shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500315 unlink(false);
316 return result.error;
317 }
318
319 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400320 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000321}
322
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000323int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000324{
325 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
326 {
327 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
328 {
329 return location;
330 }
331 }
332
333 return -1;
334}
335
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000336// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337void Program::unlink(bool destroy)
338{
339 if (destroy) // Object being destructed
340 {
341 if (mFragmentShader)
342 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000343 mFragmentShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400344 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 }
346
347 if (mVertexShader)
348 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000349 mVertexShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400350 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 }
353
Geoff Lang7dd2e102014-11-10 15:19:26 -0500354 std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500355 mOutputVariables.clear();
356
357 mProgram->reset();
358
359 mValidated = false;
360
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000361 mLinked = false;
362}
363
364bool Program::isLinked()
365{
366 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367}
368
Geoff Lang7dd2e102014-11-10 15:19:26 -0500369Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000370{
371 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000372
Geoff Lang7dd2e102014-11-10 15:19:26 -0500373#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
374 return Error(GL_NO_ERROR);
375#else
376 ASSERT(binaryFormat == mProgram->getBinaryFormat());
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000377
Geoff Lang7dd2e102014-11-10 15:19:26 -0500378 BinaryInputStream stream(binary, length);
379
380 GLenum format = stream.readInt<GLenum>();
381 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000382 {
Jamie Madillf6113162015-05-07 11:49:21 -0400383 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500384 return Error(GL_NO_ERROR);
385 }
386
387 int majorVersion = stream.readInt<int>();
388 int minorVersion = stream.readInt<int>();
389 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
390 {
Jamie Madillf6113162015-05-07 11:49:21 -0400391 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500392 return Error(GL_NO_ERROR);
393 }
394
395 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
396 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
397 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
398 {
Jamie Madillf6113162015-05-07 11:49:21 -0400399 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500400 return Error(GL_NO_ERROR);
401 }
402
Jamie Madill3da79b72015-04-27 11:09:17 -0400403 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500404 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
405 {
406 stream.readInt(&mLinkedAttribute[i].type);
407 stream.readString(&mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500408 stream.readInt(&mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500409 }
410
Jamie Madill3da79b72015-04-27 11:09:17 -0400411 unsigned int attribCount = stream.readInt<unsigned int>();
412 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
413 {
414 GLenum type = stream.readInt<GLenum>();
415 GLenum precision = stream.readInt<GLenum>();
416 std::string name = stream.readString();
417 GLint arraySize = stream.readInt<GLint>();
418 int location = stream.readInt<int>();
419 mProgram->setShaderAttribute(attribIndex, type, precision, name, arraySize, location);
420 }
421
Geoff Lang7dd2e102014-11-10 15:19:26 -0500422 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
423 if (result.error.isError() || !result.linkSuccess)
424 {
Geoff Langb543aff2014-09-30 14:52:54 -0400425 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000426 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000427
Geoff Lang7dd2e102014-11-10 15:19:26 -0500428 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400429 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500430#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
431}
432
433Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
434{
435 if (binaryFormat)
436 {
437 *binaryFormat = mProgram->getBinaryFormat();
438 }
439
440 BinaryOutputStream stream;
441
442 stream.writeInt(mProgram->getBinaryFormat());
443 stream.writeInt(ANGLE_MAJOR_VERSION);
444 stream.writeInt(ANGLE_MINOR_VERSION);
445 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
446
Jamie Madill3da79b72015-04-27 11:09:17 -0400447 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500448 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
449 {
450 stream.writeInt(mLinkedAttribute[i].type);
451 stream.writeString(mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500452 stream.writeInt(mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500453 }
454
Jamie Madill3da79b72015-04-27 11:09:17 -0400455 const auto &shaderAttributes = mProgram->getShaderAttributes();
456 stream.writeInt(shaderAttributes.size());
457 for (const auto &attrib : shaderAttributes)
458 {
459 stream.writeInt(attrib.type);
460 stream.writeInt(attrib.precision);
461 stream.writeString(attrib.name);
462 stream.writeInt(attrib.arraySize);
463 stream.writeInt(attrib.location);
464 }
465
Geoff Lang7dd2e102014-11-10 15:19:26 -0500466 gl::Error error = mProgram->save(&stream);
467 if (error.isError())
468 {
469 return error;
470 }
471
472 GLsizei streamLength = stream.length();
473 const void *streamData = stream.data();
474
475 if (streamLength > bufSize)
476 {
477 if (length)
478 {
479 *length = 0;
480 }
481
482 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
483 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
484 // sizes and then copy it.
485 return Error(GL_INVALID_OPERATION);
486 }
487
488 if (binary)
489 {
490 char *ptr = reinterpret_cast<char*>(binary);
491
492 memcpy(ptr, streamData, streamLength);
493 ptr += streamLength;
494
495 ASSERT(ptr - streamLength == binary);
496 }
497
498 if (length)
499 {
500 *length = streamLength;
501 }
502
503 return Error(GL_NO_ERROR);
504}
505
506GLint Program::getBinaryLength() const
507{
508 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400509 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500510 if (error.isError())
511 {
512 return 0;
513 }
514
515 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000516}
517
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000518void Program::release()
519{
520 mRefCount--;
521
522 if (mRefCount == 0 && mDeleteStatus)
523 {
524 mResourceManager->deleteProgram(mHandle);
525 }
526}
527
528void Program::addRef()
529{
530 mRefCount++;
531}
532
533unsigned int Program::getRefCount() const
534{
535 return mRefCount;
536}
537
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000538int Program::getInfoLogLength() const
539{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400540 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000541}
542
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000543void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
544{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000545 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000546}
547
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000548void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
549{
550 int total = 0;
551
552 if (mVertexShader)
553 {
554 if (total < maxCount)
555 {
556 shaders[total] = mVertexShader->getHandle();
557 }
558
559 total++;
560 }
561
562 if (mFragmentShader)
563 {
564 if (total < maxCount)
565 {
566 shaders[total] = mFragmentShader->getHandle();
567 }
568
569 total++;
570 }
571
572 if (count)
573 {
574 *count = total;
575 }
576}
577
Geoff Lang7dd2e102014-11-10 15:19:26 -0500578GLuint Program::getAttributeLocation(const std::string &name)
579{
580 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
581 {
582 if (mLinkedAttribute[index].name == name)
583 {
584 return index;
585 }
586 }
587
Austin Kinrossb8af7232015-03-16 22:33:25 -0700588 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500589}
590
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400591const int *Program::getSemanticIndexes() const
592{
593 return mProgram->getSemanticIndexes();
594}
595
Geoff Lang7dd2e102014-11-10 15:19:26 -0500596int Program::getSemanticIndex(int attributeIndex)
597{
598 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
599
Jamie Madill437d2662014-12-05 14:23:35 -0500600 return mProgram->getSemanticIndexes()[attributeIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500601}
602
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000603void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
604{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500605 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000606 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500607 // Skip over inactive attributes
608 unsigned int activeAttribute = 0;
609 unsigned int attribute;
610 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
611 {
612 if (mLinkedAttribute[attribute].name.empty())
613 {
614 continue;
615 }
616
617 if (activeAttribute == index)
618 {
619 break;
620 }
621
622 activeAttribute++;
623 }
624
625 if (bufsize > 0)
626 {
627 const char *string = mLinkedAttribute[attribute].name.c_str();
628
629 strncpy(name, string, bufsize);
630 name[bufsize - 1] = '\0';
631
632 if (length)
633 {
634 *length = strlen(name);
635 }
636 }
637
638 *size = 1; // Always a single 'type' instance
639
640 *type = mLinkedAttribute[attribute].type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000641 }
642 else
643 {
644 if (bufsize > 0)
645 {
646 name[0] = '\0';
647 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500648
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000649 if (length)
650 {
651 *length = 0;
652 }
653
654 *type = GL_NONE;
655 *size = 1;
656 }
657}
658
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000659GLint Program::getActiveAttributeCount()
660{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500661 int count = 0;
662
663 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000664 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500665 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
666 {
667 if (!mLinkedAttribute[attributeIndex].name.empty())
668 {
669 count++;
670 }
671 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000672 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500673
674 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000675}
676
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000677GLint Program::getActiveAttributeMaxLength()
678{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500679 int maxLength = 0;
680
681 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000682 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500683 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
684 {
685 if (!mLinkedAttribute[attributeIndex].name.empty())
686 {
687 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
688 }
689 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000690 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500691
692 return maxLength;
693}
694
695// Returns one more than the highest sampler index used.
696GLint Program::getUsedSamplerRange(SamplerType type)
697{
698 return mProgram->getUsedSamplerRange(type);
699}
700
701bool Program::usesPointSize() const
702{
703 return mProgram->usesPointSize();
704}
705
706GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
707{
708 return mProgram->getSamplerMapping(type, samplerIndex, caps);
709}
710
711GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
712{
713 return mProgram->getSamplerTextureType(type, samplerIndex);
714}
715
716GLint Program::getFragDataLocation(const std::string &name) const
717{
718 std::string baseName(name);
719 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
720 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000721 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500722 const VariableLocation &outputVariable = locationIt->second;
723 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
724 {
725 return static_cast<GLint>(locationIt->first);
726 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000727 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500728 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000729}
730
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000731void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
732{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500733 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000734 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500735 ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
736 LinkedUniform *uniform = mProgram->getUniforms()[index];
737
738 if (bufsize > 0)
739 {
740 std::string string = uniform->name;
741 if (uniform->isArray())
742 {
743 string += "[0]";
744 }
745
746 strncpy(name, string.c_str(), bufsize);
747 name[bufsize - 1] = '\0';
748
749 if (length)
750 {
751 *length = strlen(name);
752 }
753 }
754
755 *size = uniform->elementCount();
756 *type = uniform->type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000757 }
758 else
759 {
760 if (bufsize > 0)
761 {
762 name[0] = '\0';
763 }
764
765 if (length)
766 {
767 *length = 0;
768 }
769
770 *size = 0;
771 *type = GL_NONE;
772 }
773}
774
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000775GLint Program::getActiveUniformCount()
776{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500777 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000778 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500779 return mProgram->getUniforms().size();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000780 }
781 else
782 {
783 return 0;
784 }
785}
786
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000787GLint Program::getActiveUniformMaxLength()
788{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500789 int maxLength = 0;
790
791 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000792 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500793 unsigned int numUniforms = mProgram->getUniforms().size();
794 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
795 {
796 if (!mProgram->getUniforms()[uniformIndex]->name.empty())
797 {
798 int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
799 if (mProgram->getUniforms()[uniformIndex]->isArray())
800 {
801 length += 3; // Counting in "[0]".
802 }
803 maxLength = std::max(length, maxLength);
804 }
805 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000806 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500807
808 return maxLength;
809}
810
811GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
812{
813 const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
814 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000815 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500816 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
817 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
818 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
819 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
820 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
821 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
822 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
823 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
824 default:
825 UNREACHABLE();
826 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000827 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500828 return 0;
829}
830
831bool Program::isValidUniformLocation(GLint location) const
832{
833 ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
834 return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
835}
836
837LinkedUniform *Program::getUniformByLocation(GLint location) const
838{
839 return mProgram->getUniformByLocation(location);
840}
841
842LinkedUniform *Program::getUniformByName(const std::string &name) const
843{
844 return mProgram->getUniformByName(name);
845}
846
847GLint Program::getUniformLocation(const std::string &name)
848{
849 return mProgram->getUniformLocation(name);
850}
851
852GLuint Program::getUniformIndex(const std::string &name)
853{
854 return mProgram->getUniformIndex(name);
855}
856
857void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
858{
859 mProgram->setUniform1fv(location, count, v);
860}
861
862void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
863{
864 mProgram->setUniform2fv(location, count, v);
865}
866
867void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
868{
869 mProgram->setUniform3fv(location, count, v);
870}
871
872void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
873{
874 mProgram->setUniform4fv(location, count, v);
875}
876
877void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
878{
879 mProgram->setUniform1iv(location, count, v);
880}
881
882void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
883{
884 mProgram->setUniform2iv(location, count, v);
885}
886
887void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
888{
889 mProgram->setUniform3iv(location, count, v);
890}
891
892void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
893{
894 mProgram->setUniform4iv(location, count, v);
895}
896
897void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
898{
899 mProgram->setUniform1uiv(location, count, v);
900}
901
902void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
903{
904 mProgram->setUniform2uiv(location, count, v);
905}
906
907void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
908{
909 mProgram->setUniform3uiv(location, count, v);
910}
911
912void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
913{
914 mProgram->setUniform4uiv(location, count, v);
915}
916
917void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
918{
919 mProgram->setUniformMatrix2fv(location, count, transpose, v);
920}
921
922void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
923{
924 mProgram->setUniformMatrix3fv(location, count, transpose, v);
925}
926
927void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
928{
929 mProgram->setUniformMatrix4fv(location, count, transpose, v);
930}
931
932void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
933{
934 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
935}
936
937void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
938{
939 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
940}
941
942void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
943{
944 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
945}
946
947void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
948{
949 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
950}
951
952void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
953{
954 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
955}
956
957void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
958{
959 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
960}
961
962void Program::getUniformfv(GLint location, GLfloat *v)
963{
964 mProgram->getUniformfv(location, v);
965}
966
967void Program::getUniformiv(GLint location, GLint *v)
968{
969 mProgram->getUniformiv(location, v);
970}
971
972void Program::getUniformuiv(GLint location, GLuint *v)
973{
974 mProgram->getUniformuiv(location, v);
975}
976
977// Applies all the uniforms set for this program object to the renderer
978Error Program::applyUniforms()
979{
980 return mProgram->applyUniforms();
981}
982
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +0000983Error Program::applyUniformBuffers(const gl::Data &data)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500984{
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +0000985 return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000986}
987
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000988void Program::flagForDeletion()
989{
990 mDeleteStatus = true;
991}
992
993bool Program::isFlaggedForDeletion() const
994{
995 return mDeleteStatus;
996}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000997
Brandon Jones43a53e22014-08-28 16:23:22 -0700998void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000999{
1000 mInfoLog.reset();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001001 mValidated = false;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001002
Geoff Lang7dd2e102014-11-10 15:19:26 -05001003 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001004 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001005 applyUniforms();
1006 mValidated = mProgram->validateSamplers(&mInfoLog, caps);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001007 }
1008 else
1009 {
Jamie Madillf6113162015-05-07 11:49:21 -04001010 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001011 }
1012}
1013
Geoff Lang7dd2e102014-11-10 15:19:26 -05001014bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1015{
1016 return mProgram->validateSamplers(infoLog, caps);
1017}
1018
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001019bool Program::isValidated() const
1020{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001021 return mValidated;
1022}
1023
1024void Program::updateSamplerMapping()
1025{
1026 return mProgram->updateSamplerMapping();
1027}
1028
1029GLuint Program::getActiveUniformBlockCount()
1030{
1031 return mProgram->getUniformBlocks().size();
1032}
1033
1034void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1035{
1036 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1037
1038 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1039
1040 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001041 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042 std::string string = uniformBlock.name;
1043
1044 if (uniformBlock.isArrayElement())
1045 {
1046 string += ArrayString(uniformBlock.elementIndex);
1047 }
1048
1049 strncpy(uniformBlockName, string.c_str(), bufSize);
1050 uniformBlockName[bufSize - 1] = '\0';
1051
1052 if (length)
1053 {
1054 *length = strlen(uniformBlockName);
1055 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001056 }
1057}
1058
Geoff Lang7dd2e102014-11-10 15:19:26 -05001059void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001060{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001061 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1062
1063 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1064
1065 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001066 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001067 case GL_UNIFORM_BLOCK_DATA_SIZE:
1068 *params = static_cast<GLint>(uniformBlock.dataSize);
1069 break;
1070 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1071 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
1072 break;
1073 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1074 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1075 break;
1076 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1077 {
1078 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1079 {
1080 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1081 }
1082 }
1083 break;
1084 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1085 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
1086 break;
1087 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1088 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
1089 break;
1090 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001091 }
1092}
1093
1094GLint Program::getActiveUniformBlockMaxLength()
1095{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001096 int maxLength = 0;
1097
1098 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001099 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001100 unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
1101 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1102 {
1103 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1104 if (!uniformBlock.name.empty())
1105 {
1106 const int length = uniformBlock.name.length() + 1;
1107
1108 // Counting in "[0]".
1109 const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
1110
1111 maxLength = std::max(length + arrayLength, maxLength);
1112 }
1113 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001114 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001115
1116 return maxLength;
1117}
1118
1119GLuint Program::getUniformBlockIndex(const std::string &name)
1120{
1121 return mProgram->getUniformBlockIndex(name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001122}
1123
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001124const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
1125{
1126 return mProgram->getUniformBlockByIndex(index);
1127}
1128
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001129void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1130{
1131 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
1132}
1133
1134GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1135{
1136 return mUniformBlockBindings[uniformBlockIndex];
1137}
1138
1139void Program::resetUniformBlockBindings()
1140{
1141 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1142 {
1143 mUniformBlockBindings[blockId] = 0;
1144 }
1145}
1146
Geoff Lang48dcae72014-02-05 16:28:24 -05001147void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1148{
1149 mTransformFeedbackVaryings.resize(count);
1150 for (GLsizei i = 0; i < count; i++)
1151 {
1152 mTransformFeedbackVaryings[i] = varyings[i];
1153 }
1154
1155 mTransformFeedbackBufferMode = bufferMode;
1156}
1157
1158void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1159{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001160 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001161 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001162 ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
1163 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001164 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1165 if (length)
1166 {
1167 *length = lastNameIdx;
1168 }
1169 if (size)
1170 {
1171 *size = varying.size;
1172 }
1173 if (type)
1174 {
1175 *type = varying.type;
1176 }
1177 if (name)
1178 {
1179 memcpy(name, varying.name.c_str(), lastNameIdx);
1180 name[lastNameIdx] = '\0';
1181 }
1182 }
1183}
1184
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001185GLsizei Program::getTransformFeedbackVaryingCount() const
1186{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001187 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001188 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001189 return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001190 }
1191 else
1192 {
1193 return 0;
1194 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001195}
1196
1197GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1198{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001199 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001200 {
1201 GLsizei maxSize = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001202 for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001203 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001204 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001205 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1206 }
1207
1208 return maxSize;
1209 }
1210 else
1211 {
1212 return 0;
1213 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001214}
1215
1216GLenum Program::getTransformFeedbackBufferMode() const
1217{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001218 return mTransformFeedbackBufferMode;
1219}
1220
Geoff Lang7dd2e102014-11-10 15:19:26 -05001221bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
1222{
1223 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
1224 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
1225
1226 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
1227 {
1228 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
1229 bool matched = false;
1230
1231 // Built-in varyings obey special rules
1232 if (input->isBuiltIn())
1233 {
1234 continue;
1235 }
1236
1237 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
1238 {
1239 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
1240 if (output->name == input->name)
1241 {
1242 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
1243 {
1244 return false;
1245 }
1246
1247 output->registerIndex = input->registerIndex;
1248 output->columnIndex = input->columnIndex;
1249
1250 matched = true;
1251 break;
1252 }
1253 }
1254
1255 // We permit unmatched, unreferenced varyings
1256 if (!matched && input->staticUse)
1257 {
Jamie Madillf6113162015-05-07 11:49:21 -04001258 infoLog << "Fragment varying " << input->name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001259 return false;
1260 }
1261 }
1262
1263 return true;
1264}
1265
1266bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1267{
1268 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1269 {
1270 return false;
1271 }
1272
1273 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1274 {
Jamie Madillf6113162015-05-07 11:49:21 -04001275 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001276 return false;
1277 }
1278
1279 return true;
1280}
1281
1282// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill3da79b72015-04-27 11:09:17 -04001283bool Program::linkAttributes(const Data &data,
1284 InfoLog &infoLog,
1285 const AttributeBindings &attributeBindings,
1286 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001287{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001288 unsigned int usedLocations = 0;
1289 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001290 GLuint maxAttribs = data.caps->maxVertexAttributes;
1291
1292 // TODO(jmadill): handle aliasing robustly
1293 if (shaderAttributes.size() >= maxAttribs)
1294 {
Jamie Madillf6113162015-05-07 11:49:21 -04001295 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001296 return false;
1297 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001298
1299 // Link attributes that have a binding location
1300 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1301 {
1302 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1303
1304 ASSERT(attribute.staticUse);
1305
1306 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1307
Jamie Madill3da79b72015-04-27 11:09:17 -04001308 mProgram->setShaderAttribute(attributeIndex, attribute);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001309
1310 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
1311 {
1312 const int rows = VariableRegisterCount(attribute.type);
1313
Jamie Madill3da79b72015-04-27 11:09:17 -04001314 if (static_cast<GLuint>(rows + location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001315 {
Jamie Madillf6113162015-05-07 11:49:21 -04001316 infoLog << "Active attribute (" << attribute.name << ") at location "
1317 << location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001318
1319 return false;
1320 }
1321
1322 for (int row = 0; row < rows; row++)
1323 {
1324 const int rowLocation = location + row;
1325 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
1326
1327 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001328 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
1329 // TODO(jmadill): fix aliasing on ES2
1330 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001331 {
1332 if (!linkedAttribute.name.empty())
1333 {
Jamie Madillf6113162015-05-07 11:49:21 -04001334 infoLog << "Attribute '" << attribute.name
1335 << "' aliases attribute '" << linkedAttribute.name
1336 << "' at location " << rowLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001337 return false;
1338 }
1339 }
1340
1341 linkedAttribute = attribute;
1342 usedLocations |= 1 << rowLocation;
1343 }
1344 }
1345 }
1346
1347 // Link attributes that don't have a binding location
1348 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1349 {
1350 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1351
1352 ASSERT(attribute.staticUse);
1353
1354 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1355
1356 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
1357 {
1358 int rows = VariableRegisterCount(attribute.type);
Jamie Madill3da79b72015-04-27 11:09:17 -04001359 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001360
Jamie Madill3da79b72015-04-27 11:09:17 -04001361 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + rows) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001362 {
Jamie Madillf6113162015-05-07 11:49:21 -04001363 infoLog << "Too many active attributes (" << attribute.name << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001364 return false; // Fail to link
1365 }
1366
1367 mLinkedAttribute[availableIndex] = attribute;
1368 }
1369 }
1370
Jamie Madill3da79b72015-04-27 11:09:17 -04001371 for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001372 {
Jamie Madill437d2662014-12-05 14:23:35 -05001373 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001374 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
1375
1376 for (int r = 0; r < rows; r++)
1377 {
Jamie Madill437d2662014-12-05 14:23:35 -05001378 mProgram->getSemanticIndexes()[attributeIndex++] = index++;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001379 }
1380 }
1381
Geoff Lang7dd2e102014-11-10 15:19:26 -05001382 return true;
1383}
1384
1385bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
1386{
1387 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1388 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
1389 // Check that interface blocks defined in the vertex and fragment shaders are identical
1390 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1391 UniformBlockMap linkedUniformBlocks;
1392 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1393 {
1394 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
1395 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
1396 }
1397 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1398 {
1399 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
1400 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
1401 if (entry != linkedUniformBlocks.end())
1402 {
1403 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1404 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1405 {
1406 return false;
1407 }
1408 }
1409 }
1410 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1411 {
1412 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
1413 // Note: shared and std140 layouts are always considered active
1414 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1415 {
1416 if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
1417 {
1418 return false;
1419 }
1420 }
1421 }
1422 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1423 {
1424 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
1425 // Note: shared and std140 layouts are always considered active
1426 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1427 {
1428 if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
1429 {
1430 return false;
1431 }
1432 }
1433 }
1434 return true;
1435}
1436
1437bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1438 const sh::InterfaceBlock &fragmentInterfaceBlock)
1439{
1440 const char* blockName = vertexInterfaceBlock.name.c_str();
1441 // validate blocks for the same member types
1442 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1443 {
Jamie Madillf6113162015-05-07 11:49:21 -04001444 infoLog << "Types for interface block '" << blockName
1445 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001446 return false;
1447 }
1448 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1449 {
Jamie Madillf6113162015-05-07 11:49:21 -04001450 infoLog << "Array sizes differ for interface block '" << blockName
1451 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001452 return false;
1453 }
1454 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1455 {
Jamie Madillf6113162015-05-07 11:49:21 -04001456 infoLog << "Layout qualifiers differ for interface block '" << blockName
1457 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001458 return false;
1459 }
1460 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
1461 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1462 {
1463 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1464 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
1465 if (vertexMember.name != fragmentMember.name)
1466 {
Jamie Madillf6113162015-05-07 11:49:21 -04001467 infoLog << "Name mismatch for field " << blockMemberIndex
1468 << " of interface block '" << blockName
1469 << "': (in vertex: '" << vertexMember.name
1470 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471 return false;
1472 }
1473 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1474 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
1475 {
1476 return false;
1477 }
1478 }
1479 return true;
1480}
1481
1482bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1483 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
1484{
1485 if (vertexVariable.type != fragmentVariable.type)
1486 {
Jamie Madillf6113162015-05-07 11:49:21 -04001487 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001488 return false;
1489 }
1490 if (vertexVariable.arraySize != fragmentVariable.arraySize)
1491 {
Jamie Madillf6113162015-05-07 11:49:21 -04001492 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001493 return false;
1494 }
1495 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
1496 {
Jamie Madillf6113162015-05-07 11:49:21 -04001497 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001498 return false;
1499 }
1500
1501 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
1502 {
Jamie Madillf6113162015-05-07 11:49:21 -04001503 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001504 return false;
1505 }
1506 const unsigned int numMembers = vertexVariable.fields.size();
1507 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1508 {
1509 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1510 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
1511
1512 if (vertexMember.name != fragmentMember.name)
1513 {
Jamie Madillf6113162015-05-07 11:49:21 -04001514 infoLog << "Name mismatch for field '" << memberIndex
1515 << "' of " << variableName
1516 << ": (in vertex: '" << vertexMember.name
1517 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001518 return false;
1519 }
1520
1521 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1522 vertexMember.name + "'";
1523
1524 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
1525 {
1526 return false;
1527 }
1528 }
1529
1530 return true;
1531}
1532
1533bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1534{
1535 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1536 {
1537 return false;
1538 }
1539
1540 return true;
1541}
1542
1543bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1544{
1545 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1546 {
1547 return false;
1548 }
1549
Jamie Madille9cc4692015-02-19 16:00:13 -05001550 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001551 {
Jamie Madillf6113162015-05-07 11:49:21 -04001552 infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001553 return false;
1554 }
1555
1556 return true;
1557}
1558
1559bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
1560 const std::vector<std::string> &transformFeedbackVaryingNames,
1561 GLenum transformFeedbackBufferMode,
1562 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
1563 const Caps &caps) const
1564{
1565 size_t totalComponents = 0;
1566
1567 // Gather the linked varyings that are used for transform feedback, they should all exist.
1568 outTransformFeedbackLinkedVaryings->clear();
1569 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
1570 {
1571 bool found = false;
1572 for (size_t j = 0; j < linkedVaryings.size(); j++)
1573 {
1574 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
1575 {
1576 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
1577 {
1578 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
1579 {
Jamie Madillf6113162015-05-07 11:49:21 -04001580 infoLog << "Two transform feedback varyings specify the same output variable ("
1581 << linkedVaryings[j].name << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001582 return false;
1583 }
1584 }
1585
1586 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
1587 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1588 componentCount > caps.maxTransformFeedbackSeparateComponents)
1589 {
Jamie Madillf6113162015-05-07 11:49:21 -04001590 infoLog << "Transform feedback varying's " << linkedVaryings[j].name
1591 << " components (" << componentCount
1592 << ") exceed the maximum separate components ("
1593 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001594 return false;
1595 }
1596
1597 totalComponents += componentCount;
1598
1599 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
1600 found = true;
1601 break;
1602 }
1603 }
1604
1605 // All transform feedback varyings are expected to exist since packVaryings checks for them.
1606 ASSERT(found);
1607 }
1608
Jamie Madillf6113162015-05-07 11:49:21 -04001609 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
1610 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001611 {
Jamie Madillf6113162015-05-07 11:49:21 -04001612 infoLog << "Transform feedback varying total components (" << totalComponents
1613 << ") exceed the maximum interleaved components ("
1614 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001615 return false;
1616 }
1617
1618 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001619}
1620
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621}