blob: 47f11f9fd01d231173512b4481384f7fd70cf2e0 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
Geoff Lang48dcae72014-02-05 16:28:24 -05003// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
Nicolas Capense6050882013-07-08 10:43:10 -040024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
Jamie Madill5f562732014-02-14 16:41:24 -050026#include "libGLESv2/DynamicHLSL.h"
Jamie Madillc2141fb2013-08-30 13:21:08 -040027
daniel@transgaming.com88853c52012-12-20 20:56:40 +000028#undef near
29#undef far
30
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031namespace gl
32{
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000033
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000034namespace
35{
36
Jamie Madill8ff21ae2014-02-04 16:04:05 -050037unsigned int ParseAndStripArrayIndex(std::string* name)
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000038{
39 unsigned int subscript = GL_INVALID_INDEX;
40
41 // Strip any trailing array operator and retrieve the subscript
42 size_t open = name->find_last_of('[');
43 size_t close = name->find_last_of(']');
44 if (open != std::string::npos && close == name->length() - 1)
45 {
46 subscript = atoi(name->substr(open + 1).c_str());
47 name->erase(open);
48 }
49
50 return subscript;
51}
52
Jamie Madillc5a83002014-02-14 16:41:25 -050053void GetInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
54{
Jamie Madill3b7e2052014-03-17 09:47:43 -040055 size_t layoutIndex = 0;
Jamie Madillc5a83002014-02-14 16:41:25 -050056 for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
57 {
Jamie Madill3b7e2052014-03-17 09:47:43 -040058 ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS);
59
Jamie Madillc5a83002014-02-14 16:41:25 -050060 const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -050061
62 if (shaderAttr.type != GL_NONE)
63 {
Jamie Madill3b7e2052014-03-17 09:47:43 -040064 for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(shaderAttr.type); rowIndex++, layoutIndex++)
65 {
66 VertexFormat *defaultFormat = &inputLayout[layoutIndex];
67
68 defaultFormat->mType = UniformComponentType(shaderAttr.type);
69 defaultFormat->mNormalized = false;
70 defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
71 defaultFormat->mComponents = VariableColumnCount(shaderAttr.type);
72 }
Jamie Madillc5a83002014-02-14 16:41:25 -050073 }
74 }
75}
76
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000077}
78
Jamie Madill63491ea2013-06-06 11:56:45 -040079VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +000080 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000081{
82}
83
Jamie Madillc5a83002014-02-14 16:41:25 -050084ProgramBinary::VertexExecutable::VertexExecutable(rx::Renderer *const renderer,
85 const VertexFormat inputLayout[],
86 rx::ShaderExecutable *shaderExecutable)
87 : mShaderExecutable(shaderExecutable)
88{
89 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
90 {
91 mInputs[attributeIndex] = inputLayout[attributeIndex];
92 }
93}
94
95bool ProgramBinary::VertexExecutable::matchesInputLayout(const VertexFormat attributes[]) const
96{
97 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
98 {
99 if (mInputs[attributeIndex] != attributes[attributeIndex])
100 {
101 return false;
102 }
103 }
104
105 return true;
106}
107
Geoff Lang48dcae72014-02-05 16:28:24 -0500108LinkedVarying::LinkedVarying()
109{
110}
111
112LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
113 unsigned int semanticIndex, unsigned int semanticIndexCount)
114 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
115{
116}
117
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000118unsigned int ProgramBinary::mCurrentSerial = 1;
119
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500120ProgramBinary::ProgramBinary(rx::Renderer *renderer)
121 : RefCountObject(0),
122 mRenderer(renderer),
Jamie Madill5f562732014-02-14 16:41:24 -0500123 mDynamicHLSL(NULL),
Jamie Madillc5a83002014-02-14 16:41:25 -0500124 mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500125 mPixelExecutable(NULL),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500126 mGeometryExecutable(NULL),
127 mUsedVertexSamplerRange(0),
128 mUsedPixelSamplerRange(0),
129 mUsesPointSize(false),
130 mShaderVersion(100),
131 mVertexUniformStorage(NULL),
132 mFragmentUniformStorage(NULL),
133 mValidated(false),
134 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
137 {
138 mSemanticIndex[index] = -1;
139 }
140
141 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
142 {
143 mSamplersPS[index].active = false;
144 }
145
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000146 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000147 {
148 mSamplersVS[index].active = false;
149 }
Jamie Madill5f562732014-02-14 16:41:24 -0500150
151 mDynamicHLSL = new DynamicHLSL(renderer);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000152}
153
154ProgramBinary::~ProgramBinary()
155{
Jamie Madillc5a83002014-02-14 16:41:25 -0500156 while (!mVertexExecutables.empty())
157 {
158 delete mVertexExecutables.back();
159 mVertexExecutables.pop_back();
160 }
161
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500162 SafeDelete(mGeometryExecutable);
Jamie Madillc5a83002014-02-14 16:41:25 -0500163 SafeDelete(mPixelExecutable);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000164
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000165 while (!mUniforms.empty())
166 {
167 delete mUniforms.back();
168 mUniforms.pop_back();
169 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000170
171 while (!mUniformBlocks.empty())
172 {
173 delete mUniformBlocks.back();
174 mUniformBlocks.pop_back();
175 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500176
177 SafeDelete(mVertexUniformStorage);
178 SafeDelete(mFragmentUniformStorage);
Jamie Madill5f562732014-02-14 16:41:24 -0500179 SafeDelete(mDynamicHLSL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000180}
181
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000182unsigned int ProgramBinary::getSerial() const
183{
184 return mSerial;
185}
186
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000187int ProgramBinary::getShaderVersion() const
188{
189 return mShaderVersion;
190}
191
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000192unsigned int ProgramBinary::issueSerial()
193{
194 return mCurrentSerial++;
195}
196
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500197rx::ShaderExecutable *ProgramBinary::getPixelExecutable() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000198{
199 return mPixelExecutable;
200}
201
Jamie Madillc5a83002014-02-14 16:41:25 -0500202rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000203{
Jamie Madillc5a83002014-02-14 16:41:25 -0500204 for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
205 {
206 if (mVertexExecutables[executableIndex]->matchesInputLayout(inputLayout))
207 {
208 return mVertexExecutables[executableIndex]->shaderExecutable();
209 }
210 }
211
Jamie Madillc5ede1a2014-02-14 16:41:27 -0500212 // Generate new dynamic layout with attribute conversions
213 const std::string &layoutHLSL = mDynamicHLSL->generateInputLayoutHLSL(inputLayout, mShaderAttributes);
214
215 // Generate new shader source by replacing the attributes stub with the defined input layout
216 std::string vertexHLSL = mVertexHLSL;
217 size_t insertPos = vertexHLSL.find(DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING);
218 vertexHLSL.replace(insertPos, DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING.length(), layoutHLSL);
219
Jamie Madillc5a83002014-02-14 16:41:25 -0500220 // Generate new vertex executable
221 InfoLog tempInfoLog;
Geoff Lang48dcae72014-02-05 16:28:24 -0500222 rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, vertexHLSL.c_str(),
223 rx::SHADER_VERTEX,
224 mTransformFeedbackLinkedVaryings,
225 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
226 mVertexWorkarounds);
Jamie Madillc5a83002014-02-14 16:41:25 -0500227
228 if (!vertexExecutable)
229 {
230 std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
231 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
232 ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
233 }
234 else
235 {
236 mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, vertexExecutable));
237 }
238
239 return vertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000240}
241
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500242rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000243{
244 return mGeometryExecutable;
245}
246
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000247GLuint ProgramBinary::getAttributeLocation(const char *name)
248{
249 if (name)
250 {
251 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
252 {
253 if (mLinkedAttribute[index].name == std::string(name))
254 {
255 return index;
256 }
257 }
258 }
259
260 return -1;
261}
262
263int ProgramBinary::getSemanticIndex(int attributeIndex)
264{
265 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
266
267 return mSemanticIndex[attributeIndex];
268}
269
270// Returns one more than the highest sampler index used.
271GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
272{
273 switch (type)
274 {
275 case SAMPLER_PIXEL:
276 return mUsedPixelSamplerRange;
277 case SAMPLER_VERTEX:
278 return mUsedVertexSamplerRange;
279 default:
280 UNREACHABLE();
281 return 0;
282 }
283}
284
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000285bool ProgramBinary::usesPointSize() const
286{
287 return mUsesPointSize;
288}
289
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000290bool ProgramBinary::usesPointSpriteEmulation() const
291{
292 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
293}
294
295bool ProgramBinary::usesGeometryShader() const
296{
297 return usesPointSpriteEmulation();
298}
299
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000300// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
301// index (0-15 for the pixel shader and 0-3 for the vertex shader).
302GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
303{
304 GLint logicalTextureUnit = -1;
305
306 switch (type)
307 {
308 case SAMPLER_PIXEL:
309 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
310
311 if (mSamplersPS[samplerIndex].active)
312 {
313 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
314 }
315 break;
316 case SAMPLER_VERTEX:
317 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
318
319 if (mSamplersVS[samplerIndex].active)
320 {
321 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
322 }
323 break;
324 default: UNREACHABLE();
325 }
326
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000327 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000328 {
329 return logicalTextureUnit;
330 }
331
332 return -1;
333}
334
335// Returns the texture type for a given Direct3D 9 sampler type and
336// index (0-15 for the pixel shader and 0-3 for the vertex shader).
337TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
338{
339 switch (type)
340 {
341 case SAMPLER_PIXEL:
342 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
343 ASSERT(mSamplersPS[samplerIndex].active);
344 return mSamplersPS[samplerIndex].textureType;
345 case SAMPLER_VERTEX:
346 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
347 ASSERT(mSamplersVS[samplerIndex].active);
348 return mSamplersVS[samplerIndex].textureType;
349 default: UNREACHABLE();
350 }
351
352 return TEXTURE_2D;
353}
354
355GLint ProgramBinary::getUniformLocation(std::string name)
356{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500357 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000358
359 unsigned int numUniforms = mUniformIndex.size();
360 for (unsigned int location = 0; location < numUniforms; location++)
361 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000362 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000363 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000364 const int index = mUniformIndex[location].index;
365 const bool isArray = mUniforms[index]->isArray();
366
367 if ((isArray && mUniformIndex[location].element == subscript) ||
368 (subscript == GL_INVALID_INDEX))
369 {
370 return location;
371 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372 }
373 }
374
375 return -1;
376}
377
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000378GLuint ProgramBinary::getUniformIndex(std::string name)
379{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500380 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000381
382 // The app is not allowed to specify array indices other than 0 for arrays of basic types
383 if (subscript != 0 && subscript != GL_INVALID_INDEX)
384 {
385 return GL_INVALID_INDEX;
386 }
387
388 unsigned int numUniforms = mUniforms.size();
389 for (unsigned int index = 0; index < numUniforms; index++)
390 {
391 if (mUniforms[index]->name == name)
392 {
393 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
394 {
395 return index;
396 }
397 }
398 }
399
400 return GL_INVALID_INDEX;
401}
402
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000403GLuint ProgramBinary::getUniformBlockIndex(std::string name)
404{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500405 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000406
407 unsigned int numUniformBlocks = mUniformBlocks.size();
408 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
409 {
410 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
411 if (uniformBlock.name == name)
412 {
413 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
414 if (subscript == uniformBlock.elementIndex || arrayElementZero)
415 {
416 return blockIndex;
417 }
418 }
419 }
420
421 return GL_INVALID_INDEX;
422}
423
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000424UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
425{
426 ASSERT(blockIndex < mUniformBlocks.size());
427 return mUniformBlocks[blockIndex];
428}
429
Jamie Madilld1e78c92013-06-20 11:55:50 -0400430GLint ProgramBinary::getFragDataLocation(const char *name) const
431{
432 std::string baseName(name);
433 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500434 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400435
436 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
437 {
438 const VariableLocation &outputVariable = locationIt->second;
439
440 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
441 {
442 return static_cast<GLint>(locationIt->first);
443 }
444 }
445
446 return -1;
447}
448
Geoff Lang48dcae72014-02-05 16:28:24 -0500449size_t ProgramBinary::getTransformFeedbackVaryingCount() const
450{
451 return mTransformFeedbackLinkedVaryings.size();
452}
453
454const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
455{
456 return mTransformFeedbackLinkedVaryings[idx];
457}
458
459GLenum ProgramBinary::getTransformFeedbackBufferMode() const
460{
461 return mTransformFeedbackBufferMode;
462}
463
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000464template <typename T>
465bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000466{
467 if (location < 0 || location >= (int)mUniformIndex.size())
468 {
469 return false;
470 }
471
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000472 const int components = UniformComponentCount(targetUniformType);
473 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
474
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000475 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
476 targetUniform->dirty = true;
477
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000478 int elementCount = targetUniform->elementCount();
479
480 if (elementCount == 1 && count > 1)
481 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
482
483 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
484
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000485 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000486 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000487 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000488
489 for (int i = 0; i < count; i++)
490 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000491 for (int c = 0; c < components; c++)
492 {
493 target[c] = v[c];
494 }
495 for (int c = components; c < 4; c++)
496 {
497 target[c] = 0;
498 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000499 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000500 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501 }
502 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000503 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000504 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000505 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000506
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000507 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000508 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000509 for (int c = 0; c < components; c++)
510 {
511 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
512 }
513 for (int c = components; c < 4; c++)
514 {
515 boolParams[c] = GL_FALSE;
516 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000517 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000518 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000519 }
520 }
521 else
522 {
523 return false;
524 }
525
526 return true;
527}
528
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000529bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
530{
531 return setUniform(location, count, v, GL_FLOAT);
532}
533
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000534bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
535{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000536 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000537}
538
539bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
540{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000541 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542}
543
544bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
545{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000546 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000547}
548
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000549template<typename T>
550void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000551{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000552 int copyWidth = std::min(targetHeight, srcWidth);
553 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000554
555 for (int x = 0; x < copyWidth; x++)
556 {
557 for (int y = 0; y < copyHeight; y++)
558 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000559 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560 }
561 }
562 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000563 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000564 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000565 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000566 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000567 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568 }
569 }
570 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000571 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000572 {
573 for (int x = 0; x < targetWidth; x++)
574 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000575 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000576 }
577 }
578}
579
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000580template<typename T>
581void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
582{
583 int copyWidth = std::min(targetWidth, srcWidth);
584 int copyHeight = std::min(targetHeight, srcHeight);
585
586 for (int y = 0; y < copyHeight; y++)
587 {
588 for (int x = 0; x < copyWidth; x++)
589 {
590 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
591 }
592 }
593 // clear unfilled right side
594 for (int y = 0; y < copyHeight; y++)
595 {
596 for (int x = copyWidth; x < targetWidth; x++)
597 {
598 target[y * targetWidth + x] = static_cast<T>(0);
599 }
600 }
601 // clear unfilled bottom.
602 for (int y = copyHeight; y < targetHeight; y++)
603 {
604 for (int x = 0; x < targetWidth; x++)
605 {
606 target[y * targetWidth + x] = static_cast<T>(0);
607 }
608 }
609}
610
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000611template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000612bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613{
614 if (location < 0 || location >= (int)mUniformIndex.size())
615 {
616 return false;
617 }
618
619 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
620 targetUniform->dirty = true;
621
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000622 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000623 {
624 return false;
625 }
626
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000627 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000629 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000630 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
631
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000632 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000633 const unsigned int targetMatrixStride = (4 * rows);
634 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000635
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000636 for (int i = 0; i < count; i++)
637 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000638 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
639 if (transpose == GL_FALSE)
640 {
641 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
642 }
643 else
644 {
645 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
646 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000647 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000648 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000649 }
650
651 return true;
652}
653
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000654bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000655{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000656 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000657}
658
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000659bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000660{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000661 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000662}
663
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000664bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000666 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667}
668
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000669bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000670{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000671 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000672}
673
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000674bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000675{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000676 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000677}
678
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000679bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000680{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000681 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000682}
683
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000684bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000685{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000686 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000687}
688
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000689bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000690{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000691 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000692}
693
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000694bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000695{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000696 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000697}
698
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000699bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
700{
701 if (location < 0 || location >= (int)mUniformIndex.size())
702 {
703 return false;
704 }
705
706 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
707 targetUniform->dirty = true;
708
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000709 int elementCount = targetUniform->elementCount();
710
711 if (elementCount == 1 && count > 1)
712 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
713
714 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
715
Nicolas Capense6050882013-07-08 10:43:10 -0400716 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000717 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000718 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000719
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000720 for (int i = 0; i < count; i++)
721 {
722 target[0] = v[0];
723 target[1] = 0;
724 target[2] = 0;
725 target[3] = 0;
726 target += 4;
727 v += 1;
728 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000729 }
730 else if (targetUniform->type == GL_BOOL)
731 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000732 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000734 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000735 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000736 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
737 boolParams[1] = GL_FALSE;
738 boolParams[2] = GL_FALSE;
739 boolParams[3] = GL_FALSE;
740 boolParams += 4;
741 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000742 }
743 }
744 else
745 {
746 return false;
747 }
748
749 return true;
750}
751
752bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
753{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000754 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755}
756
757bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
758{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000759 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000760}
761
762bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
763{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000764 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000765}
766
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000767bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
768{
769 return setUniform(location, count, v, GL_UNSIGNED_INT);
770}
771
772bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
773{
774 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
775}
776
777bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
778{
779 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
780}
781
782bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
783{
784 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
785}
786
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000787template <typename T>
788bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789{
790 if (location < 0 || location >= (int)mUniformIndex.size())
791 {
792 return false;
793 }
794
795 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
796
797 // sized queries -- ensure the provided buffer is large enough
798 if (bufSize)
799 {
800 int requiredBytes = UniformExternalSize(targetUniform->type);
801 if (*bufSize < requiredBytes)
802 {
803 return false;
804 }
805 }
806
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000807 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000808 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000809 const int rows = VariableRowCount(targetUniform->type);
810 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400811 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000812 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000813 else if (uniformType == UniformComponentType(targetUniform->type))
814 {
815 unsigned int size = UniformComponentCount(targetUniform->type);
816 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
817 size * sizeof(T));
818 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000819 else
820 {
821 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000822 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000823 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000824 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000825 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000826 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000827
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000828 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000829 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000830 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000831 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000832 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000833 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000834
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000835 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000836 {
837 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
838
839 for (unsigned int i = 0; i < size; i++)
840 {
841 params[i] = static_cast<T>(floatParams[i]);
842 }
843 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000844 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000845
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000846 case GL_INT:
847 {
848 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
849
850 for (unsigned int i = 0; i < size; i++)
851 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000852 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000853 }
854 }
855 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000856
857 case GL_UNSIGNED_INT:
858 {
859 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000860
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000861 for (unsigned int i = 0; i < size; i++)
862 {
863 params[i] = static_cast<T>(uintParams[i]);
864 }
865 }
866 break;
867
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000868 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000869 }
870 }
871
872 return true;
873}
874
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000875bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
876{
877 return getUniformv(location, bufSize, params, GL_FLOAT);
878}
879
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000880bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
881{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000882 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000883}
884
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000885bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
886{
887 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
888}
889
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000890void ProgramBinary::dirtyAllUniforms()
891{
892 unsigned int numUniforms = mUniforms.size();
893 for (unsigned int index = 0; index < numUniforms; index++)
894 {
895 mUniforms[index]->dirty = true;
896 }
897}
898
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000899// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000900void ProgramBinary::applyUniforms()
901{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000902 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500903 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000904 {
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500905 Uniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000906
907 if (targetUniform->dirty)
908 {
Nicolas Capense6050882013-07-08 10:43:10 -0400909 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000910 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000911 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000912 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000913
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000914 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000915 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000916 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000917
918 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000919 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000920 unsigned int samplerIndex = firstIndex + i;
921
922 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000923 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000924 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000925 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000926 }
927 }
928 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000929
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000930 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000931 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000932 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000933
934 for (int i = 0; i < count; i++)
935 {
936 unsigned int samplerIndex = firstIndex + i;
937
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000938 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000939 {
940 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000941 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000942 }
943 }
944 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000945 }
946 }
947 }
948
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500949 mRenderer->applyUniforms(*this);
950
951 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
952 {
953 mUniforms[uniformIndex]->dirty = false;
954 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000955}
956
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000957bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
958{
959 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
960 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
961
962 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
963 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
964
965 ASSERT(boundBuffers.size() == mUniformBlocks.size());
966
967 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
968 {
969 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
970 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
971
972 ASSERT(uniformBlock && uniformBuffer);
973
974 if (uniformBuffer->size() < uniformBlock->dataSize)
975 {
976 // undefined behaviour
977 return false;
978 }
979
980 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
981
982 if (uniformBlock->isReferencedByVertexShader())
983 {
984 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
985 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
986 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
987 vertexUniformBuffers[registerIndex] = uniformBuffer;
988 }
989
990 if (uniformBlock->isReferencedByFragmentShader())
991 {
992 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
993 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
994 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
995 fragmentUniformBuffers[registerIndex] = uniformBuffer;
996 }
997 }
998
999 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
1000}
1001
Jamie Madill5f562732014-02-14 16:41:24 -05001002bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001003{
Jamie Madill5f562732014-02-14 16:41:24 -05001004 std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
1005 std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
1006
1007 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001008 {
Jamie Madill5f562732014-02-14 16:41:24 -05001009 sh::Varying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001010 bool matched = false;
1011
Jamie Madill5f562732014-02-14 16:41:24 -05001012 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001013 {
Jamie Madill5f562732014-02-14 16:41:24 -05001014 sh::Varying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001015 if (output->name == input->name)
1016 {
Jamie Madill28167c62013-08-30 13:21:10 -04001017 if (!linkValidateVariables(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001018 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001019 return false;
1020 }
1021
Jamie Madill139b9092013-08-30 13:21:06 -04001022 output->registerIndex = input->registerIndex;
1023 output->elementIndex = input->elementIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001024
1025 matched = true;
1026 break;
1027 }
1028 }
1029
1030 if (!matched)
1031 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001032 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001033 return false;
1034 }
1035 }
1036
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001037 return true;
1038}
1039
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001040bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1041{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001042 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001043
1044 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001045 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001046 if (format != GL_PROGRAM_BINARY_ANGLE)
1047 {
1048 infoLog.append("Invalid program binary format.");
1049 return false;
1050 }
1051
Jamie Madill049108d2013-11-19 10:41:49 -05001052 int majorVersion = 0;
1053 int minorVersion = 0;
1054 stream.read(&majorVersion);
1055 stream.read(&minorVersion);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001056 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -05001057 {
1058 infoLog.append("Invalid program binary version.");
1059 return false;
1060 }
1061
Jamie Madill0aa84f62014-02-13 13:17:23 -05001062 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
1063 stream.read(commitString, ANGLE_COMMIT_HASH_SIZE);
1064 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001065 {
1066 infoLog.append("Invalid program binary version.");
1067 return false;
1068 }
1069
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001070 int compileFlags = 0;
1071 stream.read(&compileFlags);
1072 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1073 {
1074 infoLog.append("Mismatched compilation flags.");
1075 return false;
1076 }
1077
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001078 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1079 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001080 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001081 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001082 stream.read(&name);
1083 mLinkedAttribute[i].name = name;
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001084 stream.read(&mShaderAttributes[i].type);
1085 stream.read(&mShaderAttributes[i].name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001086 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001087 }
1088
Al Patrick3f2daa82013-08-07 12:58:57 -07001089 initAttributesByLayout();
1090
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001091 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1092 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001093 stream.read(&mSamplersPS[i].active);
1094 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001095
1096 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001097 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001098 mSamplersPS[i].textureType = (TextureType) textureType;
1099 }
1100
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001101 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001102 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001103 stream.read(&mSamplersVS[i].active);
1104 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001105
1106 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001107 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001108 mSamplersVS[i].textureType = (TextureType) textureType;
1109 }
1110
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001111 stream.read(&mUsedVertexSamplerRange);
1112 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001113 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001114 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001115
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001116 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001117 stream.read(&size);
1118 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001119 {
1120 infoLog.append("Invalid program binary.");
1121 return false;
1122 }
1123
1124 mUniforms.resize(size);
1125 for (unsigned int i = 0; i < size; ++i)
1126 {
1127 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001128 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001129 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001130 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001131 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001132
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001133 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001134 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001135 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001136 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001137 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001138
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001139 int offset;
1140 int arrayStride;
1141 int matrixStride;
1142 bool isRowMajorMatrix;
1143
1144 stream.read(&offset);
1145 stream.read(&arrayStride);
1146 stream.read(&matrixStride);
1147 stream.read(&isRowMajorMatrix);
1148
1149 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1150
1151 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001152
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001153 stream.read(&mUniforms[i]->psRegisterIndex);
1154 stream.read(&mUniforms[i]->vsRegisterIndex);
1155 stream.read(&mUniforms[i]->registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001156 stream.read(&mUniforms[i]->registerElement);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001157 }
1158
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001159 stream.read(&size);
1160 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001161 {
1162 infoLog.append("Invalid program binary.");
1163 return false;
1164 }
1165
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001166 mUniformBlocks.resize(size);
1167 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1168 {
1169 std::string name;
1170 unsigned int elementIndex;
1171 unsigned int dataSize;
1172
1173 stream.read(&name);
1174 stream.read(&elementIndex);
1175 stream.read(&dataSize);
1176
1177 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1178
1179 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1180 stream.read(&uniformBlock.psRegisterIndex);
1181 stream.read(&uniformBlock.vsRegisterIndex);
1182
1183 size_t numMembers;
1184 stream.read(&numMembers);
1185 uniformBlock.memberUniformIndexes.resize(numMembers);
1186 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1187 {
1188 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1189 }
1190 }
1191
1192 stream.read(&size);
1193 if (stream.error())
1194 {
1195 infoLog.append("Invalid program binary.");
1196 return false;
1197 }
1198
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001199 mUniformIndex.resize(size);
1200 for (unsigned int i = 0; i < size; ++i)
1201 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001202 stream.read(&mUniformIndex[i].name);
1203 stream.read(&mUniformIndex[i].element);
1204 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001205 }
1206
Geoff Lang48dcae72014-02-05 16:28:24 -05001207 stream.read(&mTransformFeedbackBufferMode);
1208 stream.read(&size);
1209 mTransformFeedbackLinkedVaryings.resize(size);
1210 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
1211 {
1212 LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
1213
1214 stream.read(&varying.name);
1215 stream.read(&varying.type);
1216 stream.read(&varying.size);
1217 stream.read(&varying.semanticName);
1218 stream.read(&varying.semanticIndex);
1219 stream.read(&varying.semanticIndexCount);
1220 }
1221
Jamie Madillc5a83002014-02-14 16:41:25 -05001222 stream.read(&mVertexHLSL);
1223 stream.read(&mVertexWorkarounds);
1224
1225 unsigned int vertexShaderCount;
1226 stream.read(&vertexShaderCount);
1227
1228 for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
1229 {
1230 VertexFormat vertexInputs[gl::MAX_VERTEX_ATTRIBS];
1231
1232 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1233 {
1234 VertexFormat *vertexInput = &vertexInputs[inputIndex];
1235 stream.read(&vertexInput->mType);
1236 stream.read(&vertexInput->mNormalized);
1237 stream.read(&vertexInput->mComponents);
1238 stream.read(&vertexInput->mPureInteger);
1239 }
1240
1241 unsigned int vertexShaderSize;
1242 stream.read(&vertexShaderSize);
1243
1244 const char *vertexShaderFunction = (const char*) binary + stream.offset();
1245
1246 rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001247 vertexShaderSize, rx::SHADER_VERTEX,
1248 mTransformFeedbackLinkedVaryings,
1249 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001250 if (!shaderExecutable)
1251 {
1252 infoLog.append("Could not create vertex shader.");
1253 return false;
1254 }
1255
1256 mVertexExecutables.push_back(new VertexExecutable(mRenderer, vertexInputs, shaderExecutable));
1257
1258 stream.skip(vertexShaderSize);
1259 }
1260
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001261 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001262 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001263
Jamie Madillc5a83002014-02-14 16:41:25 -05001264 const char *pixelShaderFunction = (const char*) binary + stream.offset();
1265 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001266 pixelShaderSize, rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
1267 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001268 if (!mPixelExecutable)
1269 {
1270 infoLog.append("Could not create pixel shader.");
1271 return false;
1272 }
1273 stream.skip(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001274
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001275 unsigned int geometryShaderSize;
1276 stream.read(&geometryShaderSize);
1277
Jamie Madillc5a83002014-02-14 16:41:25 -05001278 if (geometryShaderSize > 0)
1279 {
1280 const char *geometryShaderFunction = (const char*) binary + stream.offset();
1281 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001282 geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
1283 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001284 if (!mGeometryExecutable)
1285 {
1286 infoLog.append("Could not create geometry shader.");
1287 SafeDelete(mPixelExecutable);
1288 return false;
1289 }
1290 stream.skip(geometryShaderSize);
1291 }
1292
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001293 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001294
daniel@transgaming.com36038542012-11-28 20:59:26 +00001295 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001296 ptr += sizeof(GUID);
1297
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001298 GUID identifier = mRenderer->getAdapterIdentifier();
1299 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001300 {
1301 infoLog.append("Invalid program binary.");
1302 return false;
1303 }
1304
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001305 initializeUniformStorage();
1306
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001307 return true;
1308}
1309
1310bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1311{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001312 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001313
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001314 stream.write(GL_PROGRAM_BINARY_ANGLE);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001315 stream.write(ANGLE_MAJOR_VERSION);
1316 stream.write(ANGLE_MINOR_VERSION);
1317 stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001318 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001319
1320 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1321 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001322 stream.write(mLinkedAttribute[i].type);
1323 stream.write(mLinkedAttribute[i].name);
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001324 stream.write(mShaderAttributes[i].type);
1325 stream.write(mShaderAttributes[i].name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001326 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001327 }
1328
1329 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1330 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001331 stream.write(mSamplersPS[i].active);
1332 stream.write(mSamplersPS[i].logicalTextureUnit);
1333 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001334 }
1335
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001336 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001337 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001338 stream.write(mSamplersVS[i].active);
1339 stream.write(mSamplersVS[i].logicalTextureUnit);
1340 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001341 }
1342
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001343 stream.write(mUsedVertexSamplerRange);
1344 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001345 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001346 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001347
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001348 stream.write(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001349 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001350 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001351 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001352
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001353 stream.write(uniform.type);
1354 stream.write(uniform.precision);
1355 stream.write(uniform.name);
1356 stream.write(uniform.arraySize);
1357 stream.write(uniform.blockIndex);
1358
1359 stream.write(uniform.blockInfo.offset);
1360 stream.write(uniform.blockInfo.arrayStride);
1361 stream.write(uniform.blockInfo.matrixStride);
1362 stream.write(uniform.blockInfo.isRowMajorMatrix);
1363
1364 stream.write(uniform.psRegisterIndex);
1365 stream.write(uniform.vsRegisterIndex);
1366 stream.write(uniform.registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001367 stream.write(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001368 }
1369
1370 stream.write(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001371 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001372 {
1373 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1374
1375 stream.write(uniformBlock.name);
1376 stream.write(uniformBlock.elementIndex);
1377 stream.write(uniformBlock.dataSize);
1378
1379 stream.write(uniformBlock.memberUniformIndexes.size());
1380 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1381 {
1382 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1383 }
1384
1385 stream.write(uniformBlock.psRegisterIndex);
1386 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001387 }
1388
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001389 stream.write(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001390 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001391 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001392 stream.write(mUniformIndex[i].name);
1393 stream.write(mUniformIndex[i].element);
1394 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001395 }
1396
Geoff Lang48dcae72014-02-05 16:28:24 -05001397 stream.write(mTransformFeedbackBufferMode);
1398 stream.write(mTransformFeedbackLinkedVaryings.size());
1399 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
1400 {
1401 const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
1402
1403 stream.write(varying.name);
1404 stream.write(varying.type);
1405 stream.write(varying.size);
1406 stream.write(varying.semanticName);
1407 stream.write(varying.semanticIndex);
1408 stream.write(varying.semanticIndexCount);
1409 }
1410
Jamie Madillc5a83002014-02-14 16:41:25 -05001411 stream.write(mVertexHLSL);
1412 stream.write(mVertexWorkarounds);
1413
1414 UINT vertexShadersTotalSize = 0;
1415
1416 stream.write(mVertexExecutables.size());
1417 for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
1418 {
1419 VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
1420
1421 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1422 {
1423 const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
1424 stream.write(vertexInput.mType);
1425 stream.write(vertexInput.mNormalized);
1426 stream.write(vertexInput.mComponents);
1427 stream.write(vertexInput.mPureInteger);
1428 }
1429
1430 UINT vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
1431 stream.write(vertexShaderSize);
1432
1433 unsigned char *vertexBlob = static_cast<unsigned char *>(vertexExecutable->shaderExecutable()->getFunction());
1434 stream.write(vertexBlob, vertexShaderSize);
1435 }
1436
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001437 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001438 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001439
Jamie Madillc5a83002014-02-14 16:41:25 -05001440 unsigned char *pixelBlob = static_cast<unsigned char *>(mPixelExecutable->getFunction());
1441 stream.write(pixelBlob, pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001442
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001443 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1444 stream.write(geometryShaderSize);
1445
Jamie Madillc5a83002014-02-14 16:41:25 -05001446 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1447 {
1448 unsigned char *geometryBlob = static_cast<unsigned char *>(mGeometryExecutable->getFunction());
1449 stream.write(geometryBlob, geometryShaderSize);
1450 }
1451
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001452 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001453
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001454 GLsizei streamLength = stream.length();
1455 const void *streamData = stream.data();
1456
Jamie Madillc5a83002014-02-14 16:41:25 -05001457 GLsizei totalLength = streamLength + sizeof(GUID);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001458 if (totalLength > bufSize)
1459 {
1460 if (length)
1461 {
1462 *length = 0;
1463 }
1464
1465 return false;
1466 }
1467
1468 if (binary)
1469 {
1470 char *ptr = (char*) binary;
1471
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001472 memcpy(ptr, streamData, streamLength);
1473 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001474
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001475 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001476 ptr += sizeof(GUID);
1477
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001478 ASSERT(ptr - totalLength == binary);
1479 }
1480
1481 if (length)
1482 {
1483 *length = totalLength;
1484 }
1485
1486 return true;
1487}
1488
1489GLint ProgramBinary::getLength()
1490{
1491 GLint length;
1492 if (save(NULL, INT_MAX, &length))
1493 {
1494 return length;
1495 }
1496 else
1497 {
1498 return 0;
1499 }
1500}
1501
Geoff Lang48dcae72014-02-05 16:28:24 -05001502bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader,
1503 const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001504{
1505 if (!fragmentShader || !fragmentShader->isCompiled())
1506 {
1507 return false;
1508 }
1509
1510 if (!vertexShader || !vertexShader->isCompiled())
1511 {
1512 return false;
1513 }
1514
Geoff Lang48dcae72014-02-05 16:28:24 -05001515 mTransformFeedbackLinkedVaryings.clear();
1516 mTransformFeedbackBufferMode = transformFeedbackBufferMode;
1517
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001518 mShaderVersion = vertexShader->getShaderVersion();
1519
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001520 std::string pixelHLSL = fragmentShader->getHLSL();
Jamie Madillc5a83002014-02-14 16:41:25 -05001521 mVertexHLSL = vertexShader->getHLSL();
1522 mVertexWorkarounds = vertexShader->getD3DWorkarounds();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001523
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001524 // Map the varyings to the register file
Jamie Madilla6da33a2013-08-30 13:21:07 -04001525 const sh::ShaderVariable *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
Geoff Lang48dcae72014-02-05 16:28:24 -05001526 int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader, vertexShader, transformFeedbackVaryings);
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001527
1528 if (registers < 0)
1529 {
1530 return false;
1531 }
1532
Jamie Madill5f562732014-02-14 16:41:24 -05001533 if (!linkVaryings(infoLog, fragmentShader, vertexShader))
1534 {
1535 return false;
1536 }
1537
1538 mUsesPointSize = vertexShader->usesPointSize();
Geoff Lang48dcae72014-02-05 16:28:24 -05001539 std::vector<LinkedVarying> linkedVaryings;
Jamie Madillc5a83002014-02-14 16:41:25 -05001540 if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, pixelHLSL, mVertexHLSL,
Geoff Lang48dcae72014-02-05 16:28:24 -05001541 fragmentShader, vertexShader, transformFeedbackVaryings,
1542 &linkedVaryings, &mOutputVariables))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001543 {
1544 return false;
1545 }
1546
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001547 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001548
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001549 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1550 {
1551 success = false;
1552 }
1553
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001554 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001555 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001556 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001557 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001558
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001559 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Jamie Madill5f562732014-02-14 16:41:24 -05001560 if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001561 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001562 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1563 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1564 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001565 }
1566
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001567 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1568 {
1569 success = false;
1570 }
1571
Geoff Lang48dcae72014-02-05 16:28:24 -05001572 if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
1573 transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings))
1574 {
1575 success = false;
1576 }
1577
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001578 if (success)
1579 {
Jamie Madillc5a83002014-02-14 16:41:25 -05001580 VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
1581 GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout);
1582
1583 rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
Geoff Lang48dcae72014-02-05 16:28:24 -05001584 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL,
1585 mTransformFeedbackLinkedVaryings,
1586 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1587 fragmentShader->getD3DWorkarounds());
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001588
1589 if (usesGeometryShader())
1590 {
Jamie Madill5f562732014-02-14 16:41:24 -05001591 std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
Geoff Lang48dcae72014-02-05 16:28:24 -05001592 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY,
1593 mTransformFeedbackLinkedVaryings,
1594 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1595 rx::ANGLE_D3D_WORKAROUND_NONE);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001596 }
1597
Jamie Madillc5a83002014-02-14 16:41:25 -05001598 if (!defaultVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001599 {
1600 infoLog.append("Failed to create D3D shaders.");
1601 success = false;
1602
Jamie Madillc5a83002014-02-14 16:41:25 -05001603 while (!mVertexExecutables.empty())
1604 {
1605 delete mVertexExecutables.back();
1606 mVertexExecutables.pop_back();
1607 }
1608
1609 SafeDelete(mGeometryExecutable);
1610 SafeDelete(mPixelExecutable);
Geoff Lang48dcae72014-02-05 16:28:24 -05001611
1612 mTransformFeedbackLinkedVaryings.clear();
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001613 }
1614 }
1615
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001616 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001617}
1618
1619// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001620bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001621{
1622 unsigned int usedLocations = 0;
Jamie Madill5f562732014-02-14 16:41:24 -05001623 const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001624
1625 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001626 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001627 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001628 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001629 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001630
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001631 mShaderAttributes[attributeIndex] = attribute;
1632
Jamie Madilleba4eff2013-06-20 11:55:51 -04001633 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001634 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001635 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001636
1637 if (rows + location > MAX_VERTEX_ATTRIBS)
1638 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001639 infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001640
1641 return false;
1642 }
1643
Jamie Madilleba4eff2013-06-20 11:55:51 -04001644 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001645 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001646 const int rowLocation = location + row;
1647 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
1648
1649 // In GLSL 3.00, attribute aliasing produces a link error
1650 // In GLSL 1.00, attribute aliasing is allowed
1651 if (mShaderVersion >= 300)
1652 {
1653 if (!linkedAttribute.name.empty())
1654 {
1655 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1656 return false;
1657 }
1658 }
1659
1660 linkedAttribute = attribute;
1661 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001662 }
1663 }
1664 }
1665
1666 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001667 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001668 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001669 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001670 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001671
Jamie Madilleba4eff2013-06-20 11:55:51 -04001672 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001673 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001674 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001675 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1676
1677 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1678 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001679 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001680
1681 return false; // Fail to link
1682 }
1683
Jamie Madilldefb6742013-06-20 11:55:51 -04001684 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001685 }
1686 }
1687
1688 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1689 {
1690 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04001691 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001692
1693 for (int r = 0; r < rows; r++)
1694 {
1695 mSemanticIndex[attributeIndex++] = index++;
1696 }
1697 }
1698
Al Patrick3f2daa82013-08-07 12:58:57 -07001699 initAttributesByLayout();
1700
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001701 return true;
1702}
1703
Jamie Madill28167c62013-08-30 13:21:10 -04001704bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001705{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001706 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001707 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001708 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001709 return false;
1710 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001711 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001712 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001713 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001714 return false;
1715 }
Jamie Madill28167c62013-08-30 13:21:10 -04001716 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001717 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001718 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001719 return false;
1720 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001721
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001722 return true;
1723}
1724
1725template <class ShaderVarType>
1726bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
1727{
1728 if (vertexVar.fields.size() != fragmentVar.fields.size())
1729 {
1730 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
1731 return false;
1732 }
1733 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001734 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1735 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001736 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
1737 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001738
1739 if (vertexMember.name != fragmentMember.name)
1740 {
Jamie Madill28167c62013-08-30 13:21:10 -04001741 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
1742 memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001743 return false;
1744 }
1745
Jamie Madill28167c62013-08-30 13:21:10 -04001746 const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001747 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001748 {
1749 return false;
1750 }
1751 }
1752
1753 return true;
1754}
1755
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001756bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1757{
Jamie Madill28167c62013-08-30 13:21:10 -04001758 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001759 {
1760 return false;
1761 }
1762
1763 if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
1764 {
1765 return false;
1766 }
1767
1768 return true;
1769}
1770
Jamie Madill28167c62013-08-30 13:21:10 -04001771bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1772{
1773 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1774 {
1775 return false;
1776 }
1777
1778 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1779 {
1780 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1781 return false;
1782 }
1783
1784 if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
1785 {
1786 return false;
1787 }
1788
1789 return true;
1790}
1791
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001792bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1793{
Jamie Madill28167c62013-08-30 13:21:10 -04001794 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001795 {
1796 return false;
1797 }
1798
1799 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
1800 {
1801 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1802 return false;
1803 }
1804
1805 if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
1806 {
1807 return false;
1808 }
1809
1810 return true;
1811}
1812
1813bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001814{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001815 // Check that uniforms defined in the vertex and fragment shaders are identical
1816 typedef std::map<std::string, const sh::Uniform*> UniformMap;
1817 UniformMap linkedUniforms;
1818
1819 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1820 {
1821 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
1822 linkedUniforms[vertexUniform.name] = &vertexUniform;
1823 }
1824
1825 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1826 {
1827 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
1828 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1829 if (entry != linkedUniforms.end())
1830 {
1831 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001832 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001833 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001834 {
1835 return false;
1836 }
1837 }
1838 }
1839
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001840 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001841 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001842 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001843 {
1844 return false;
1845 }
1846 }
1847
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001848 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001849 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001850 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001851 {
1852 return false;
1853 }
1854 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001855
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001856 initializeUniformStorage();
1857
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001858 return true;
1859}
1860
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001861int totalRegisterCount(const sh::Uniform &uniform)
1862{
1863 int registerCount = 0;
1864
1865 if (!uniform.fields.empty())
1866 {
1867 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
1868 {
1869 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
1870 }
1871 }
1872 else
1873 {
1874 registerCount = 1;
1875 }
1876
1877 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
1878}
1879
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001880TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
1881{
1882 switch(samplerType)
1883 {
1884 case GL_SAMPLER_2D:
1885 case GL_INT_SAMPLER_2D:
1886 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001887 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001888 return TEXTURE_2D;
1889 case GL_SAMPLER_3D:
1890 case GL_INT_SAMPLER_3D:
1891 case GL_UNSIGNED_INT_SAMPLER_3D:
1892 return TEXTURE_3D;
1893 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001894 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001895 return TEXTURE_CUBE;
1896 case GL_INT_SAMPLER_CUBE:
1897 case GL_UNSIGNED_INT_SAMPLER_CUBE:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001898 return TEXTURE_CUBE;
1899 case GL_SAMPLER_2D_ARRAY:
1900 case GL_INT_SAMPLER_2D_ARRAY:
1901 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001902 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001903 return TEXTURE_2D_ARRAY;
1904 default: UNREACHABLE();
1905 }
1906
1907 return TEXTURE_2D;
1908}
1909
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001910bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001911{
Jamie Madillfcef3362013-11-13 19:37:19 -05001912 if (constant.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001913 {
1914 if (constant.arraySize > 0)
1915 {
1916 unsigned int elementRegisterIndex = constant.registerIndex;
1917
1918 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
1919 {
1920 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1921 {
1922 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill5f562732014-02-14 16:41:24 -05001923 const std::string &uniformName = constant.name + ArrayString(elementIndex) + "." + field.name;
Jamie Madillfcef3362013-11-13 19:37:19 -05001924 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
1925 elementRegisterIndex, field.elementIndex);
1926
1927 fieldUniform.fields = field.fields;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001928 if (!defineUniform(shader, fieldUniform, infoLog))
1929 {
1930 return false;
1931 }
1932 elementRegisterIndex += totalRegisterCount(field);
1933 }
1934 }
1935 }
1936 else
1937 {
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001938 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1939 {
1940 const sh::Uniform &field = constant.fields[fieldIndex];
1941 const std::string &uniformName = constant.name + "." + field.name;
1942
Jamie Madill56093782013-08-30 13:21:11 -04001943 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
1944 field.registerIndex, field.elementIndex);
1945
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001946 fieldUniform.fields = field.fields;
1947
1948 if (!defineUniform(shader, fieldUniform, infoLog))
1949 {
1950 return false;
1951 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001952 }
1953 }
1954
1955 return true;
1956 }
1957
Nicolas Capense6050882013-07-08 10:43:10 -04001958 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001959 {
1960 unsigned int samplerIndex = constant.registerIndex;
1961
1962 do
1963 {
1964 if (shader == GL_VERTEX_SHADER)
1965 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001966 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001967 {
1968 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001969 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001970 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1971 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1972 }
1973 else
1974 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001975 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001976 return false;
1977 }
1978 }
1979 else if (shader == GL_FRAGMENT_SHADER)
1980 {
1981 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1982 {
1983 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001984 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001985 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1986 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1987 }
1988 else
1989 {
1990 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1991 return false;
1992 }
1993 }
1994 else UNREACHABLE();
1995
1996 samplerIndex++;
1997 }
1998 while (samplerIndex < constant.registerIndex + constant.arraySize);
1999 }
2000
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002001 Uniform *uniform = NULL;
2002 GLint location = getUniformLocation(constant.name);
2003
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002004 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002005 {
2006 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002007 }
2008 else
2009 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002010 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
Jamie Madill56093782013-08-30 13:21:11 -04002011 uniform->registerElement = constant.elementIndex;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002012 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002013
2014 if (!uniform)
2015 {
2016 return false;
2017 }
2018
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002019 if (shader == GL_FRAGMENT_SHADER)
2020 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002021 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002022 }
2023 else if (shader == GL_VERTEX_SHADER)
2024 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002025 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002026 }
2027 else UNREACHABLE();
2028
2029 if (location >= 0)
2030 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002031 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002032 }
2033
2034 mUniforms.push_back(uniform);
2035 unsigned int uniformIndex = mUniforms.size() - 1;
2036
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002037 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002038 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002039 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002040 }
2041
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002042 if (shader == GL_VERTEX_SHADER)
2043 {
2044 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2045 {
2046 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2047 return false;
2048 }
2049 }
2050 else if (shader == GL_FRAGMENT_SHADER)
2051 {
2052 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2053 {
2054 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2055 return false;
2056 }
2057 }
2058 else UNREACHABLE();
2059
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002060 return true;
2061}
2062
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002063bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2064{
2065 const char* blockName = vertexInterfaceBlock.name.c_str();
2066
2067 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002068 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002069 {
2070 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2071 return false;
2072 }
2073
2074 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2075 {
2076 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2077 return false;
2078 }
2079
Jamie Madill9060a4e2013-08-12 16:22:57 -07002080 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2081 {
2082 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2083 return false;
2084 }
2085
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002086 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002087 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2088 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002089 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2090 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002091
2092 if (vertexMember.name != fragmentMember.name)
2093 {
Jamie Madill28167c62013-08-30 13:21:10 -04002094 infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002095 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2096 return false;
2097 }
2098
Jamie Madill28167c62013-08-30 13:21:10 -04002099 std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002100 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002101 {
2102 return false;
2103 }
2104 }
2105
2106 return true;
2107}
2108
2109bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2110{
2111 // Check that interface blocks defined in the vertex and fragment shaders are identical
2112 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2113 UniformBlockMap linkedUniformBlocks;
2114
2115 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2116 {
2117 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2118 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2119 }
2120
2121 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2122 {
2123 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2124 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2125 if (entry != linkedUniformBlocks.end())
2126 {
2127 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2128 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2129 {
2130 return false;
2131 }
2132 }
2133 }
2134
2135 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2136 {
2137 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2138 {
2139 return false;
2140 }
2141 }
2142
2143 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2144 {
2145 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2146 {
2147 return false;
2148 }
2149 }
2150
2151 return true;
2152}
2153
Geoff Lang48dcae72014-02-05 16:28:24 -05002154bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
2155 const std::vector<std::string> &transformFeedbackVaryingNames,
2156 GLenum transformFeedbackBufferMode,
2157 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const
2158{
2159 size_t totalComponents = 0;
2160 const size_t maxSeparateComponents = mRenderer->getMaxTransformFeedbackSeparateComponents();
2161 const size_t maxInterleavedComponents = mRenderer->getMaxTransformFeedbackInterleavedComponents();
2162
2163 // Gather the linked varyings that are used for transform feedback, they should all exist.
2164 outTransformFeedbackLinkedVaryings->clear();
2165 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
2166 {
2167 bool found = false;
2168 for (size_t j = 0; j < linkedVaryings.size(); j++)
2169 {
2170 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
2171 {
2172 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
2173 {
2174 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
2175 {
2176 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
2177 return false;
2178 }
2179 }
2180
2181 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
2182 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
2183 componentCount > maxSeparateComponents)
2184 {
2185 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
2186 linkedVaryings[j].name.c_str(), componentCount, maxSeparateComponents);
2187 return false;
2188 }
2189
2190 totalComponents += componentCount;
2191
2192 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
2193 found = true;
2194 break;
2195 }
2196 }
2197
2198 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2199 ASSERT(found);
2200 }
2201
2202 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > maxInterleavedComponents)
2203 {
2204 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
2205 totalComponents, maxInterleavedComponents);
2206 return false;
2207 }
2208
2209 return true;
2210}
2211
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002212void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002213{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002214 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002215 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002216 const sh::InterfaceBlockField &field = fields[uniformIndex];
2217 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002218
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002219 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002220 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002221 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002222 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002223 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002224 {
Jamie Madill5f562732014-02-14 16:41:24 -05002225 const std::string uniformElementName = fieldName + ArrayString(arrayElement);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002226 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002227 }
2228 }
2229 else
2230 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002231 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002232 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002233 }
2234 else
2235 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002236 Uniform *newUniform = new Uniform(field.type, field.precision, fieldName, field.arraySize,
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002237 blockIndex, **blockInfoItr);
2238
2239 // add to uniform list, but not index, since uniform block uniforms have no location
2240 blockUniformIndexes->push_back(mUniforms.size());
2241 mUniforms.push_back(newUniform);
2242 (*blockInfoItr)++;
2243 }
2244 }
2245}
2246
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002247bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2248{
2249 // create uniform block entries if they do not exist
2250 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2251 {
2252 std::vector<unsigned int> blockUniformIndexes;
2253 const unsigned int blockIndex = mUniformBlocks.size();
2254
2255 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002256 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002257 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002258
2259 // create all the uniform blocks
2260 if (interfaceBlock.arraySize > 0)
2261 {
2262 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2263 {
2264 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2265 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2266 mUniformBlocks.push_back(newUniformBlock);
2267 }
2268 }
2269 else
2270 {
2271 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2272 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2273 mUniformBlocks.push_back(newUniformBlock);
2274 }
2275 }
2276
2277 // Assign registers to the uniform blocks
2278 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2279 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2280 ASSERT(blockIndex != GL_INVALID_INDEX);
2281 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2282
2283 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2284 {
2285 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2286 ASSERT(uniformBlock->name == interfaceBlock.name);
2287
2288 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2289 {
2290 return false;
2291 }
2292 }
2293
2294 return true;
2295}
2296
2297bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2298{
2299 if (shader == GL_VERTEX_SHADER)
2300 {
2301 uniformBlock->vsRegisterIndex = registerIndex;
2302 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2303
2304 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2305 {
2306 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2307 return false;
2308 }
2309 }
2310 else if (shader == GL_FRAGMENT_SHADER)
2311 {
2312 uniformBlock->psRegisterIndex = registerIndex;
2313 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2314
2315 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2316 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002317 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002318 return false;
2319 }
2320 }
2321 else UNREACHABLE();
2322
2323 return true;
2324}
2325
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002326bool ProgramBinary::isValidated() const
2327{
2328 return mValidated;
2329}
2330
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002331void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002332{
2333 // Skip over inactive attributes
2334 unsigned int activeAttribute = 0;
2335 unsigned int attribute;
2336 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2337 {
2338 if (mLinkedAttribute[attribute].name.empty())
2339 {
2340 continue;
2341 }
2342
2343 if (activeAttribute == index)
2344 {
2345 break;
2346 }
2347
2348 activeAttribute++;
2349 }
2350
2351 if (bufsize > 0)
2352 {
2353 const char *string = mLinkedAttribute[attribute].name.c_str();
2354
2355 strncpy(name, string, bufsize);
2356 name[bufsize - 1] = '\0';
2357
2358 if (length)
2359 {
2360 *length = strlen(name);
2361 }
2362 }
2363
2364 *size = 1; // Always a single 'type' instance
2365
2366 *type = mLinkedAttribute[attribute].type;
2367}
2368
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002369GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002370{
2371 int count = 0;
2372
2373 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2374 {
2375 if (!mLinkedAttribute[attributeIndex].name.empty())
2376 {
2377 count++;
2378 }
2379 }
2380
2381 return count;
2382}
2383
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002384GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002385{
2386 int maxLength = 0;
2387
2388 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2389 {
2390 if (!mLinkedAttribute[attributeIndex].name.empty())
2391 {
2392 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2393 }
2394 }
2395
2396 return maxLength;
2397}
2398
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002399void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002400{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002401 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002402
2403 if (bufsize > 0)
2404 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002405 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002406
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002407 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002408 {
2409 string += "[0]";
2410 }
2411
2412 strncpy(name, string.c_str(), bufsize);
2413 name[bufsize - 1] = '\0';
2414
2415 if (length)
2416 {
2417 *length = strlen(name);
2418 }
2419 }
2420
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002421 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002422
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002423 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002424}
2425
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002426GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002427{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002428 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002429}
2430
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002431GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002432{
2433 int maxLength = 0;
2434
2435 unsigned int numUniforms = mUniforms.size();
2436 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2437 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002438 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002439 {
2440 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2441 if (mUniforms[uniformIndex]->isArray())
2442 {
2443 length += 3; // Counting in "[0]".
2444 }
2445 maxLength = std::max(length, maxLength);
2446 }
2447 }
2448
2449 return maxLength;
2450}
2451
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002452GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2453{
2454 const gl::Uniform& uniform = *mUniforms[index];
2455
2456 switch (pname)
2457 {
2458 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2459 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002460 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002461 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002462
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002463 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2464 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2465 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2466 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002467
2468 default:
2469 UNREACHABLE();
2470 break;
2471 }
2472 return 0;
2473}
2474
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002475void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2476{
2477 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2478
2479 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2480
2481 if (bufSize > 0)
2482 {
2483 std::string string = uniformBlock.name;
2484
2485 if (uniformBlock.isArrayElement())
2486 {
Jamie Madill5f562732014-02-14 16:41:24 -05002487 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002488 }
2489
2490 strncpy(uniformBlockName, string.c_str(), bufSize);
2491 uniformBlockName[bufSize - 1] = '\0';
2492
2493 if (length)
2494 {
2495 *length = strlen(uniformBlockName);
2496 }
2497 }
2498}
2499
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002500void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2501{
2502 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2503
2504 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2505
2506 switch (pname)
2507 {
2508 case GL_UNIFORM_BLOCK_DATA_SIZE:
2509 *params = static_cast<GLint>(uniformBlock.dataSize);
2510 break;
2511 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002512 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002513 break;
2514 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2515 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2516 break;
2517 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2518 {
2519 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2520 {
2521 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2522 }
2523 }
2524 break;
2525 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2526 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2527 break;
2528 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2529 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2530 break;
2531 default: UNREACHABLE();
2532 }
2533}
2534
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002535GLuint ProgramBinary::getActiveUniformBlockCount() const
2536{
2537 return mUniformBlocks.size();
2538}
2539
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002540GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2541{
2542 unsigned int maxLength = 0;
2543
2544 unsigned int numUniformBlocks = mUniformBlocks.size();
2545 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2546 {
2547 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2548 if (!uniformBlock.name.empty())
2549 {
2550 const unsigned int length = uniformBlock.name.length() + 1;
2551
2552 // Counting in "[0]".
2553 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2554
2555 maxLength = std::max(length + arrayLength, maxLength);
2556 }
2557 }
2558
2559 return maxLength;
2560}
2561
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002562void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002563{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002564 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002565 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002566 {
2567 mValidated = false;
2568 }
2569 else
2570 {
2571 mValidated = true;
2572 }
2573}
2574
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002575bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002576{
2577 // if any two active samplers in a program are of different types, but refer to the same
2578 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2579 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2580
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002581 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002582 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002583
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002584 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002585 {
2586 textureUnitType[i] = TEXTURE_UNKNOWN;
2587 }
2588
2589 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2590 {
2591 if (mSamplersPS[i].active)
2592 {
2593 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2594
2595 if (unit >= maxCombinedTextureImageUnits)
2596 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002597 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002598 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002599 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002600 }
2601
2602 return false;
2603 }
2604
2605 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2606 {
2607 if (mSamplersPS[i].textureType != textureUnitType[unit])
2608 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002609 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002610 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002611 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002612 }
2613
2614 return false;
2615 }
2616 }
2617 else
2618 {
2619 textureUnitType[unit] = mSamplersPS[i].textureType;
2620 }
2621 }
2622 }
2623
2624 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2625 {
2626 if (mSamplersVS[i].active)
2627 {
2628 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2629
2630 if (unit >= maxCombinedTextureImageUnits)
2631 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002632 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002633 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002634 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002635 }
2636
2637 return false;
2638 }
2639
2640 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2641 {
2642 if (mSamplersVS[i].textureType != textureUnitType[unit])
2643 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002644 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002645 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002646 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002647 }
2648
2649 return false;
2650 }
2651 }
2652 else
2653 {
2654 textureUnitType[unit] = mSamplersVS[i].textureType;
2655 }
2656 }
2657 }
2658
2659 return true;
2660}
2661
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002662ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2663{
2664}
2665
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002666struct AttributeSorter
2667{
2668 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2669 : originalIndices(semanticIndices)
2670 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002671 }
2672
2673 bool operator()(int a, int b)
2674 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002675 if (originalIndices[a] == -1) return false;
2676 if (originalIndices[b] == -1) return true;
2677 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002678 }
2679
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002680 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2681};
2682
Al Patrick3f2daa82013-08-07 12:58:57 -07002683void ProgramBinary::initAttributesByLayout()
2684{
2685 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2686 {
2687 mAttributesByLayout[i] = i;
2688 }
2689
2690 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2691}
2692
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002693void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2694{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002695 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2696
2697 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2698 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002699 oldTranslatedAttributes[i] = attributes[i];
2700 }
2701
2702 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2703 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002704 int oldIndex = mAttributesByLayout[i];
2705 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002706 attributes[i] = oldTranslatedAttributes[oldIndex];
2707 }
2708}
2709
Jamie Madill8ff21ae2014-02-04 16:04:05 -05002710void ProgramBinary::initializeUniformStorage()
2711{
2712 // Compute total default block size
2713 unsigned int vertexRegisters = 0;
2714 unsigned int fragmentRegisters = 0;
2715 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2716 {
2717 const Uniform &uniform = *mUniforms[uniformIndex];
2718
2719 if (!IsSampler(uniform.type))
2720 {
2721 if (uniform.isReferencedByVertexShader())
2722 {
2723 vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
2724 }
2725 if (uniform.isReferencedByFragmentShader())
2726 {
2727 fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
2728 }
2729 }
2730 }
2731
2732 mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
2733 mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
2734}
2735
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002736}