blob: e215379d432e066a729fef56d40f904e88f08357 [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 Madill8ae74e12015-05-04 10:34:15 -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 Madill8ae74e12015-05-04 10:34:15 -040066size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000067{
Jamie Madill8ae74e12015-05-04 10:34:15 -040068 return mStream.str().length();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000069}
70
71void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
72{
Jamie Madill8ae74e12015-05-04 10:34:15 -040073 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000074
75 if (bufSize > 0)
76 {
Jamie Madill8ae74e12015-05-04 10:34:15 -040077 const std::string str(mStream.str());
78
79 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000080 {
Jamie Madill8ae74e12015-05-04 10:34:15 -040081 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
82 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000083 }
84
85 infoLog[index] = '\0';
86 }
87
88 if (length)
89 {
Jamie Madill8ae74e12015-05-04 10:34:15 -040090 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000091 }
92}
93
94// append a santized message to the program info log.
95// The D3D compiler includes a fake file path in some of the warning or error
96// messages, so lets remove all occurrences of this fake file path from the log.
97void InfoLog::appendSanitized(const char *message)
98{
99 std::string msg(message);
100
101 size_t found;
102 do
103 {
104 found = msg.find(g_fakepath);
105 if (found != std::string::npos)
106 {
107 msg.erase(found, strlen(g_fakepath));
108 }
109 }
110 while (found != std::string::npos);
111
Jamie Madill8ae74e12015-05-04 10:34:15 -0400112 mStream << message << "\n";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000113}
114
115void InfoLog::append(const char *format, ...)
116{
117 if (!format)
118 {
119 return;
120 }
121
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000122 va_list vararg;
123 va_start(vararg, format);
Jamie Madill8ae74e12015-05-04 10:34:15 -0400124 std::string tempString(FormatString(format, vararg));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000125 va_end(vararg);
126
Jamie Madill8ae74e12015-05-04 10:34:15 -0400127 mStream << tempString << "\n";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000128}
129
130void InfoLog::reset()
131{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000132}
133
Geoff Lang7dd2e102014-11-10 15:19:26 -0500134VariableLocation::VariableLocation()
Jamie Madill8ae74e12015-05-04 10:34:15 -0400135 : name(),
136 element(0),
137 index(0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000138{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500139}
140
141VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
Jamie Madill8ae74e12015-05-04 10:34:15 -0400142 : name(name),
143 element(element),
144 index(index)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500145{
146}
147
148LinkedVarying::LinkedVarying()
149{
150}
151
152LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
153 unsigned int semanticIndex, unsigned int semanticIndexCount)
154 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
155{
156}
157
158Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
159 : mProgram(impl),
160 mValidated(false),
Geoff Langce5d66e2015-01-07 14:06:12 -0500161 mTransformFeedbackVaryings(),
162 mTransformFeedbackBufferMode(GL_NONE),
Jamie Madill8ae74e12015-05-04 10:34:15 -0400163 mFragmentShader(nullptr),
164 mVertexShader(nullptr),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500165 mLinked(false),
166 mDeleteStatus(false),
167 mRefCount(0),
168 mResourceManager(manager),
169 mHandle(handle)
170{
171 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000172
173 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500174 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175}
176
177Program::~Program()
178{
179 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000180
Jamie Madill8ae74e12015-05-04 10:34:15 -0400181 if (mVertexShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000182 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000183 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000184 }
185
Jamie Madill8ae74e12015-05-04 10:34:15 -0400186 if (mFragmentShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000187 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000188 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000189 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500190
191 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192}
193
194bool Program::attachShader(Shader *shader)
195{
196 if (shader->getType() == GL_VERTEX_SHADER)
197 {
198 if (mVertexShader)
199 {
200 return false;
201 }
202
Brandon Jones71620962014-08-20 14:04:59 -0700203 mVertexShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000204 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205 }
206 else if (shader->getType() == GL_FRAGMENT_SHADER)
207 {
208 if (mFragmentShader)
209 {
210 return false;
211 }
212
Brandon Jones71620962014-08-20 14:04:59 -0700213 mFragmentShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000214 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 }
216 else UNREACHABLE();
217
218 return true;
219}
220
221bool Program::detachShader(Shader *shader)
222{
223 if (shader->getType() == GL_VERTEX_SHADER)
224 {
225 if (mVertexShader != shader)
226 {
227 return false;
228 }
229
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000230 mVertexShader->release();
Jamie Madill8ae74e12015-05-04 10:34:15 -0400231 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232 }
233 else if (shader->getType() == GL_FRAGMENT_SHADER)
234 {
235 if (mFragmentShader != shader)
236 {
237 return false;
238 }
239
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000240 mFragmentShader->release();
Jamie Madill8ae74e12015-05-04 10:34:15 -0400241 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242 }
243 else UNREACHABLE();
244
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245 return true;
246}
247
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000248int Program::getAttachedShadersCount() const
249{
250 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
251}
252
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000253void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
254{
255 if (index < MAX_VERTEX_ATTRIBS)
256 {
257 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
258 {
259 mAttributeBinding[i].erase(name);
260 }
261
262 mAttributeBinding[index].insert(name);
263 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000264}
265
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266void Program::bindAttributeLocation(GLuint index, const char *name)
267{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000268 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269}
270
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
272// compiling them into binaries, determining the attribute mappings, and collecting
273// a list of uniforms
Jamie Madillde8892b2014-11-11 13:00:22 -0500274Error Program::link(const Data &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000275{
276 unlink(false);
277
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000278 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000279 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000280
Geoff Lang7dd2e102014-11-10 15:19:26 -0500281 if (!mFragmentShader || !mFragmentShader->isCompiled())
282 {
283 return Error(GL_NO_ERROR);
284 }
285 ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
286
287 if (!mVertexShader || !mVertexShader->isCompiled())
288 {
289 return Error(GL_NO_ERROR);
290 }
291 ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
292
Jamie Madill3da79b72015-04-27 11:09:17 -0400293 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500294 {
295 return Error(GL_NO_ERROR);
296 }
297
Geoff Lang7dd2e102014-11-10 15:19:26 -0500298 int registers;
299 std::vector<LinkedVarying> linkedVaryings;
300 rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
301 &registers, &linkedVaryings, &mOutputVariables);
302 if (result.error.isError() || !result.linkSuccess)
Geoff Langb543aff2014-09-30 14:52:54 -0400303 {
304 return result.error;
305 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000306
Geoff Lang7dd2e102014-11-10 15:19:26 -0500307 if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
308 {
309 return Error(GL_NO_ERROR);
310 }
311
312 if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
313 {
314 return Error(GL_NO_ERROR);
315 }
316
317 if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
318 mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
319 {
320 return Error(GL_NO_ERROR);
321 }
322
323 // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
324 // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
325 result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers);
326 if (result.error.isError() || !result.linkSuccess)
327 {
328 mInfoLog.append("Failed to create D3D shaders.");
329 unlink(false);
330 return result.error;
331 }
332
333 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400334 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000335}
336
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000337int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000338{
339 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
340 {
341 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
342 {
343 return location;
344 }
345 }
346
347 return -1;
348}
349
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000350// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351void Program::unlink(bool destroy)
352{
353 if (destroy) // Object being destructed
354 {
355 if (mFragmentShader)
356 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000357 mFragmentShader->release();
Jamie Madill8ae74e12015-05-04 10:34:15 -0400358 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359 }
360
361 if (mVertexShader)
362 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000363 mVertexShader->release();
Jamie Madill8ae74e12015-05-04 10:34:15 -0400364 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366 }
367
Geoff Lang7dd2e102014-11-10 15:19:26 -0500368 std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500369 mOutputVariables.clear();
370
371 mProgram->reset();
372
373 mValidated = false;
374
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000375 mLinked = false;
376}
377
378bool Program::isLinked()
379{
380 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381}
382
Geoff Lang7dd2e102014-11-10 15:19:26 -0500383Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000384{
385 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000386
Geoff Lang7dd2e102014-11-10 15:19:26 -0500387#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
388 return Error(GL_NO_ERROR);
389#else
390 ASSERT(binaryFormat == mProgram->getBinaryFormat());
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000391
Geoff Lang7dd2e102014-11-10 15:19:26 -0500392 BinaryInputStream stream(binary, length);
393
394 GLenum format = stream.readInt<GLenum>();
395 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000396 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500397 mInfoLog.append("Invalid program binary format.");
398 return Error(GL_NO_ERROR);
399 }
400
401 int majorVersion = stream.readInt<int>();
402 int minorVersion = stream.readInt<int>();
403 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
404 {
405 mInfoLog.append("Invalid program binary version.");
406 return Error(GL_NO_ERROR);
407 }
408
409 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
410 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
411 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
412 {
413 mInfoLog.append("Invalid program binary version.");
414 return Error(GL_NO_ERROR);
415 }
416
Jamie Madill3da79b72015-04-27 11:09:17 -0400417 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500418 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
419 {
420 stream.readInt(&mLinkedAttribute[i].type);
421 stream.readString(&mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500422 stream.readInt(&mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500423 }
424
Jamie Madill3da79b72015-04-27 11:09:17 -0400425 unsigned int attribCount = stream.readInt<unsigned int>();
426 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
427 {
428 GLenum type = stream.readInt<GLenum>();
429 GLenum precision = stream.readInt<GLenum>();
430 std::string name = stream.readString();
431 GLint arraySize = stream.readInt<GLint>();
432 int location = stream.readInt<int>();
433 mProgram->setShaderAttribute(attribIndex, type, precision, name, arraySize, location);
434 }
435
Geoff Lang7dd2e102014-11-10 15:19:26 -0500436 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
437 if (result.error.isError() || !result.linkSuccess)
438 {
Geoff Langb543aff2014-09-30 14:52:54 -0400439 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000440 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000441
Geoff Lang7dd2e102014-11-10 15:19:26 -0500442 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400443 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500444#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
445}
446
447Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
448{
449 if (binaryFormat)
450 {
451 *binaryFormat = mProgram->getBinaryFormat();
452 }
453
454 BinaryOutputStream stream;
455
456 stream.writeInt(mProgram->getBinaryFormat());
457 stream.writeInt(ANGLE_MAJOR_VERSION);
458 stream.writeInt(ANGLE_MINOR_VERSION);
459 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
460
Jamie Madill3da79b72015-04-27 11:09:17 -0400461 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500462 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
463 {
464 stream.writeInt(mLinkedAttribute[i].type);
465 stream.writeString(mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500466 stream.writeInt(mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500467 }
468
Jamie Madill3da79b72015-04-27 11:09:17 -0400469 const auto &shaderAttributes = mProgram->getShaderAttributes();
470 stream.writeInt(shaderAttributes.size());
471 for (const auto &attrib : shaderAttributes)
472 {
473 stream.writeInt(attrib.type);
474 stream.writeInt(attrib.precision);
475 stream.writeString(attrib.name);
476 stream.writeInt(attrib.arraySize);
477 stream.writeInt(attrib.location);
478 }
479
Geoff Lang7dd2e102014-11-10 15:19:26 -0500480 gl::Error error = mProgram->save(&stream);
481 if (error.isError())
482 {
483 return error;
484 }
485
486 GLsizei streamLength = stream.length();
487 const void *streamData = stream.data();
488
489 if (streamLength > bufSize)
490 {
491 if (length)
492 {
493 *length = 0;
494 }
495
496 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
497 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
498 // sizes and then copy it.
499 return Error(GL_INVALID_OPERATION);
500 }
501
502 if (binary)
503 {
504 char *ptr = reinterpret_cast<char*>(binary);
505
506 memcpy(ptr, streamData, streamLength);
507 ptr += streamLength;
508
509 ASSERT(ptr - streamLength == binary);
510 }
511
512 if (length)
513 {
514 *length = streamLength;
515 }
516
517 return Error(GL_NO_ERROR);
518}
519
520GLint Program::getBinaryLength() const
521{
522 GLint length;
Jamie Madill8ae74e12015-05-04 10:34:15 -0400523 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500524 if (error.isError())
525 {
526 return 0;
527 }
528
529 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000530}
531
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000532void Program::release()
533{
534 mRefCount--;
535
536 if (mRefCount == 0 && mDeleteStatus)
537 {
538 mResourceManager->deleteProgram(mHandle);
539 }
540}
541
542void Program::addRef()
543{
544 mRefCount++;
545}
546
547unsigned int Program::getRefCount() const
548{
549 return mRefCount;
550}
551
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000552int Program::getInfoLogLength() const
553{
Jamie Madill8ae74e12015-05-04 10:34:15 -0400554 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000555}
556
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000557void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
558{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000559 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000560}
561
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000562void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
563{
564 int total = 0;
565
566 if (mVertexShader)
567 {
568 if (total < maxCount)
569 {
570 shaders[total] = mVertexShader->getHandle();
571 }
572
573 total++;
574 }
575
576 if (mFragmentShader)
577 {
578 if (total < maxCount)
579 {
580 shaders[total] = mFragmentShader->getHandle();
581 }
582
583 total++;
584 }
585
586 if (count)
587 {
588 *count = total;
589 }
590}
591
Geoff Lang7dd2e102014-11-10 15:19:26 -0500592GLuint Program::getAttributeLocation(const std::string &name)
593{
594 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
595 {
596 if (mLinkedAttribute[index].name == name)
597 {
598 return index;
599 }
600 }
601
Austin Kinrossb8af7232015-03-16 22:33:25 -0700602 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500603}
604
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400605const int *Program::getSemanticIndexes() const
606{
607 return mProgram->getSemanticIndexes();
608}
609
Geoff Lang7dd2e102014-11-10 15:19:26 -0500610int Program::getSemanticIndex(int attributeIndex)
611{
612 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
613
Jamie Madill437d2662014-12-05 14:23:35 -0500614 return mProgram->getSemanticIndexes()[attributeIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500615}
616
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000617void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
618{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500619 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000620 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500621 // Skip over inactive attributes
622 unsigned int activeAttribute = 0;
623 unsigned int attribute;
624 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
625 {
626 if (mLinkedAttribute[attribute].name.empty())
627 {
628 continue;
629 }
630
631 if (activeAttribute == index)
632 {
633 break;
634 }
635
636 activeAttribute++;
637 }
638
639 if (bufsize > 0)
640 {
641 const char *string = mLinkedAttribute[attribute].name.c_str();
642
643 strncpy(name, string, bufsize);
644 name[bufsize - 1] = '\0';
645
646 if (length)
647 {
648 *length = strlen(name);
649 }
650 }
651
652 *size = 1; // Always a single 'type' instance
653
654 *type = mLinkedAttribute[attribute].type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000655 }
656 else
657 {
658 if (bufsize > 0)
659 {
660 name[0] = '\0';
661 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500662
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000663 if (length)
664 {
665 *length = 0;
666 }
667
668 *type = GL_NONE;
669 *size = 1;
670 }
671}
672
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000673GLint Program::getActiveAttributeCount()
674{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500675 int count = 0;
676
677 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000678 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500679 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
680 {
681 if (!mLinkedAttribute[attributeIndex].name.empty())
682 {
683 count++;
684 }
685 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000686 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500687
688 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000689}
690
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000691GLint Program::getActiveAttributeMaxLength()
692{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500693 int maxLength = 0;
694
695 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000696 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500697 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
698 {
699 if (!mLinkedAttribute[attributeIndex].name.empty())
700 {
701 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
702 }
703 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000704 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500705
706 return maxLength;
707}
708
709// Returns one more than the highest sampler index used.
710GLint Program::getUsedSamplerRange(SamplerType type)
711{
712 return mProgram->getUsedSamplerRange(type);
713}
714
715bool Program::usesPointSize() const
716{
717 return mProgram->usesPointSize();
718}
719
720GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
721{
722 return mProgram->getSamplerMapping(type, samplerIndex, caps);
723}
724
725GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
726{
727 return mProgram->getSamplerTextureType(type, samplerIndex);
728}
729
730GLint Program::getFragDataLocation(const std::string &name) const
731{
732 std::string baseName(name);
733 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
734 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000735 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500736 const VariableLocation &outputVariable = locationIt->second;
737 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
738 {
739 return static_cast<GLint>(locationIt->first);
740 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000741 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500742 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000743}
744
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000745void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
746{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500747 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000748 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500749 ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
750 LinkedUniform *uniform = mProgram->getUniforms()[index];
751
752 if (bufsize > 0)
753 {
754 std::string string = uniform->name;
755 if (uniform->isArray())
756 {
757 string += "[0]";
758 }
759
760 strncpy(name, string.c_str(), bufsize);
761 name[bufsize - 1] = '\0';
762
763 if (length)
764 {
765 *length = strlen(name);
766 }
767 }
768
769 *size = uniform->elementCount();
770 *type = uniform->type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000771 }
772 else
773 {
774 if (bufsize > 0)
775 {
776 name[0] = '\0';
777 }
778
779 if (length)
780 {
781 *length = 0;
782 }
783
784 *size = 0;
785 *type = GL_NONE;
786 }
787}
788
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000789GLint Program::getActiveUniformCount()
790{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500791 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000792 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500793 return mProgram->getUniforms().size();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000794 }
795 else
796 {
797 return 0;
798 }
799}
800
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000801GLint Program::getActiveUniformMaxLength()
802{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500803 int maxLength = 0;
804
805 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000806 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500807 unsigned int numUniforms = mProgram->getUniforms().size();
808 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
809 {
810 if (!mProgram->getUniforms()[uniformIndex]->name.empty())
811 {
812 int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
813 if (mProgram->getUniforms()[uniformIndex]->isArray())
814 {
815 length += 3; // Counting in "[0]".
816 }
817 maxLength = std::max(length, maxLength);
818 }
819 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000820 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500821
822 return maxLength;
823}
824
825GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
826{
827 const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
828 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000829 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500830 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
831 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
832 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
833 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
834 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
835 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
836 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
837 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
838 default:
839 UNREACHABLE();
840 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000841 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500842 return 0;
843}
844
845bool Program::isValidUniformLocation(GLint location) const
846{
847 ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
848 return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
849}
850
851LinkedUniform *Program::getUniformByLocation(GLint location) const
852{
853 return mProgram->getUniformByLocation(location);
854}
855
856LinkedUniform *Program::getUniformByName(const std::string &name) const
857{
858 return mProgram->getUniformByName(name);
859}
860
861GLint Program::getUniformLocation(const std::string &name)
862{
863 return mProgram->getUniformLocation(name);
864}
865
866GLuint Program::getUniformIndex(const std::string &name)
867{
868 return mProgram->getUniformIndex(name);
869}
870
871void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
872{
873 mProgram->setUniform1fv(location, count, v);
874}
875
876void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
877{
878 mProgram->setUniform2fv(location, count, v);
879}
880
881void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
882{
883 mProgram->setUniform3fv(location, count, v);
884}
885
886void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
887{
888 mProgram->setUniform4fv(location, count, v);
889}
890
891void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
892{
893 mProgram->setUniform1iv(location, count, v);
894}
895
896void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
897{
898 mProgram->setUniform2iv(location, count, v);
899}
900
901void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
902{
903 mProgram->setUniform3iv(location, count, v);
904}
905
906void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
907{
908 mProgram->setUniform4iv(location, count, v);
909}
910
911void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
912{
913 mProgram->setUniform1uiv(location, count, v);
914}
915
916void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
917{
918 mProgram->setUniform2uiv(location, count, v);
919}
920
921void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
922{
923 mProgram->setUniform3uiv(location, count, v);
924}
925
926void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
927{
928 mProgram->setUniform4uiv(location, count, v);
929}
930
931void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
932{
933 mProgram->setUniformMatrix2fv(location, count, transpose, v);
934}
935
936void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
937{
938 mProgram->setUniformMatrix3fv(location, count, transpose, v);
939}
940
941void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
942{
943 mProgram->setUniformMatrix4fv(location, count, transpose, v);
944}
945
946void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
947{
948 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
949}
950
951void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
952{
953 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
954}
955
956void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
957{
958 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
959}
960
961void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
962{
963 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
964}
965
966void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
967{
968 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
969}
970
971void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
972{
973 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
974}
975
976void Program::getUniformfv(GLint location, GLfloat *v)
977{
978 mProgram->getUniformfv(location, v);
979}
980
981void Program::getUniformiv(GLint location, GLint *v)
982{
983 mProgram->getUniformiv(location, v);
984}
985
986void Program::getUniformuiv(GLint location, GLuint *v)
987{
988 mProgram->getUniformuiv(location, v);
989}
990
991// Applies all the uniforms set for this program object to the renderer
992Error Program::applyUniforms()
993{
994 return mProgram->applyUniforms();
995}
996
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +0000997Error Program::applyUniformBuffers(const gl::Data &data)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500998{
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +0000999 return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001000}
1001
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001002void Program::flagForDeletion()
1003{
1004 mDeleteStatus = true;
1005}
1006
1007bool Program::isFlaggedForDeletion() const
1008{
1009 return mDeleteStatus;
1010}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001011
Brandon Jones43a53e22014-08-28 16:23:22 -07001012void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001013{
1014 mInfoLog.reset();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001015 mValidated = false;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001016
Geoff Lang7dd2e102014-11-10 15:19:26 -05001017 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001018 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001019 applyUniforms();
1020 mValidated = mProgram->validateSamplers(&mInfoLog, caps);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001021 }
1022 else
1023 {
1024 mInfoLog.append("Program has not been successfully linked.");
1025 }
1026}
1027
Geoff Lang7dd2e102014-11-10 15:19:26 -05001028bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1029{
1030 return mProgram->validateSamplers(infoLog, caps);
1031}
1032
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001033bool Program::isValidated() const
1034{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001035 return mValidated;
1036}
1037
1038void Program::updateSamplerMapping()
1039{
1040 return mProgram->updateSamplerMapping();
1041}
1042
1043GLuint Program::getActiveUniformBlockCount()
1044{
1045 return mProgram->getUniformBlocks().size();
1046}
1047
1048void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1049{
1050 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1051
1052 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1053
1054 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001055 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001056 std::string string = uniformBlock.name;
1057
1058 if (uniformBlock.isArrayElement())
1059 {
1060 string += ArrayString(uniformBlock.elementIndex);
1061 }
1062
1063 strncpy(uniformBlockName, string.c_str(), bufSize);
1064 uniformBlockName[bufSize - 1] = '\0';
1065
1066 if (length)
1067 {
1068 *length = strlen(uniformBlockName);
1069 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001070 }
1071}
1072
Geoff Lang7dd2e102014-11-10 15:19:26 -05001073void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001074{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001075 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1076
1077 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1078
1079 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001080 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001081 case GL_UNIFORM_BLOCK_DATA_SIZE:
1082 *params = static_cast<GLint>(uniformBlock.dataSize);
1083 break;
1084 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1085 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
1086 break;
1087 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1088 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1089 break;
1090 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1091 {
1092 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1093 {
1094 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1095 }
1096 }
1097 break;
1098 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1099 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
1100 break;
1101 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1102 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
1103 break;
1104 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001105 }
1106}
1107
1108GLint Program::getActiveUniformBlockMaxLength()
1109{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001110 int maxLength = 0;
1111
1112 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001113 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001114 unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
1115 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1116 {
1117 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1118 if (!uniformBlock.name.empty())
1119 {
1120 const int length = uniformBlock.name.length() + 1;
1121
1122 // Counting in "[0]".
1123 const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
1124
1125 maxLength = std::max(length + arrayLength, maxLength);
1126 }
1127 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001128 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001129
1130 return maxLength;
1131}
1132
1133GLuint Program::getUniformBlockIndex(const std::string &name)
1134{
1135 return mProgram->getUniformBlockIndex(name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001136}
1137
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001138const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
1139{
1140 return mProgram->getUniformBlockByIndex(index);
1141}
1142
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001143void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1144{
1145 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
1146}
1147
1148GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1149{
1150 return mUniformBlockBindings[uniformBlockIndex];
1151}
1152
1153void Program::resetUniformBlockBindings()
1154{
1155 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1156 {
1157 mUniformBlockBindings[blockId] = 0;
1158 }
1159}
1160
Geoff Lang48dcae72014-02-05 16:28:24 -05001161void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1162{
1163 mTransformFeedbackVaryings.resize(count);
1164 for (GLsizei i = 0; i < count; i++)
1165 {
1166 mTransformFeedbackVaryings[i] = varyings[i];
1167 }
1168
1169 mTransformFeedbackBufferMode = bufferMode;
1170}
1171
1172void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1173{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001174 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001175 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001176 ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
1177 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001178 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1179 if (length)
1180 {
1181 *length = lastNameIdx;
1182 }
1183 if (size)
1184 {
1185 *size = varying.size;
1186 }
1187 if (type)
1188 {
1189 *type = varying.type;
1190 }
1191 if (name)
1192 {
1193 memcpy(name, varying.name.c_str(), lastNameIdx);
1194 name[lastNameIdx] = '\0';
1195 }
1196 }
1197}
1198
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001199GLsizei Program::getTransformFeedbackVaryingCount() const
1200{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001201 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001202 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001203 return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001204 }
1205 else
1206 {
1207 return 0;
1208 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001209}
1210
1211GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1212{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001213 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001214 {
1215 GLsizei maxSize = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001216 for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001217 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001218 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001219 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1220 }
1221
1222 return maxSize;
1223 }
1224 else
1225 {
1226 return 0;
1227 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001228}
1229
1230GLenum Program::getTransformFeedbackBufferMode() const
1231{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001232 return mTransformFeedbackBufferMode;
1233}
1234
Geoff Lang7dd2e102014-11-10 15:19:26 -05001235bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
1236{
1237 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
1238 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
1239
1240 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
1241 {
1242 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
1243 bool matched = false;
1244
1245 // Built-in varyings obey special rules
1246 if (input->isBuiltIn())
1247 {
1248 continue;
1249 }
1250
1251 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
1252 {
1253 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
1254 if (output->name == input->name)
1255 {
1256 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
1257 {
1258 return false;
1259 }
1260
1261 output->registerIndex = input->registerIndex;
1262 output->columnIndex = input->columnIndex;
1263
1264 matched = true;
1265 break;
1266 }
1267 }
1268
1269 // We permit unmatched, unreferenced varyings
1270 if (!matched && input->staticUse)
1271 {
1272 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
1273 return false;
1274 }
1275 }
1276
1277 return true;
1278}
1279
1280bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1281{
1282 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1283 {
1284 return false;
1285 }
1286
1287 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1288 {
1289 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1290 return false;
1291 }
1292
1293 return true;
1294}
1295
1296// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill3da79b72015-04-27 11:09:17 -04001297bool Program::linkAttributes(const Data &data,
1298 InfoLog &infoLog,
1299 const AttributeBindings &attributeBindings,
1300 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001301{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001302 unsigned int usedLocations = 0;
1303 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001304 GLuint maxAttribs = data.caps->maxVertexAttributes;
1305
1306 // TODO(jmadill): handle aliasing robustly
1307 if (shaderAttributes.size() >= maxAttribs)
1308 {
1309 infoLog.append("Too many vertex attributes.");
1310 return false;
1311 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001312
1313 // Link attributes that have a binding location
1314 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1315 {
1316 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1317
1318 ASSERT(attribute.staticUse);
1319
1320 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1321
Jamie Madill3da79b72015-04-27 11:09:17 -04001322 mProgram->setShaderAttribute(attributeIndex, attribute);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001323
1324 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
1325 {
1326 const int rows = VariableRegisterCount(attribute.type);
1327
Jamie Madill3da79b72015-04-27 11:09:17 -04001328 if (static_cast<GLuint>(rows + location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001329 {
1330 infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1331
1332 return false;
1333 }
1334
1335 for (int row = 0; row < rows; row++)
1336 {
1337 const int rowLocation = location + row;
1338 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
1339
1340 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001341 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
1342 // TODO(jmadill): fix aliasing on ES2
1343 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001344 {
1345 if (!linkedAttribute.name.empty())
1346 {
1347 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1348 return false;
1349 }
1350 }
1351
1352 linkedAttribute = attribute;
1353 usedLocations |= 1 << rowLocation;
1354 }
1355 }
1356 }
1357
1358 // Link attributes that don't have a binding location
1359 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1360 {
1361 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1362
1363 ASSERT(attribute.staticUse);
1364
1365 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1366
1367 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
1368 {
1369 int rows = VariableRegisterCount(attribute.type);
Jamie Madill3da79b72015-04-27 11:09:17 -04001370 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001371
Jamie Madill3da79b72015-04-27 11:09:17 -04001372 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + rows) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001373 {
1374 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
1375
1376 return false; // Fail to link
1377 }
1378
1379 mLinkedAttribute[availableIndex] = attribute;
1380 }
1381 }
1382
Jamie Madill3da79b72015-04-27 11:09:17 -04001383 for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001384 {
Jamie Madill437d2662014-12-05 14:23:35 -05001385 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
1387
1388 for (int r = 0; r < rows; r++)
1389 {
Jamie Madill437d2662014-12-05 14:23:35 -05001390 mProgram->getSemanticIndexes()[attributeIndex++] = index++;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001391 }
1392 }
1393
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394 return true;
1395}
1396
1397bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
1398{
1399 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1400 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
1401 // Check that interface blocks defined in the vertex and fragment shaders are identical
1402 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1403 UniformBlockMap linkedUniformBlocks;
1404 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1405 {
1406 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
1407 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
1408 }
1409 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1410 {
1411 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
1412 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
1413 if (entry != linkedUniformBlocks.end())
1414 {
1415 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1416 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1417 {
1418 return false;
1419 }
1420 }
1421 }
1422 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1423 {
1424 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[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, vertexShader, interfaceBlock, caps))
1429 {
1430 return false;
1431 }
1432 }
1433 }
1434 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1435 {
1436 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
1437 // Note: shared and std140 layouts are always considered active
1438 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1439 {
1440 if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
1441 {
1442 return false;
1443 }
1444 }
1445 }
1446 return true;
1447}
1448
1449bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1450 const sh::InterfaceBlock &fragmentInterfaceBlock)
1451{
1452 const char* blockName = vertexInterfaceBlock.name.c_str();
1453 // validate blocks for the same member types
1454 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1455 {
1456 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
1457 return false;
1458 }
1459 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1460 {
1461 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
1462 return false;
1463 }
1464 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1465 {
1466 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
1467 return false;
1468 }
1469 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
1470 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1471 {
1472 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1473 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
1474 if (vertexMember.name != fragmentMember.name)
1475 {
1476 infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
1477 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
1478 return false;
1479 }
1480 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1481 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
1482 {
1483 return false;
1484 }
1485 }
1486 return true;
1487}
1488
1489bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1490 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
1491{
1492 if (vertexVariable.type != fragmentVariable.type)
1493 {
1494 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
1495 return false;
1496 }
1497 if (vertexVariable.arraySize != fragmentVariable.arraySize)
1498 {
1499 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
1500 return false;
1501 }
1502 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
1503 {
1504 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
1505 return false;
1506 }
1507
1508 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
1509 {
1510 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
1511 return false;
1512 }
1513 const unsigned int numMembers = vertexVariable.fields.size();
1514 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1515 {
1516 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1517 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
1518
1519 if (vertexMember.name != fragmentMember.name)
1520 {
1521 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
1522 memberIndex, variableName.c_str(),
1523 vertexMember.name.c_str(), fragmentMember.name.c_str());
1524 return false;
1525 }
1526
1527 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1528 vertexMember.name + "'";
1529
1530 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
1531 {
1532 return false;
1533 }
1534 }
1535
1536 return true;
1537}
1538
1539bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1540{
1541 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1542 {
1543 return false;
1544 }
1545
1546 return true;
1547}
1548
1549bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1550{
1551 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1552 {
1553 return false;
1554 }
1555
Jamie Madille9cc4692015-02-19 16:00:13 -05001556 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001557 {
1558 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1559 return false;
1560 }
1561
1562 return true;
1563}
1564
1565bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
1566 const std::vector<std::string> &transformFeedbackVaryingNames,
1567 GLenum transformFeedbackBufferMode,
1568 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
1569 const Caps &caps) const
1570{
1571 size_t totalComponents = 0;
1572
1573 // Gather the linked varyings that are used for transform feedback, they should all exist.
1574 outTransformFeedbackLinkedVaryings->clear();
1575 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
1576 {
1577 bool found = false;
1578 for (size_t j = 0; j < linkedVaryings.size(); j++)
1579 {
1580 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
1581 {
1582 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
1583 {
1584 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
1585 {
1586 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
1587 return false;
1588 }
1589 }
1590
1591 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
1592 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1593 componentCount > caps.maxTransformFeedbackSeparateComponents)
1594 {
1595 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
1596 linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
1597 return false;
1598 }
1599
1600 totalComponents += componentCount;
1601
1602 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
1603 found = true;
1604 break;
1605 }
1606 }
1607
1608 // All transform feedback varyings are expected to exist since packVaryings checks for them.
1609 ASSERT(found);
1610 }
1611
1612 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
1613 {
1614 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
1615 totalComponents, caps.maxTransformFeedbackInterleavedComponents);
1616 return false;
1617 }
1618
1619 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001620}
1621
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622}