blob: fb3449f2ce2f41dbcdd62a7a928103813658615b [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Program.h"
Jamie Madill437d2662014-12-05 14:23:35 -050011
Jamie Madill9e0478f2015-01-13 11:13:54 -050012#include <algorithm>
13
14#include "common/debug.h"
15#include "common/platform.h"
16#include "common/utilities.h"
17#include "common/version.h"
18#include "compiler/translator/blocklayout.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050019#include "libANGLE/Data.h"
Jamie Madill437d2662014-12-05 14:23:35 -050020#include "libANGLE/ResourceManager.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/features.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/renderer/Renderer.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050023#include "libANGLE/renderer/ProgramImpl.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025namespace gl
26{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000027const char * const g_fakepath = "C:\\fakepath";
28
Geoff Lang7dd2e102014-11-10 15:19:26 -050029namespace
30{
31
32unsigned int ParseAndStripArrayIndex(std::string* name)
33{
34 unsigned int subscript = GL_INVALID_INDEX;
35
36 // Strip any trailing array operator and retrieve the subscript
37 size_t open = name->find_last_of('[');
38 size_t close = name->find_last_of(']');
39 if (open != std::string::npos && close == name->length() - 1)
40 {
41 subscript = atoi(name->substr(open + 1).c_str());
42 name->erase(open);
43 }
44
45 return subscript;
46}
47
48}
49
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000050AttributeBindings::AttributeBindings()
51{
52}
53
54AttributeBindings::~AttributeBindings()
55{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000056}
57
Jamie Madill71c3b2c2015-05-07 11:49:20 -040058InfoLog::InfoLog()
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000059{
60}
61
62InfoLog::~InfoLog()
63{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000064}
65
Jamie Madill71c3b2c2015-05-07 11:49:20 -040066size_t InfoLog::getLength() const
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000067{
Jamie Madill71c3b2c2015-05-07 11:49:20 -040068 const std::string &logString = mStream.str();
69 return logString.empty() ? 0 : logString.length() + 1;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000070}
71
72void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
73{
Jamie Madill71c3b2c2015-05-07 11:49:20 -040074 size_t index = 0;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000075
76 if (bufSize > 0)
77 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040078 const std::string str(mStream.str());
79
80 if (!str.empty())
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000081 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040082 index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
83 memcpy(infoLog, str.c_str(), index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000084 }
85
86 infoLog[index] = '\0';
87 }
88
89 if (length)
90 {
Jamie Madill71c3b2c2015-05-07 11:49:20 -040091 *length = static_cast<GLsizei>(index);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000092 }
93}
94
95// append a santized message to the program info log.
96// The D3D compiler includes a fake file path in some of the warning or error
97// messages, so lets remove all occurrences of this fake file path from the log.
98void InfoLog::appendSanitized(const char *message)
99{
100 std::string msg(message);
101
102 size_t found;
103 do
104 {
105 found = msg.find(g_fakepath);
106 if (found != std::string::npos)
107 {
108 msg.erase(found, strlen(g_fakepath));
109 }
110 }
111 while (found != std::string::npos);
112
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400113 mStream << message << std::endl;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000114}
115
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000116void InfoLog::reset()
117{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000118}
119
Geoff Lang7dd2e102014-11-10 15:19:26 -0500120VariableLocation::VariableLocation()
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400121 : name(),
122 element(0),
123 index(0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000124{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500125}
126
127VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400128 : name(name),
129 element(element),
130 index(index)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500131{
132}
133
134LinkedVarying::LinkedVarying()
135{
136}
137
138LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
139 unsigned int semanticIndex, unsigned int semanticIndexCount)
140 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
141{
142}
143
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400144Program::Data::Data()
145 : mAttachedFragmentShader(nullptr),
146 mAttachedVertexShader(nullptr),
Corentin Wallezbc99bb62015-05-14 17:42:20 -0400147 mTransformFeedbackVaryings(),
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400148 mTransformFeedbackBufferMode(GL_NONE)
149{
150}
151
152Program::Data::~Data()
153{
154 if (mAttachedVertexShader != nullptr)
155 {
156 mAttachedVertexShader->release();
157 }
158
159 if (mAttachedFragmentShader != nullptr)
160 {
161 mAttachedFragmentShader->release();
162 }
163}
164
165Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
166 : mProgram(factory->createProgram(mData)),
167 mLinkedAttributes(gl::MAX_VERTEX_ATTRIBS),
168 mValidated(false),
Geoff Lang7dd2e102014-11-10 15:19:26 -0500169 mLinked(false),
170 mDeleteStatus(false),
171 mRefCount(0),
172 mResourceManager(manager),
173 mHandle(handle)
174{
175 ASSERT(mProgram);
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000176
177 resetUniformBlockBindings();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500178 unlink();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179}
180
181Program::~Program()
182{
183 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000184
Geoff Lang7dd2e102014-11-10 15:19:26 -0500185 SafeDelete(mProgram);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186}
187
188bool Program::attachShader(Shader *shader)
189{
190 if (shader->getType() == GL_VERTEX_SHADER)
191 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400192 if (mData.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193 {
194 return false;
195 }
196
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400197 mData.mAttachedVertexShader = shader;
198 mData.mAttachedVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000199 }
200 else if (shader->getType() == GL_FRAGMENT_SHADER)
201 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400202 if (mData.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 {
204 return false;
205 }
206
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400207 mData.mAttachedFragmentShader = shader;
208 mData.mAttachedFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 }
210 else UNREACHABLE();
211
212 return true;
213}
214
215bool Program::detachShader(Shader *shader)
216{
217 if (shader->getType() == GL_VERTEX_SHADER)
218 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400219 if (mData.mAttachedVertexShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220 {
221 return false;
222 }
223
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400224 shader->release();
225 mData.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226 }
227 else if (shader->getType() == GL_FRAGMENT_SHADER)
228 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400229 if (mData.mAttachedFragmentShader != shader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230 {
231 return false;
232 }
233
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400234 shader->release();
235 mData.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236 }
237 else UNREACHABLE();
238
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239 return true;
240}
241
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000242int Program::getAttachedShadersCount() const
243{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400244 return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000245}
246
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000247void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
248{
249 if (index < MAX_VERTEX_ATTRIBS)
250 {
251 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
252 {
253 mAttributeBinding[i].erase(name);
254 }
255
256 mAttributeBinding[index].insert(name);
257 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000258}
259
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260void Program::bindAttributeLocation(GLuint index, const char *name)
261{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000262 mAttributeBindings.bindAttributeLocation(index, name);
Geoff Lang0ca53782015-05-07 13:49:39 -0400263 mProgram->bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264}
265
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
267// compiling them into binaries, determining the attribute mappings, and collecting
268// a list of uniforms
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400269Error Program::link(const gl::Data &data)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000270{
271 unlink(false);
272
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000273 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000274 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000275
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400276 if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500277 {
278 return Error(GL_NO_ERROR);
279 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400280 ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500281
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400282 if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500283 {
284 return Error(GL_NO_ERROR);
285 }
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400286 ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500287
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400288 if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader))
Jamie Madill437d2662014-12-05 14:23:35 -0500289 {
290 return Error(GL_NO_ERROR);
291 }
292
Jamie Madillada9ecc2015-08-17 12:53:37 -0400293 if (!linkVaryings(mInfoLog, mData.mAttachedVertexShader, mData.mAttachedFragmentShader))
294 {
295 return Error(GL_NO_ERROR);
296 }
297
Geoff Lang7dd2e102014-11-10 15:19:26 -0500298 int registers;
299 std::vector<LinkedVarying> linkedVaryings;
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400300 rx::LinkResult result =
301 mProgram->link(data, mInfoLog, mData.mAttachedFragmentShader, mData.mAttachedVertexShader,
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400302 &registers, &linkedVaryings, &mOutputVariables);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500303 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
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400308 if (!mProgram->linkUniforms(mInfoLog, *mData.mAttachedVertexShader,
309 *mData.mAttachedFragmentShader, *data.caps))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500310 {
311 return Error(GL_NO_ERROR);
312 }
313
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400314 if (!linkUniformBlocks(mInfoLog, *mData.mAttachedVertexShader, *mData.mAttachedFragmentShader,
315 *data.caps))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500316 {
317 return Error(GL_NO_ERROR);
318 }
319
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400320 if (!gatherTransformFeedbackLinkedVaryings(
Jamie Madillada9ecc2015-08-17 12:53:37 -0400321 mInfoLog, linkedVaryings, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
Geoff Lang7dd2e102014-11-10 15:19:26 -0500322 {
323 return Error(GL_NO_ERROR);
324 }
325
326 // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
327 // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400328 result = mProgram->compileProgramExecutables(mInfoLog, registers);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500329 if (result.error.isError() || !result.linkSuccess)
330 {
Jamie Madillf6113162015-05-07 11:49:21 -0400331 mInfoLog << "Failed to create D3D shaders.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500332 unlink(false);
333 return result.error;
334 }
335
336 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400337 return gl::Error(GL_NO_ERROR);
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000338}
339
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000340int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000341{
342 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
343 {
344 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
345 {
346 return location;
347 }
348 }
349
350 return -1;
351}
352
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000353// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354void Program::unlink(bool destroy)
355{
356 if (destroy) // Object being destructed
357 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400358 if (mData.mAttachedFragmentShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400360 mData.mAttachedFragmentShader->release();
361 mData.mAttachedFragmentShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 }
363
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400364 if (mData.mAttachedVertexShader)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400366 mData.mAttachedVertexShader->release();
367 mData.mAttachedVertexShader = nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369 }
370
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400371 mLinkedAttributes.assign(mLinkedAttributes.size(), sh::Attribute());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500372 mOutputVariables.clear();
373
374 mProgram->reset();
375
376 mValidated = false;
377
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000378 mLinked = false;
379}
380
381bool Program::isLinked()
382{
383 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384}
385
Geoff Lang7dd2e102014-11-10 15:19:26 -0500386Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000387{
388 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000389
Geoff Lang7dd2e102014-11-10 15:19:26 -0500390#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
391 return Error(GL_NO_ERROR);
392#else
393 ASSERT(binaryFormat == mProgram->getBinaryFormat());
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000394
Geoff Lang7dd2e102014-11-10 15:19:26 -0500395 BinaryInputStream stream(binary, length);
396
397 GLenum format = stream.readInt<GLenum>();
398 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000399 {
Jamie Madillf6113162015-05-07 11:49:21 -0400400 mInfoLog << "Invalid program binary format.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500401 return Error(GL_NO_ERROR);
402 }
403
404 int majorVersion = stream.readInt<int>();
405 int minorVersion = stream.readInt<int>();
406 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
407 {
Jamie Madillf6113162015-05-07 11:49:21 -0400408 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500409 return Error(GL_NO_ERROR);
410 }
411
412 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
413 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
414 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
415 {
Jamie Madillf6113162015-05-07 11:49:21 -0400416 mInfoLog << "Invalid program binary version.";
Geoff Lang7dd2e102014-11-10 15:19:26 -0500417 return Error(GL_NO_ERROR);
418 }
419
Jamie Madill3da79b72015-04-27 11:09:17 -0400420 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500421 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
422 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400423 stream.readInt(&mLinkedAttributes[i].type);
424 stream.readString(&mLinkedAttributes[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500425 stream.readInt(&mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500426 }
427
Jamie Madill3da79b72015-04-27 11:09:17 -0400428 unsigned int attribCount = stream.readInt<unsigned int>();
429 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
430 {
431 GLenum type = stream.readInt<GLenum>();
432 GLenum precision = stream.readInt<GLenum>();
433 std::string name = stream.readString();
434 GLint arraySize = stream.readInt<GLint>();
435 int location = stream.readInt<int>();
436 mProgram->setShaderAttribute(attribIndex, type, precision, name, arraySize, location);
437 }
438
Jamie Madillada9ecc2015-08-17 12:53:37 -0400439 stream.readInt(&mData.mTransformFeedbackBufferMode);
440
Geoff Lang7dd2e102014-11-10 15:19:26 -0500441 rx::LinkResult result = mProgram->load(mInfoLog, &stream);
442 if (result.error.isError() || !result.linkSuccess)
443 {
Geoff Langb543aff2014-09-30 14:52:54 -0400444 return result.error;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000445 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000446
Geoff Lang7dd2e102014-11-10 15:19:26 -0500447 mLinked = true;
Geoff Langb543aff2014-09-30 14:52:54 -0400448 return Error(GL_NO_ERROR);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500449#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
450}
451
452Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
453{
454 if (binaryFormat)
455 {
456 *binaryFormat = mProgram->getBinaryFormat();
457 }
458
459 BinaryOutputStream stream;
460
461 stream.writeInt(mProgram->getBinaryFormat());
462 stream.writeInt(ANGLE_MAJOR_VERSION);
463 stream.writeInt(ANGLE_MINOR_VERSION);
464 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
465
Jamie Madill3da79b72015-04-27 11:09:17 -0400466 // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
Geoff Lang7dd2e102014-11-10 15:19:26 -0500467 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
468 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400469 stream.writeInt(mLinkedAttributes[i].type);
470 stream.writeString(mLinkedAttributes[i].name);
Jamie Madill437d2662014-12-05 14:23:35 -0500471 stream.writeInt(mProgram->getSemanticIndexes()[i]);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500472 }
473
Jamie Madill3da79b72015-04-27 11:09:17 -0400474 const auto &shaderAttributes = mProgram->getShaderAttributes();
475 stream.writeInt(shaderAttributes.size());
476 for (const auto &attrib : shaderAttributes)
477 {
478 stream.writeInt(attrib.type);
479 stream.writeInt(attrib.precision);
480 stream.writeString(attrib.name);
481 stream.writeInt(attrib.arraySize);
482 stream.writeInt(attrib.location);
483 }
484
Jamie Madillada9ecc2015-08-17 12:53:37 -0400485 stream.writeInt(mData.mTransformFeedbackBufferMode);
486
Geoff Lang7dd2e102014-11-10 15:19:26 -0500487 gl::Error error = mProgram->save(&stream);
488 if (error.isError())
489 {
490 return error;
491 }
492
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700493 GLsizei streamLength = static_cast<GLsizei>(stream.length());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500494 const void *streamData = stream.data();
495
496 if (streamLength > bufSize)
497 {
498 if (length)
499 {
500 *length = 0;
501 }
502
503 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
504 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
505 // sizes and then copy it.
506 return Error(GL_INVALID_OPERATION);
507 }
508
509 if (binary)
510 {
511 char *ptr = reinterpret_cast<char*>(binary);
512
513 memcpy(ptr, streamData, streamLength);
514 ptr += streamLength;
515
516 ASSERT(ptr - streamLength == binary);
517 }
518
519 if (length)
520 {
521 *length = streamLength;
522 }
523
524 return Error(GL_NO_ERROR);
525}
526
527GLint Program::getBinaryLength() const
528{
529 GLint length;
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400530 Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500531 if (error.isError())
532 {
533 return 0;
534 }
535
536 return length;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000537}
538
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000539void Program::release()
540{
541 mRefCount--;
542
543 if (mRefCount == 0 && mDeleteStatus)
544 {
545 mResourceManager->deleteProgram(mHandle);
546 }
547}
548
549void Program::addRef()
550{
551 mRefCount++;
552}
553
554unsigned int Program::getRefCount() const
555{
556 return mRefCount;
557}
558
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000559int Program::getInfoLogLength() const
560{
Jamie Madill71c3b2c2015-05-07 11:49:20 -0400561 return static_cast<int>(mInfoLog.getLength());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000562}
563
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000564void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
565{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000566 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000567}
568
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000569void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
570{
571 int total = 0;
572
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400573 if (mData.mAttachedVertexShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000574 {
575 if (total < maxCount)
576 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400577 shaders[total] = mData.mAttachedVertexShader->getHandle();
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000578 }
579
580 total++;
581 }
582
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400583 if (mData.mAttachedFragmentShader)
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000584 {
585 if (total < maxCount)
586 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400587 shaders[total] = mData.mAttachedFragmentShader->getHandle();
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000588 }
589
590 total++;
591 }
592
593 if (count)
594 {
595 *count = total;
596 }
597}
598
Geoff Lang7dd2e102014-11-10 15:19:26 -0500599GLuint Program::getAttributeLocation(const std::string &name)
600{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400601 for (size_t index = 0; index < mLinkedAttributes.size(); index++)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500602 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400603 if (mLinkedAttributes[index].name == name)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500604 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400605 return static_cast<GLuint>(index);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500606 }
607 }
608
Austin Kinrossb8af7232015-03-16 22:33:25 -0700609 return static_cast<GLuint>(-1);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500610}
611
Jamie Madill56c6e3c2015-04-15 10:18:05 -0400612const int *Program::getSemanticIndexes() const
613{
614 return mProgram->getSemanticIndexes();
615}
616
Jamie Madill46565a42015-06-22 13:57:21 -0400617int Program::getSemanticIndex(int attributeIndex) const
Geoff Lang7dd2e102014-11-10 15:19:26 -0500618{
619 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
620
Jamie Madill437d2662014-12-05 14:23:35 -0500621 return mProgram->getSemanticIndexes()[attributeIndex];
Geoff Lang7dd2e102014-11-10 15:19:26 -0500622}
623
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000624void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
625{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500626 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000627 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500628 // Skip over inactive attributes
629 unsigned int activeAttribute = 0;
630 unsigned int attribute;
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400631 for (attribute = 0; attribute < static_cast<unsigned int>(mLinkedAttributes.size());
632 attribute++)
Geoff Lang7dd2e102014-11-10 15:19:26 -0500633 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400634 if (mLinkedAttributes[attribute].name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500635 {
636 continue;
637 }
638
639 if (activeAttribute == index)
640 {
641 break;
642 }
643
644 activeAttribute++;
645 }
646
647 if (bufsize > 0)
648 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400649 const char *string = mLinkedAttributes[attribute].name.c_str();
Geoff Lang7dd2e102014-11-10 15:19:26 -0500650
651 strncpy(name, string, bufsize);
652 name[bufsize - 1] = '\0';
653
654 if (length)
655 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700656 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -0500657 }
658 }
659
660 *size = 1; // Always a single 'type' instance
661
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400662 *type = mLinkedAttributes[attribute].type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000663 }
664 else
665 {
666 if (bufsize > 0)
667 {
668 name[0] = '\0';
669 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500670
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000671 if (length)
672 {
673 *length = 0;
674 }
675
676 *type = GL_NONE;
677 *size = 1;
678 }
679}
680
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000681GLint Program::getActiveAttributeCount()
682{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500683 int count = 0;
684
685 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000686 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500687 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
688 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400689 if (!mLinkedAttributes[attributeIndex].name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500690 {
691 count++;
692 }
693 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000694 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500695
696 return count;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000697}
698
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000699GLint Program::getActiveAttributeMaxLength()
700{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400701 GLint maxLength = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500702
703 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000704 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500705 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
706 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400707 if (!mLinkedAttributes[attributeIndex].name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -0500708 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400709 maxLength = std::max(
710 static_cast<GLint>(mLinkedAttributes[attributeIndex].name.length() + 1),
711 maxLength);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500712 }
713 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000714 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500715
716 return maxLength;
717}
718
719// Returns one more than the highest sampler index used.
720GLint Program::getUsedSamplerRange(SamplerType type)
721{
722 return mProgram->getUsedSamplerRange(type);
723}
724
725bool Program::usesPointSize() const
726{
727 return mProgram->usesPointSize();
728}
729
730GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
731{
732 return mProgram->getSamplerMapping(type, samplerIndex, caps);
733}
734
735GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
736{
737 return mProgram->getSamplerTextureType(type, samplerIndex);
738}
739
740GLint Program::getFragDataLocation(const std::string &name) const
741{
742 std::string baseName(name);
743 unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400744 for (auto outputPair : mOutputVariables)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000745 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400746 const VariableLocation &outputVariable = outputPair.second;
Geoff Lang7dd2e102014-11-10 15:19:26 -0500747 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
748 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -0400749 return static_cast<GLint>(outputPair.first);
Geoff Lang7dd2e102014-11-10 15:19:26 -0500750 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000751 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500752 return -1;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000753}
754
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000755void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
756{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500757 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000758 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500759 ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
760 LinkedUniform *uniform = mProgram->getUniforms()[index];
761
762 if (bufsize > 0)
763 {
764 std::string string = uniform->name;
765 if (uniform->isArray())
766 {
767 string += "[0]";
768 }
769
770 strncpy(name, string.c_str(), bufsize);
771 name[bufsize - 1] = '\0';
772
773 if (length)
774 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700775 *length = static_cast<GLsizei>(strlen(name));
Geoff Lang7dd2e102014-11-10 15:19:26 -0500776 }
777 }
778
779 *size = uniform->elementCount();
780 *type = uniform->type;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000781 }
782 else
783 {
784 if (bufsize > 0)
785 {
786 name[0] = '\0';
787 }
788
789 if (length)
790 {
791 *length = 0;
792 }
793
794 *size = 0;
795 *type = GL_NONE;
796 }
797}
798
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000799GLint Program::getActiveUniformCount()
800{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500801 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000802 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700803 return static_cast<GLint>(mProgram->getUniforms().size());
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000804 }
805 else
806 {
807 return 0;
808 }
809}
810
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000811GLint Program::getActiveUniformMaxLength()
812{
Geoff Lang7dd2e102014-11-10 15:19:26 -0500813 int maxLength = 0;
814
815 if (mLinked)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000816 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700817 unsigned int numUniforms = static_cast<unsigned int>(mProgram->getUniforms().size());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500818 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
819 {
820 if (!mProgram->getUniforms()[uniformIndex]->name.empty())
821 {
822 int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
823 if (mProgram->getUniforms()[uniformIndex]->isArray())
824 {
825 length += 3; // Counting in "[0]".
826 }
827 maxLength = std::max(length, maxLength);
828 }
829 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000830 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500831
832 return maxLength;
833}
834
835GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
836{
837 const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
838 switch (pname)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000839 {
Geoff Lang7dd2e102014-11-10 15:19:26 -0500840 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
841 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
842 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
843 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
844 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
845 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
846 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
847 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
848 default:
849 UNREACHABLE();
850 break;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000851 }
Geoff Lang7dd2e102014-11-10 15:19:26 -0500852 return 0;
853}
854
855bool Program::isValidUniformLocation(GLint location) const
856{
Geoff Lang95137842015-06-02 15:38:43 -0400857 const auto &uniformIndices = mProgram->getUniformIndices();
858 ASSERT(rx::IsIntegerCastSafe<GLint>(uniformIndices.size()));
859 return (location >= 0 && uniformIndices.find(location) != uniformIndices.end());
Geoff Lang7dd2e102014-11-10 15:19:26 -0500860}
861
862LinkedUniform *Program::getUniformByLocation(GLint location) const
863{
864 return mProgram->getUniformByLocation(location);
865}
866
867LinkedUniform *Program::getUniformByName(const std::string &name) const
868{
869 return mProgram->getUniformByName(name);
870}
871
872GLint Program::getUniformLocation(const std::string &name)
873{
874 return mProgram->getUniformLocation(name);
875}
876
877GLuint Program::getUniformIndex(const std::string &name)
878{
879 return mProgram->getUniformIndex(name);
880}
881
882void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
883{
884 mProgram->setUniform1fv(location, count, v);
885}
886
887void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
888{
889 mProgram->setUniform2fv(location, count, v);
890}
891
892void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
893{
894 mProgram->setUniform3fv(location, count, v);
895}
896
897void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
898{
899 mProgram->setUniform4fv(location, count, v);
900}
901
902void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
903{
904 mProgram->setUniform1iv(location, count, v);
905}
906
907void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
908{
909 mProgram->setUniform2iv(location, count, v);
910}
911
912void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
913{
914 mProgram->setUniform3iv(location, count, v);
915}
916
917void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
918{
919 mProgram->setUniform4iv(location, count, v);
920}
921
922void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
923{
924 mProgram->setUniform1uiv(location, count, v);
925}
926
927void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
928{
929 mProgram->setUniform2uiv(location, count, v);
930}
931
932void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
933{
934 mProgram->setUniform3uiv(location, count, v);
935}
936
937void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
938{
939 mProgram->setUniform4uiv(location, count, v);
940}
941
942void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
943{
944 mProgram->setUniformMatrix2fv(location, count, transpose, v);
945}
946
947void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
948{
949 mProgram->setUniformMatrix3fv(location, count, transpose, v);
950}
951
952void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
953{
954 mProgram->setUniformMatrix4fv(location, count, transpose, v);
955}
956
957void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
958{
959 mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
960}
961
962void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
963{
964 mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
965}
966
967void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
968{
969 mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
970}
971
972void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
973{
974 mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
975}
976
977void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
978{
979 mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
980}
981
982void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
983{
984 mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
985}
986
987void Program::getUniformfv(GLint location, GLfloat *v)
988{
989 mProgram->getUniformfv(location, v);
990}
991
992void Program::getUniformiv(GLint location, GLint *v)
993{
994 mProgram->getUniformiv(location, v);
995}
996
997void Program::getUniformuiv(GLint location, GLuint *v)
998{
999 mProgram->getUniformuiv(location, v);
1000}
1001
1002// Applies all the uniforms set for this program object to the renderer
1003Error Program::applyUniforms()
1004{
1005 return mProgram->applyUniforms();
1006}
1007
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001008Error Program::applyUniformBuffers(const gl::Data &data)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001009{
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001010 return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001011}
1012
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001013void Program::flagForDeletion()
1014{
1015 mDeleteStatus = true;
1016}
1017
1018bool Program::isFlaggedForDeletion() const
1019{
1020 return mDeleteStatus;
1021}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001022
Brandon Jones43a53e22014-08-28 16:23:22 -07001023void Program::validate(const Caps &caps)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001024{
1025 mInfoLog.reset();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001026 mValidated = false;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001027
Geoff Lang7dd2e102014-11-10 15:19:26 -05001028 if (mLinked)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001029 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001030 applyUniforms();
1031 mValidated = mProgram->validateSamplers(&mInfoLog, caps);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001032 }
1033 else
1034 {
Jamie Madillf6113162015-05-07 11:49:21 -04001035 mInfoLog << "Program has not been successfully linked.";
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001036 }
1037}
1038
Geoff Lang7dd2e102014-11-10 15:19:26 -05001039bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
1040{
1041 return mProgram->validateSamplers(infoLog, caps);
1042}
1043
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001044bool Program::isValidated() const
1045{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001046 return mValidated;
1047}
1048
1049void Program::updateSamplerMapping()
1050{
1051 return mProgram->updateSamplerMapping();
1052}
1053
1054GLuint Program::getActiveUniformBlockCount()
1055{
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001056 return static_cast<GLuint>(mProgram->getUniformBlocks().size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001057}
1058
1059void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
1060{
1061 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1062
1063 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1064
1065 if (bufSize > 0)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001066 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001067 std::string string = uniformBlock.name;
1068
1069 if (uniformBlock.isArrayElement())
1070 {
1071 string += ArrayString(uniformBlock.elementIndex);
1072 }
1073
1074 strncpy(uniformBlockName, string.c_str(), bufSize);
1075 uniformBlockName[bufSize - 1] = '\0';
1076
1077 if (length)
1078 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001079 *length = static_cast<GLsizei>(strlen(uniformBlockName));
Geoff Lang7dd2e102014-11-10 15:19:26 -05001080 }
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +00001081 }
1082}
1083
Geoff Lang7dd2e102014-11-10 15:19:26 -05001084void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001085{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001086 ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
1087
1088 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1089
1090 switch (pname)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001091 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001092 case GL_UNIFORM_BLOCK_DATA_SIZE:
1093 *params = static_cast<GLint>(uniformBlock.dataSize);
1094 break;
1095 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1096 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
1097 break;
1098 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1099 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
1100 break;
1101 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1102 {
1103 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1104 {
1105 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1106 }
1107 }
1108 break;
1109 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1110 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
1111 break;
1112 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1113 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
1114 break;
1115 default: UNREACHABLE();
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001116 }
1117}
1118
1119GLint Program::getActiveUniformBlockMaxLength()
1120{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001121 int maxLength = 0;
1122
1123 if (mLinked)
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001124 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001125 unsigned int numUniformBlocks =
1126 static_cast<unsigned int>(mProgram->getUniformBlocks().size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001127 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
1128 {
1129 const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
1130 if (!uniformBlock.name.empty())
1131 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001132 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001133
1134 // Counting in "[0]".
1135 const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
1136
1137 maxLength = std::max(length + arrayLength, maxLength);
1138 }
1139 }
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001140 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001141
1142 return maxLength;
1143}
1144
1145GLuint Program::getUniformBlockIndex(const std::string &name)
1146{
1147 return mProgram->getUniformBlockIndex(name);
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00001148}
1149
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001150const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
1151{
1152 return mProgram->getUniformBlockByIndex(index);
1153}
1154
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00001155void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
1156{
1157 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
1158}
1159
1160GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
1161{
1162 return mUniformBlockBindings[uniformBlockIndex];
1163}
1164
1165void Program::resetUniformBlockBindings()
1166{
1167 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
1168 {
1169 mUniformBlockBindings[blockId] = 0;
1170 }
1171}
1172
Geoff Lang48dcae72014-02-05 16:28:24 -05001173void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
1174{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001175 mData.mTransformFeedbackVaryings.resize(count);
Geoff Lang48dcae72014-02-05 16:28:24 -05001176 for (GLsizei i = 0; i < count; i++)
1177 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001178 mData.mTransformFeedbackVaryings[i] = varyings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001179 }
1180
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001181 mData.mTransformFeedbackBufferMode = bufferMode;
Geoff Lang48dcae72014-02-05 16:28:24 -05001182}
1183
1184void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
1185{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001186 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001187 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001188 ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
1189 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
Geoff Lang48dcae72014-02-05 16:28:24 -05001190 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
1191 if (length)
1192 {
1193 *length = lastNameIdx;
1194 }
1195 if (size)
1196 {
1197 *size = varying.size;
1198 }
1199 if (type)
1200 {
1201 *type = varying.type;
1202 }
1203 if (name)
1204 {
1205 memcpy(name, varying.name.c_str(), lastNameIdx);
1206 name[lastNameIdx] = '\0';
1207 }
1208 }
1209}
1210
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001211GLsizei Program::getTransformFeedbackVaryingCount() const
1212{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001213 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001214 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001215 return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001216 }
1217 else
1218 {
1219 return 0;
1220 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001221}
1222
1223GLsizei Program::getTransformFeedbackVaryingMaxLength() const
1224{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001225 if (mLinked)
Geoff Lang48dcae72014-02-05 16:28:24 -05001226 {
1227 GLsizei maxSize = 0;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001228 for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001229 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001230 const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001231 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
1232 }
1233
1234 return maxSize;
1235 }
1236 else
1237 {
1238 return 0;
1239 }
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001240}
1241
1242GLenum Program::getTransformFeedbackBufferMode() const
1243{
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001244 return mData.mTransformFeedbackBufferMode;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001245}
1246
Jamie Madillada9ecc2015-08-17 12:53:37 -04001247// static
1248bool Program::linkVaryings(InfoLog &infoLog,
1249 const Shader *vertexShader,
1250 const Shader *fragmentShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001251{
Jamie Madillada9ecc2015-08-17 12:53:37 -04001252 const std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
1253 const std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001254
Jamie Madillada9ecc2015-08-17 12:53:37 -04001255 for (const PackedVarying &output : fragmentVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001256 {
Geoff Lang7dd2e102014-11-10 15:19:26 -05001257 bool matched = false;
1258
1259 // Built-in varyings obey special rules
Jamie Madillada9ecc2015-08-17 12:53:37 -04001260 if (output.isBuiltIn())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001261 {
1262 continue;
1263 }
1264
Jamie Madillada9ecc2015-08-17 12:53:37 -04001265 for (const PackedVarying &input : vertexVaryings)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001266 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001267 if (output.name == input.name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001268 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001269 ASSERT(!input.isBuiltIn());
1270 if (!linkValidateVaryings(infoLog, output.name, input, output))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001271 {
1272 return false;
1273 }
1274
Geoff Lang7dd2e102014-11-10 15:19:26 -05001275 matched = true;
1276 break;
1277 }
1278 }
1279
1280 // We permit unmatched, unreferenced varyings
Jamie Madillada9ecc2015-08-17 12:53:37 -04001281 if (!matched && output.staticUse)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001282 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001283 infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001284 return false;
1285 }
1286 }
1287
Jamie Madillada9ecc2015-08-17 12:53:37 -04001288 // TODO(jmadill): verify no unmatched vertex varyings?
1289
Geoff Lang7dd2e102014-11-10 15:19:26 -05001290 return true;
1291}
1292
1293bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1294{
1295 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
1296 {
1297 return false;
1298 }
1299
1300 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
1301 {
Jamie Madillf6113162015-05-07 11:49:21 -04001302 infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001303 return false;
1304 }
1305
1306 return true;
1307}
1308
1309// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001310bool Program::linkAttributes(const gl::Data &data,
Jamie Madill3da79b72015-04-27 11:09:17 -04001311 InfoLog &infoLog,
1312 const AttributeBindings &attributeBindings,
1313 const Shader *vertexShader)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001314{
Geoff Lang7dd2e102014-11-10 15:19:26 -05001315 unsigned int usedLocations = 0;
1316 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
Jamie Madill3da79b72015-04-27 11:09:17 -04001317 GLuint maxAttribs = data.caps->maxVertexAttributes;
1318
1319 // TODO(jmadill): handle aliasing robustly
Jamie Madill8e695ed2015-06-15 17:00:44 -04001320 if (shaderAttributes.size() > maxAttribs)
Jamie Madill3da79b72015-04-27 11:09:17 -04001321 {
Jamie Madillf6113162015-05-07 11:49:21 -04001322 infoLog << "Too many vertex attributes.";
Jamie Madill3da79b72015-04-27 11:09:17 -04001323 return false;
1324 }
Geoff Lang7dd2e102014-11-10 15:19:26 -05001325
1326 // Link attributes that have a binding location
1327 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1328 {
1329 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1330
1331 ASSERT(attribute.staticUse);
1332
1333 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1334
Jamie Madill3da79b72015-04-27 11:09:17 -04001335 mProgram->setShaderAttribute(attributeIndex, attribute);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001336
1337 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
1338 {
1339 const int rows = VariableRegisterCount(attribute.type);
1340
Jamie Madill3da79b72015-04-27 11:09:17 -04001341 if (static_cast<GLuint>(rows + location) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001342 {
Jamie Madillf6113162015-05-07 11:49:21 -04001343 infoLog << "Active attribute (" << attribute.name << ") at location "
1344 << location << " is too big to fit";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001345
1346 return false;
1347 }
1348
1349 for (int row = 0; row < rows; row++)
1350 {
1351 const int rowLocation = location + row;
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001352 sh::ShaderVariable *linkedAttribute = &mLinkedAttributes[rowLocation];
Geoff Lang7dd2e102014-11-10 15:19:26 -05001353
1354 // In GLSL 3.00, attribute aliasing produces a link error
Jamie Madill3da79b72015-04-27 11:09:17 -04001355 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
1356 // TODO(jmadill): fix aliasing on ES2
1357 // if (mProgram->getShaderVersion() >= 300)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001358 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001359 if (!linkedAttribute->name.empty())
Geoff Lang7dd2e102014-11-10 15:19:26 -05001360 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001361 infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
1362 << linkedAttribute->name << "' at location " << rowLocation;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001363 return false;
1364 }
1365 }
1366
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001367 *linkedAttribute = attribute;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001368 usedLocations |= 1 << rowLocation;
1369 }
1370 }
1371 }
1372
1373 // Link attributes that don't have a binding location
1374 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
1375 {
1376 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1377
1378 ASSERT(attribute.staticUse);
1379
1380 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
1381
1382 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
1383 {
1384 int rows = VariableRegisterCount(attribute.type);
Jamie Madill3da79b72015-04-27 11:09:17 -04001385 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, maxAttribs);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001386
Jamie Madill3da79b72015-04-27 11:09:17 -04001387 if (availableIndex == -1 || static_cast<GLuint>(availableIndex + rows) > maxAttribs)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001388 {
Jamie Madillf6113162015-05-07 11:49:21 -04001389 infoLog << "Too many active attributes (" << attribute.name << ")";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001390 return false; // Fail to link
1391 }
1392
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001393 mLinkedAttributes[availableIndex] = attribute;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001394 }
1395 }
1396
Jamie Madill3da79b72015-04-27 11:09:17 -04001397 for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398 {
Jamie Madill5c6b7bf2015-08-17 12:53:35 -04001399 int index = vertexShader->getSemanticIndex(mLinkedAttributes[attributeIndex].name);
1400 int rows = VariableRegisterCount(mLinkedAttributes[attributeIndex].type);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001401
1402 for (int r = 0; r < rows; r++)
1403 {
Jamie Madill437d2662014-12-05 14:23:35 -05001404 mProgram->getSemanticIndexes()[attributeIndex++] = index++;
Geoff Lang7dd2e102014-11-10 15:19:26 -05001405 }
1406 }
1407
Geoff Lang7dd2e102014-11-10 15:19:26 -05001408 return true;
1409}
1410
1411bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
1412{
1413 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1414 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
1415 // Check that interface blocks defined in the vertex and fragment shaders are identical
1416 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
1417 UniformBlockMap linkedUniformBlocks;
1418 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1419 {
1420 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
1421 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
1422 }
1423 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1424 {
1425 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
1426 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
1427 if (entry != linkedUniformBlocks.end())
1428 {
1429 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
1430 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1431 {
1432 return false;
1433 }
1434 }
1435 }
1436 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1437 {
1438 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
1439 // Note: shared and std140 layouts are always considered active
1440 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1441 {
1442 if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
1443 {
1444 return false;
1445 }
1446 }
1447 }
1448 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1449 {
1450 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
1451 // Note: shared and std140 layouts are always considered active
1452 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
1453 {
1454 if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
1455 {
1456 return false;
1457 }
1458 }
1459 }
1460 return true;
1461}
1462
1463bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
1464 const sh::InterfaceBlock &fragmentInterfaceBlock)
1465{
1466 const char* blockName = vertexInterfaceBlock.name.c_str();
1467 // validate blocks for the same member types
1468 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
1469 {
Jamie Madillf6113162015-05-07 11:49:21 -04001470 infoLog << "Types for interface block '" << blockName
1471 << "' differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001472 return false;
1473 }
1474 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1475 {
Jamie Madillf6113162015-05-07 11:49:21 -04001476 infoLog << "Array sizes differ for interface block '" << blockName
1477 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478 return false;
1479 }
1480 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1481 {
Jamie Madillf6113162015-05-07 11:49:21 -04001482 infoLog << "Layout qualifiers differ for interface block '" << blockName
1483 << "' between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001484 return false;
1485 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001486 const unsigned int numBlockMembers =
1487 static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001488 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1489 {
1490 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1491 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
1492 if (vertexMember.name != fragmentMember.name)
1493 {
Jamie Madillf6113162015-05-07 11:49:21 -04001494 infoLog << "Name mismatch for field " << blockMemberIndex
1495 << " of interface block '" << blockName
1496 << "': (in vertex: '" << vertexMember.name
1497 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001498 return false;
1499 }
1500 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1501 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
1502 {
1503 return false;
1504 }
1505 }
1506 return true;
1507}
1508
1509bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1510 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
1511{
1512 if (vertexVariable.type != fragmentVariable.type)
1513 {
Jamie Madillf6113162015-05-07 11:49:21 -04001514 infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515 return false;
1516 }
1517 if (vertexVariable.arraySize != fragmentVariable.arraySize)
1518 {
Jamie Madillf6113162015-05-07 11:49:21 -04001519 infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001520 return false;
1521 }
1522 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
1523 {
Jamie Madillf6113162015-05-07 11:49:21 -04001524 infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001525 return false;
1526 }
1527
1528 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
1529 {
Jamie Madillf6113162015-05-07 11:49:21 -04001530 infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001531 return false;
1532 }
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001533 const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
Geoff Lang7dd2e102014-11-10 15:19:26 -05001534 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1535 {
1536 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1537 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
1538
1539 if (vertexMember.name != fragmentMember.name)
1540 {
Jamie Madillf6113162015-05-07 11:49:21 -04001541 infoLog << "Name mismatch for field '" << memberIndex
1542 << "' of " << variableName
1543 << ": (in vertex: '" << vertexMember.name
1544 << "', in fragment: '" << fragmentMember.name << "')";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001545 return false;
1546 }
1547
1548 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1549 vertexMember.name + "'";
1550
1551 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
1552 {
1553 return false;
1554 }
1555 }
1556
1557 return true;
1558}
1559
1560bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1561{
Cooper Partin1acf4382015-06-12 12:38:57 -07001562#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
1563 const bool validatePrecision = true;
1564#else
1565 const bool validatePrecision = false;
1566#endif
1567
1568 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569 {
1570 return false;
1571 }
1572
1573 return true;
1574}
1575
1576bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1577{
1578 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1579 {
1580 return false;
1581 }
1582
Jamie Madille9cc4692015-02-19 16:00:13 -05001583 if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
Geoff Lang7dd2e102014-11-10 15:19:26 -05001584 {
Jamie Madillf6113162015-05-07 11:49:21 -04001585 infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001586 return false;
1587 }
1588
1589 return true;
1590}
1591
1592bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
Geoff Lang7dd2e102014-11-10 15:19:26 -05001593 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
1594 const Caps &caps) const
1595{
1596 size_t totalComponents = 0;
1597
1598 // Gather the linked varyings that are used for transform feedback, they should all exist.
1599 outTransformFeedbackLinkedVaryings->clear();
Jamie Madillada9ecc2015-08-17 12:53:37 -04001600 for (size_t i = 0; i < mData.mTransformFeedbackVaryings.size(); i++)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001601 {
1602 bool found = false;
1603 for (size_t j = 0; j < linkedVaryings.size(); j++)
1604 {
Jamie Madillada9ecc2015-08-17 12:53:37 -04001605 if (mData.mTransformFeedbackVaryings[i] == linkedVaryings[j].name)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001606 {
1607 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
1608 {
1609 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
1610 {
Jamie Madillf6113162015-05-07 11:49:21 -04001611 infoLog << "Two transform feedback varyings specify the same output variable ("
1612 << linkedVaryings[j].name << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001613 return false;
1614 }
1615 }
1616
1617 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
Jamie Madillada9ecc2015-08-17 12:53:37 -04001618 if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang7dd2e102014-11-10 15:19:26 -05001619 componentCount > caps.maxTransformFeedbackSeparateComponents)
1620 {
Jamie Madillf6113162015-05-07 11:49:21 -04001621 infoLog << "Transform feedback varying's " << linkedVaryings[j].name
1622 << " components (" << componentCount
1623 << ") exceed the maximum separate components ("
1624 << caps.maxTransformFeedbackSeparateComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001625 return false;
1626 }
1627
1628 totalComponents += componentCount;
1629
1630 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
1631 found = true;
1632 break;
1633 }
1634 }
1635
1636 // All transform feedback varyings are expected to exist since packVaryings checks for them.
1637 ASSERT(found);
Corentin Wallez54c34e02015-07-02 15:06:55 -04001638 UNUSED_ASSERTION_VARIABLE(found);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001639 }
1640
Jamie Madillada9ecc2015-08-17 12:53:37 -04001641 if (mData.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
Jamie Madillf6113162015-05-07 11:49:21 -04001642 totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang7dd2e102014-11-10 15:19:26 -05001643 {
Jamie Madillf6113162015-05-07 11:49:21 -04001644 infoLog << "Transform feedback varying total components (" << totalComponents
1645 << ") exceed the maximum interleaved components ("
1646 << caps.maxTransformFeedbackInterleavedComponents << ").";
Geoff Lang7dd2e102014-11-10 15:19:26 -05001647 return false;
1648 }
1649
1650 return true;
Geoff Lang1b6edcb2014-02-03 14:27:56 -05001651}
1652
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001653}