blob: a7de23d3e1dbf87e60ca992acc27ddfd2491dd31 [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
116void InfoLog::append(const char *format, ...)
117{
118 if (!format)
119 {
120 return;
121 }
122
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000123 va_list vararg;
124 va_start(vararg, format);
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400125 std::string tempString(FormatString(format, vararg));
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000126 va_end(vararg);
127
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400128 mStream << tempString << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000129}
130
131void InfoLog::reset()
132{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000133}
134
Geoff Lang7dd2e102014-11-10 15:19:26 -0500135VariableLocation::VariableLocation()
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400136 : name(),
137 element(0),
138 index(0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000139{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500140}
141
142VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400143 : name(name),
144 element(element),
145 index(index)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500146{
147}
148
149LinkedVarying::LinkedVarying()
150{
151}
152
153LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
154 unsigned int semanticIndex, unsigned int semanticIndexCount)
155 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
156{
157}
158
159Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
160 : mProgram(impl),
161 mValidated(false),
Geoff Langce5d66e2015-01-07 14:06:12 -0500162 mTransformFeedbackVaryings(),
163 mTransformFeedbackBufferMode(GL_NONE),
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400164 mFragmentShader(nullptr),
165 mVertexShader(nullptr),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500166 mLinked(false),
167 mDeleteStatus(false),
168 mRefCount(0),
169 mResourceManager(manager),
170 mHandle(handle)
171{
172 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000173
174 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500175 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176}
177
178Program::~Program()
179{
180 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000181
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400182 if (mVertexShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000183 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000184 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000185 }
186
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400187 if (mFragmentShader != nullptr)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000188 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000189 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000190 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500191
192 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
195bool Program::attachShader(Shader *shader)
196{
197 if (shader->getType() == GL_VERTEX_SHADER)
198 {
199 if (mVertexShader)
200 {
201 return false;
202 }
203
Brandon Jones71620962014-08-20 14:04:59 -0700204 mVertexShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000205 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206 }
207 else if (shader->getType() == GL_FRAGMENT_SHADER)
208 {
209 if (mFragmentShader)
210 {
211 return false;
212 }
213
Brandon Jones71620962014-08-20 14:04:59 -0700214 mFragmentShader = shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000215 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216 }
217 else UNREACHABLE();
218
219 return true;
220}
221
222bool Program::detachShader(Shader *shader)
223{
224 if (shader->getType() == GL_VERTEX_SHADER)
225 {
226 if (mVertexShader != shader)
227 {
228 return false;
229 }
230
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000231 mVertexShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400232 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233 }
234 else if (shader->getType() == GL_FRAGMENT_SHADER)
235 {
236 if (mFragmentShader != shader)
237 {
238 return false;
239 }
240
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000241 mFragmentShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400242 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243 }
244 else UNREACHABLE();
245
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000246 return true;
247}
248
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000249int Program::getAttachedShadersCount() const
250{
251 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
252}
253
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000254void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
255{
256 if (index < MAX_VERTEX_ATTRIBS)
257 {
258 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
259 {
260 mAttributeBinding[i].erase(name);
261 }
262
263 mAttributeBinding[index].insert(name);
264 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000265}
266
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267void Program::bindAttributeLocation(GLuint index, const char *name)
268{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000269 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270}
271
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
273// compiling them into binaries, determining the attribute mappings, and collecting
274// a list of uniforms
Jamie Madillde8892b2014-11-11 13:00:22 -0500275Error Program::link(const Data &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000276{
277 unlink(false);
278
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000279 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000280 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000281
Geoff Lang7dd2e102014-11-10 15:19:26 -0500282 if (!mFragmentShader || !mFragmentShader->isCompiled())
283 {
284 return Error(GL_NO_ERROR);
285 }
286 ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
287
288 if (!mVertexShader || !mVertexShader->isCompiled())
289 {
290 return Error(GL_NO_ERROR);
291 }
292 ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
293
Jamie Madill3da79b72015-04-27 11:09:17 -0400294 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500295 {
296 return Error(GL_NO_ERROR);
297 }
298
Geoff Lang7dd2e102014-11-10 15:19:26 -0500299 int registers;
300 std::vector<LinkedVarying> linkedVaryings;
301 rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
302 &registers, &linkedVaryings, &mOutputVariables);
303 if (result.error.isError() || !result.linkSuccess)
Geoff Langb543aff2014-09-30 14:52:54 -0400304 {
305 return result.error;
306 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000307
Geoff Lang7dd2e102014-11-10 15:19:26 -0500308 if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
309 {
310 return Error(GL_NO_ERROR);
311 }
312
313 if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
314 {
315 return Error(GL_NO_ERROR);
316 }
317
318 if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
319 mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
320 {
321 return Error(GL_NO_ERROR);
322 }
323
324 // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
325 // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
326 result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers);
327 if (result.error.isError() || !result.linkSuccess)
328 {
329 mInfoLog.append("Failed to create D3D shaders.");
330 unlink(false);
331 return result.error;
332 }
333
334 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400335 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000336}
337
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000338int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000339{
340 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
341 {
342 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
343 {
344 return location;
345 }
346 }
347
348 return -1;
349}
350
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000351// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352void Program::unlink(bool destroy)
353{
354 if (destroy) // Object being destructed
355 {
356 if (mFragmentShader)
357 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000358 mFragmentShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400359 mFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360 }
361
362 if (mVertexShader)
363 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000364 mVertexShader->release();
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400365 mVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367 }
368
Geoff Lang7dd2e102014-11-10 15:19:26 -0500369 std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500370 mOutputVariables.clear();
371
372 mProgram->reset();
373
374 mValidated = false;
375
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000376 mLinked = false;
377}
378
379bool Program::isLinked()
380{
381 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382}
383
Geoff Lang7dd2e102014-11-10 15:19:26 -0500384Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000385{
386 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000387
Geoff Lang7dd2e102014-11-10 15:19:26 -0500388#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
389 return Error(GL_NO_ERROR);
390#else
391 ASSERT(binaryFormat == mProgram->getBinaryFormat());
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000392
Geoff Lang7dd2e102014-11-10 15:19:26 -0500393 BinaryInputStream stream(binary, length);
394
395 GLenum format = stream.readInt<GLenum>();
396 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000397 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500398 mInfoLog.append("Invalid program binary format.");
399 return Error(GL_NO_ERROR);
400 }
401
402 int majorVersion = stream.readInt<int>();
403 int minorVersion = stream.readInt<int>();
404 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
405 {
406 mInfoLog.append("Invalid program binary version.");
407 return Error(GL_NO_ERROR);
408 }
409
410 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
411 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
412 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
413 {
414 mInfoLog.append("Invalid program binary version.");
415 return Error(GL_NO_ERROR);
416 }
417
Jamie Madill3da79b72015-04-27 11:09:17 -0400418 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500419 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
420 {
421 stream.readInt(&mLinkedAttribute[i].type);
422 stream.readString(&mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500423 stream.readInt(&mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500424 }
425
Jamie Madill3da79b72015-04-27 11:09:17 -0400426 unsigned int attribCount = stream.readInt<unsigned int>();
427 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
428 {
429 GLenum type = stream.readInt<GLenum>();
430 GLenum precision = stream.readInt<GLenum>();
431 std::string name = stream.readString();
432 GLint arraySize = stream.readInt<GLint>();
433 int location = stream.readInt<int>();
434 mProgram->setShaderAttribute(attribIndex, type, precision, name, arraySize, location);
435 }
436
Geoff Lang7dd2e102014-11-10 15:19:26 -0500437 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
438 if (result.error.isError() || !result.linkSuccess)
439 {
Geoff Langb543aff2014-09-30 14:52:54 -0400440 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000441 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000442
Geoff Lang7dd2e102014-11-10 15:19:26 -0500443 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400444 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500445#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
446}
447
448Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
449{
450 if (binaryFormat)
451 {
452 *binaryFormat = mProgram->getBinaryFormat();
453 }
454
455 BinaryOutputStream stream;
456
457 stream.writeInt(mProgram->getBinaryFormat());
458 stream.writeInt(ANGLE_MAJOR_VERSION);
459 stream.writeInt(ANGLE_MINOR_VERSION);
460 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
461
Jamie Madill3da79b72015-04-27 11:09:17 -0400462 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500463 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
464 {
465 stream.writeInt(mLinkedAttribute[i].type);
466 stream.writeString(mLinkedAttribute[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500467 stream.writeInt(mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500468 }
469
Jamie Madill3da79b72015-04-27 11:09:17 -0400470 const auto &shaderAttributes = mProgram->getShaderAttributes();
471 stream.writeInt(shaderAttributes.size());
472 for (const auto &attrib : shaderAttributes)
473 {
474 stream.writeInt(attrib.type);
475 stream.writeInt(attrib.precision);
476 stream.writeString(attrib.name);
477 stream.writeInt(attrib.arraySize);
478 stream.writeInt(attrib.location);
479 }
480
Geoff Lang7dd2e102014-11-10 15:19:26 -0500481 gl::Error error = mProgram->save(&stream);
482 if (error.isError())
483 {
484 return error;
485 }
486
487 GLsizei streamLength = stream.length();
488 const void *streamData = stream.data();
489
490 if (streamLength > bufSize)
491 {
492 if (length)
493 {
494 *length = 0;
495 }
496
497 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
498 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
499 // sizes and then copy it.
500 return Error(GL_INVALID_OPERATION);
501 }
502
503 if (binary)
504 {
505 char *ptr = reinterpret_cast<char*>(binary);
506
507 memcpy(ptr, streamData, streamLength);
508 ptr += streamLength;
509
510 ASSERT(ptr - streamLength == binary);
511 }
512
513 if (length)
514 {
515 *length = streamLength;
516 }
517
518 return Error(GL_NO_ERROR);
519}
520
521GLint Program::getBinaryLength() const
522{
523 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400524 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500525 if (error.isError())
526 {
527 return 0;
528 }
529
530 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000531}
532
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000533void Program::release()
534{
535 mRefCount--;
536
537 if (mRefCount == 0 && mDeleteStatus)
538 {
539 mResourceManager->deleteProgram(mHandle);
540 }
541}
542
543void Program::addRef()
544{
545 mRefCount++;
546}
547
548unsigned int Program::getRefCount() const
549{
550 return mRefCount;
551}
552
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000553int Program::getInfoLogLength() const
554{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400555 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000556}
557
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000558void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
559{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000560 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000561}
562
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000563void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
564{
565 int total = 0;
566
567 if (mVertexShader)
568 {
569 if (total < maxCount)
570 {
571 shaders[total] = mVertexShader->getHandle();
572 }
573
574 total++;
575 }
576
577 if (mFragmentShader)
578 {
579 if (total < maxCount)
580 {
581 shaders[total] = mFragmentShader->getHandle();
582 }
583
584 total++;
585 }
586
587 if (count)
588 {
589 *count = total;
590 }
591}
592
Geoff Lang7dd2e102014-11-10 15:19:26 -0500593GLuint Program::getAttributeLocation(const std::string &name)
594{
595 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
596 {
597 if (mLinkedAttribute[index].name == name)
598 {
599 return index;
600 }
601 }
602
Austin Kinrossb8af7232015-03-16 22:33:25 -0700603 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500604}
605
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400606const int *Program::getSemanticIndexes() const
607{
608 return mProgram->getSemanticIndexes();
609}
610
Geoff Lang7dd2e102014-11-10 15:19:26 -0500611int Program::getSemanticIndex(int attributeIndex)
612{
613 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
614
Jamie Madill437d2662014-12-05 14:23:35 -0500615 return mProgram->getSemanticIndexes()[attributeIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500616}
617
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000618void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
619{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500620 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000621 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500622 // Skip over inactive attributes
623 unsigned int activeAttribute = 0;
624 unsigned int attribute;
625 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
626 {
627 if (mLinkedAttribute[attribute].name.empty())
628 {
629 continue;
630 }
631
632 if (activeAttribute == index)
633 {
634 break;
635 }
636
637 activeAttribute++;
638 }
639
640 if (bufsize > 0)
641 {
642 const char *string = mLinkedAttribute[attribute].name.c_str();
643
644 strncpy(name, string, bufsize);
645 name[bufsize - 1] = '\0';
646
647 if (length)
648 {
649 *length = strlen(name);
650 }
651 }
652
653 *size = 1; // Always a single 'type' instance
654
655 *type = mLinkedAttribute[attribute].type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000656 }
657 else
658 {
659 if (bufsize > 0)
660 {
661 name[0] = '\0';
662 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500663
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000664 if (length)
665 {
666 *length = 0;
667 }
668
669 *type = GL_NONE;
670 *size = 1;
671 }
672}
673
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000674GLint Program::getActiveAttributeCount()
675{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500676 int count = 0;
677
678 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000679 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500680 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
681 {
682 if (!mLinkedAttribute[attributeIndex].name.empty())
683 {
684 count++;
685 }
686 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000687 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500688
689 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000690}
691
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000692GLint Program::getActiveAttributeMaxLength()
693{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500694 int maxLength = 0;
695
696 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000697 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500698 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
699 {
700 if (!mLinkedAttribute[attributeIndex].name.empty())
701 {
702 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
703 }
704 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000705 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500706
707 return maxLength;
708}
709
710// Returns one more than the highest sampler index used.
711GLint Program::getUsedSamplerRange(SamplerType type)
712{
713 return mProgram->getUsedSamplerRange(type);
714}
715
716bool Program::usesPointSize() const
717{
718 return mProgram->usesPointSize();
719}
720
721GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
722{
723 return mProgram->getSamplerMapping(type, samplerIndex, caps);
724}
725
726GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
727{
728 return mProgram->getSamplerTextureType(type, samplerIndex);
729}
730
731GLint Program::getFragDataLocation(const std::string &name) const
732{
733 std::string baseName(name);
734 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
735 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000736 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500737 const VariableLocation &outputVariable = locationIt->second;
738 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
739 {
740 return static_cast<GLint>(locationIt->first);
741 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000742 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500743 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000744}
745
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000746void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
747{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500748 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000749 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500750 ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
751 LinkedUniform *uniform = mProgram->getUniforms()[index];
752
753 if (bufsize > 0)
754 {
755 std::string string = uniform->name;
756 if (uniform->isArray())
757 {
758 string += "[0]";
759 }
760
761 strncpy(name, string.c_str(), bufsize);
762 name[bufsize - 1] = '\0';
763
764 if (length)
765 {
766 *length = strlen(name);
767 }
768 }
769
770 *size = uniform->elementCount();
771 *type = uniform->type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000772 }
773 else
774 {
775 if (bufsize > 0)
776 {
777 name[0] = '\0';
778 }
779
780 if (length)
781 {
782 *length = 0;
783 }
784
785 *size = 0;
786 *type = GL_NONE;
787 }
788}
789
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000790GLint Program::getActiveUniformCount()
791{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500792 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000793 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500794 return mProgram->getUniforms().size();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000795 }
796 else
797 {
798 return 0;
799 }
800}
801
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000802GLint Program::getActiveUniformMaxLength()
803{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500804 int maxLength = 0;
805
806 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000807 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500808 unsigned int numUniforms = mProgram->getUniforms().size();
809 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
810 {
811 if (!mProgram->getUniforms()[uniformIndex]->name.empty())
812 {
813 int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
814 if (mProgram->getUniforms()[uniformIndex]->isArray())
815 {
816 length += 3; // Counting in "[0]".
817 }
818 maxLength = std::max(length, maxLength);
819 }
820 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000821 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500822
823 return maxLength;
824}
825
826GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
827{
828 const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
829 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000830 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500831 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
832 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
833 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
834 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
835 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
836 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
837 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
838 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
839 default:
840 UNREACHABLE();
841 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000842 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500843 return 0;
844}
845
846bool Program::isValidUniformLocation(GLint location) const
847{
848 ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
849 return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
850}
851
852LinkedUniform *Program::getUniformByLocation(GLint location) const
853{
854 return mProgram->getUniformByLocation(location);
855}
856
857LinkedUniform *Program::getUniformByName(const std::string &name) const
858{
859 return mProgram->getUniformByName(name);
860}
861
862GLint Program::getUniformLocation(const std::string &name)
863{
864 return mProgram->getUniformLocation(name);
865}
866
867GLuint Program::getUniformIndex(const std::string &name)
868{
869 return mProgram->getUniformIndex(name);
870}
871
872void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
873{
874 mProgram->setUniform1fv(location, count, v);
875}
876
877void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
878{
879 mProgram->setUniform2fv(location, count, v);
880}
881
882void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
883{
884 mProgram->setUniform3fv(location, count, v);
885}
886
887void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
888{
889 mProgram->setUniform4fv(location, count, v);
890}
891
892void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
893{
894 mProgram->setUniform1iv(location, count, v);
895}
896
897void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
898{
899 mProgram->setUniform2iv(location, count, v);
900}
901
902void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
903{
904 mProgram->setUniform3iv(location, count, v);
905}
906
907void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
908{
909 mProgram->setUniform4iv(location, count, v);
910}
911
912void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
913{
914 mProgram->setUniform1uiv(location, count, v);
915}
916
917void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
918{
919 mProgram->setUniform2uiv(location, count, v);
920}
921
922void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
923{
924 mProgram->setUniform3uiv(location, count, v);
925}
926
927void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
928{
929 mProgram->setUniform4uiv(location, count, v);
930}
931
932void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
933{
934 mProgram->setUniformMatrix2fv(location, count, transpose, v);
935}
936
937void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
938{
939 mProgram->setUniformMatrix3fv(location, count, transpose, v);
940}
941
942void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
943{
944 mProgram->setUniformMatrix4fv(location, count, transpose, v);
945}
946
947void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
948{
949 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
950}
951
952void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
953{
954 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
955}
956
957void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
958{
959 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
960}
961
962void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
963{
964 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
965}
966
967void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
968{
969 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
970}
971
972void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
973{
974 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
975}
976
977void Program::getUniformfv(GLint location, GLfloat *v)
978{
979 mProgram->getUniformfv(location, v);
980}
981
982void Program::getUniformiv(GLint location, GLint *v)
983{
984 mProgram->getUniformiv(location, v);
985}
986
987void Program::getUniformuiv(GLint location, GLuint *v)
988{
989 mProgram->getUniformuiv(location, v);
990}
991
992// Applies all the uniforms set for this program object to the renderer
993Error Program::applyUniforms()
994{
995 return mProgram->applyUniforms();
996}
997
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +0000998Error Program::applyUniformBuffers(const gl::Data &data)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500999{
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001000 return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001001}
1002
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003void Program::flagForDeletion()
1004{
1005 mDeleteStatus = true;
1006}
1007
1008bool Program::isFlaggedForDeletion() const
1009{
1010 return mDeleteStatus;
1011}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001012
Brandon Jones43a53e22014-08-28 16:23:22 -07001013void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001014{
1015 mInfoLog.reset();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001016 mValidated = false;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001017
Geoff Lang7dd2e102014-11-10 15:19:26 -05001018 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001019 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001020 applyUniforms();
1021 mValidated = mProgram->validateSamplers(&mInfoLog, caps);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001022 }
1023 else
1024 {
1025 mInfoLog.append("Program has not been successfully linked.");
1026 }
1027}
1028
Geoff Lang7dd2e102014-11-10 15:19:26 -05001029bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1030{
1031 return mProgram->validateSamplers(infoLog, caps);
1032}
1033
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001034bool Program::isValidated() const
1035{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001036 return mValidated;
1037}
1038
1039void Program::updateSamplerMapping()
1040{
1041 return mProgram->updateSamplerMapping();
1042}
1043
1044GLuint Program::getActiveUniformBlockCount()
1045{
1046 return mProgram->getUniformBlocks().size();
1047}
1048
1049void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1050{
1051 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1052
1053 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1054
1055 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001056 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001057 std::string string = uniformBlock.name;
1058
1059 if (uniformBlock.isArrayElement())
1060 {
1061 string += ArrayString(uniformBlock.elementIndex);
1062 }
1063
1064 strncpy(uniformBlockName, string.c_str(), bufSize);
1065 uniformBlockName[bufSize - 1] = '\0';
1066
1067 if (length)
1068 {
1069 *length = strlen(uniformBlockName);
1070 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001071 }
1072}
1073
Geoff Lang7dd2e102014-11-10 15:19:26 -05001074void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001075{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001076 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1077
1078 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1079
1080 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001081 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001082 case GL_UNIFORM_BLOCK_DATA_SIZE:
1083 *params = static_cast<GLint>(uniformBlock.dataSize);
1084 break;
1085 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1086 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
1087 break;
1088 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1089 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1090 break;
1091 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1092 {
1093 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1094 {
1095 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1096 }
1097 }
1098 break;
1099 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1100 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
1101 break;
1102 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1103 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
1104 break;
1105 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001106 }
1107}
1108
1109GLint Program::getActiveUniformBlockMaxLength()
1110{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001111 int maxLength = 0;
1112
1113 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001114 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001115 unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
1116 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1117 {
1118 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1119 if (!uniformBlock.name.empty())
1120 {
1121 const int length = uniformBlock.name.length() + 1;
1122
1123 // Counting in "[0]".
1124 const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
1125
1126 maxLength = std::max(length + arrayLength, maxLength);
1127 }
1128 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001129 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001130
1131 return maxLength;
1132}
1133
1134GLuint Program::getUniformBlockIndex(const std::string &name)
1135{
1136 return mProgram->getUniformBlockIndex(name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001137}
1138
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001139const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
1140{
1141 return mProgram->getUniformBlockByIndex(index);
1142}
1143
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001144void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1145{
1146 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
1147}
1148
1149GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1150{
1151 return mUniformBlockBindings[uniformBlockIndex];
1152}
1153
1154void Program::resetUniformBlockBindings()
1155{
1156 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1157 {
1158 mUniformBlockBindings[blockId] = 0;
1159 }
1160}
1161
Geoff Lang48dcae72014-02-05 16:28:24 -05001162void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1163{
1164 mTransformFeedbackVaryings.resize(count);
1165 for (GLsizei i = 0; i < count; i++)
1166 {
1167 mTransformFeedbackVaryings[i] = varyings[i];
1168 }
1169
1170 mTransformFeedbackBufferMode = bufferMode;
1171}
1172
1173void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1174{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001175 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001176 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001177 ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
1178 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001179 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1180 if (length)
1181 {
1182 *length = lastNameIdx;
1183 }
1184 if (size)
1185 {
1186 *size = varying.size;
1187 }
1188 if (type)
1189 {
1190 *type = varying.type;
1191 }
1192 if (name)
1193 {
1194 memcpy(name, varying.name.c_str(), lastNameIdx);
1195 name[lastNameIdx] = '\0';
1196 }
1197 }
1198}
1199
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001200GLsizei Program::getTransformFeedbackVaryingCount() const
1201{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001202 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001203 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001204 return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001205 }
1206 else
1207 {
1208 return 0;
1209 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001210}
1211
1212GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1213{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001214 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001215 {
1216 GLsizei maxSize = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001217 for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001218 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001219 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001220 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1221 }
1222
1223 return maxSize;
1224 }
1225 else
1226 {
1227 return 0;
1228 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001229}
1230
1231GLenum Program::getTransformFeedbackBufferMode() const
1232{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001233 return mTransformFeedbackBufferMode;
1234}
1235
Geoff Lang7dd2e102014-11-10 15:19:26 -05001236bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
1237{
1238 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
1239 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
1240
1241 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
1242 {
1243 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
1244 bool matched = false;
1245
1246 // Built-in varyings obey special rules
1247 if (input->isBuiltIn())
1248 {
1249 continue;
1250 }
1251
1252 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
1253 {
1254 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
1255 if (output->name == input->name)
1256 {
1257 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
1258 {
1259 return false;
1260 }
1261
1262 output->registerIndex = input->registerIndex;
1263 output->columnIndex = input->columnIndex;
1264
1265 matched = true;
1266 break;
1267 }
1268 }
1269
1270 // We permit unmatched, unreferenced varyings
1271 if (!matched && input->staticUse)
1272 {
1273 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
1274 return false;
1275 }
1276 }
1277
1278 return true;
1279}
1280
1281bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1282{
1283 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1284 {
1285 return false;
1286 }
1287
1288 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1289 {
1290 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1291 return false;
1292 }
1293
1294 return true;
1295}
1296
1297// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill3da79b72015-04-27 11:09:17 -04001298bool Program::linkAttributes(const Data &data,
1299 InfoLog &infoLog,
1300 const AttributeBindings &attributeBindings,
1301 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001302{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001303 unsigned int usedLocations = 0;
1304 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001305 GLuint maxAttribs = data.caps->maxVertexAttributes;
1306
1307 // TODO(jmadill): handle aliasing robustly
1308 if (shaderAttributes.size() >= maxAttribs)
1309 {
1310 infoLog.append("Too many vertex attributes.");
1311 return false;
1312 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001313
1314 // Link attributes that have a binding location
1315 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1316 {
1317 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1318
1319 ASSERT(attribute.staticUse);
1320
1321 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1322
Jamie Madill3da79b72015-04-27 11:09:17 -04001323 mProgram->setShaderAttribute(attributeIndex, attribute);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001324
1325 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
1326 {
1327 const int rows = VariableRegisterCount(attribute.type);
1328
Jamie Madill3da79b72015-04-27 11:09:17 -04001329 if (static_cast<GLuint>(rows + location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001330 {
1331 infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1332
1333 return false;
1334 }
1335
1336 for (int row = 0; row < rows; row++)
1337 {
1338 const int rowLocation = location + row;
1339 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
1340
1341 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001342 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
1343 // TODO(jmadill): fix aliasing on ES2
1344 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001345 {
1346 if (!linkedAttribute.name.empty())
1347 {
1348 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1349 return false;
1350 }
1351 }
1352
1353 linkedAttribute = attribute;
1354 usedLocations |= 1 << rowLocation;
1355 }
1356 }
1357 }
1358
1359 // Link attributes that don't have a binding location
1360 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1361 {
1362 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1363
1364 ASSERT(attribute.staticUse);
1365
1366 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1367
1368 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
1369 {
1370 int rows = VariableRegisterCount(attribute.type);
Jamie Madill3da79b72015-04-27 11:09:17 -04001371 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001372
Jamie Madill3da79b72015-04-27 11:09:17 -04001373 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + rows) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001374 {
1375 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
1376
1377 return false; // Fail to link
1378 }
1379
1380 mLinkedAttribute[availableIndex] = attribute;
1381 }
1382 }
1383
Jamie Madill3da79b72015-04-27 11:09:17 -04001384 for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001385 {
Jamie Madill437d2662014-12-05 14:23:35 -05001386 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
1388
1389 for (int r = 0; r < rows; r++)
1390 {
Jamie Madill437d2662014-12-05 14:23:35 -05001391 mProgram->getSemanticIndexes()[attributeIndex++] = index++;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392 }
1393 }
1394
Geoff Lang7dd2e102014-11-10 15:19:26 -05001395 return true;
1396}
1397
1398bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
1399{
1400 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1401 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
1402 // Check that interface blocks defined in the vertex and fragment shaders are identical
1403 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1404 UniformBlockMap linkedUniformBlocks;
1405 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1406 {
1407 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
1408 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
1409 }
1410 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1411 {
1412 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
1413 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
1414 if (entry != linkedUniformBlocks.end())
1415 {
1416 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1417 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1418 {
1419 return false;
1420 }
1421 }
1422 }
1423 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1424 {
1425 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
1426 // Note: shared and std140 layouts are always considered active
1427 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1428 {
1429 if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
1430 {
1431 return false;
1432 }
1433 }
1434 }
1435 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1436 {
1437 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
1438 // Note: shared and std140 layouts are always considered active
1439 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1440 {
1441 if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
1442 {
1443 return false;
1444 }
1445 }
1446 }
1447 return true;
1448}
1449
1450bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1451 const sh::InterfaceBlock &fragmentInterfaceBlock)
1452{
1453 const char* blockName = vertexInterfaceBlock.name.c_str();
1454 // validate blocks for the same member types
1455 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1456 {
1457 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
1458 return false;
1459 }
1460 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1461 {
1462 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
1463 return false;
1464 }
1465 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1466 {
1467 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
1468 return false;
1469 }
1470 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
1471 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1472 {
1473 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1474 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
1475 if (vertexMember.name != fragmentMember.name)
1476 {
1477 infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
1478 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
1479 return false;
1480 }
1481 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1482 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
1483 {
1484 return false;
1485 }
1486 }
1487 return true;
1488}
1489
1490bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1491 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
1492{
1493 if (vertexVariable.type != fragmentVariable.type)
1494 {
1495 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
1496 return false;
1497 }
1498 if (vertexVariable.arraySize != fragmentVariable.arraySize)
1499 {
1500 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
1501 return false;
1502 }
1503 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
1504 {
1505 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
1506 return false;
1507 }
1508
1509 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
1510 {
1511 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
1512 return false;
1513 }
1514 const unsigned int numMembers = vertexVariable.fields.size();
1515 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1516 {
1517 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1518 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
1519
1520 if (vertexMember.name != fragmentMember.name)
1521 {
1522 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
1523 memberIndex, variableName.c_str(),
1524 vertexMember.name.c_str(), fragmentMember.name.c_str());
1525 return false;
1526 }
1527
1528 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1529 vertexMember.name + "'";
1530
1531 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
1532 {
1533 return false;
1534 }
1535 }
1536
1537 return true;
1538}
1539
1540bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1541{
1542 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1543 {
1544 return false;
1545 }
1546
1547 return true;
1548}
1549
1550bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1551{
1552 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1553 {
1554 return false;
1555 }
1556
Jamie Madille9cc4692015-02-19 16:00:13 -05001557 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558 {
1559 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1560 return false;
1561 }
1562
1563 return true;
1564}
1565
1566bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
1567 const std::vector<std::string> &transformFeedbackVaryingNames,
1568 GLenum transformFeedbackBufferMode,
1569 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
1570 const Caps &caps) const
1571{
1572 size_t totalComponents = 0;
1573
1574 // Gather the linked varyings that are used for transform feedback, they should all exist.
1575 outTransformFeedbackLinkedVaryings->clear();
1576 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
1577 {
1578 bool found = false;
1579 for (size_t j = 0; j < linkedVaryings.size(); j++)
1580 {
1581 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
1582 {
1583 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
1584 {
1585 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
1586 {
1587 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
1588 return false;
1589 }
1590 }
1591
1592 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
1593 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1594 componentCount > caps.maxTransformFeedbackSeparateComponents)
1595 {
1596 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
1597 linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
1598 return false;
1599 }
1600
1601 totalComponents += componentCount;
1602
1603 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
1604 found = true;
1605 break;
1606 }
1607 }
1608
1609 // All transform feedback varyings are expected to exist since packVaryings checks for them.
1610 ASSERT(found);
1611 }
1612
1613 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
1614 {
1615 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
1616 totalComponents, caps.maxTransformFeedbackInterleavedComponents);
1617 return false;
1618 }
1619
1620 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001621}
1622
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001623}