blob: 2aa3719ff02a35c046639456975f8ef3831f46dd [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 Madill834e8b72014-04-11 13:33:58 -040053void GetInputLayoutFromShader(const std::vector<gl::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
Jamie Madillc5a83002014-02-14 16:41:25 -050054{
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 Madill834e8b72014-04-11 13:33:58 -040060 const gl::Attribute &shaderAttr = shaderAttributes[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -050061
62 if (shaderAttr.type != GL_NONE)
63 {
Jamie Madillac0a2672014-04-11 13:33:56 -040064 GLenum transposedType = TransposeMatrixType(shaderAttr.type);
65
66 for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++)
Jamie Madill3b7e2052014-03-17 09:47:43 -040067 {
68 VertexFormat *defaultFormat = &inputLayout[layoutIndex];
69
Jamie Madillac0a2672014-04-11 13:33:56 -040070 defaultFormat->mType = UniformComponentType(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -040071 defaultFormat->mNormalized = false;
72 defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
Jamie Madillac0a2672014-04-11 13:33:56 -040073 defaultFormat->mComponents = VariableColumnCount(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -040074 }
Jamie Madillc5a83002014-02-14 16:41:25 -050075 }
76 }
77}
78
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000079}
80
Jamie Madill63491ea2013-06-06 11:56:45 -040081VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +000082 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083{
84}
85
Jamie Madillc5a83002014-02-14 16:41:25 -050086ProgramBinary::VertexExecutable::VertexExecutable(rx::Renderer *const renderer,
87 const VertexFormat inputLayout[],
Jamie Madill7a29e4a2014-05-02 10:41:48 -040088 const GLenum signature[],
Jamie Madillc5a83002014-02-14 16:41:25 -050089 rx::ShaderExecutable *shaderExecutable)
90 : mShaderExecutable(shaderExecutable)
91{
92 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
93 {
94 mInputs[attributeIndex] = inputLayout[attributeIndex];
Jamie Madill7a29e4a2014-05-02 10:41:48 -040095 mSignature[attributeIndex] = signature[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -050096 }
97}
98
Jamie Madill8b4f8f82014-03-26 14:01:58 -040099ProgramBinary::VertexExecutable::~VertexExecutable()
100{
101 delete mShaderExecutable;
102}
103
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400104bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
Jamie Madillc5a83002014-02-14 16:41:25 -0500105{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400106 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -0500107 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400108 if (mSignature[attributeIndex] != signature[attributeIndex])
Jamie Madillc5a83002014-02-14 16:41:25 -0500109 {
110 return false;
111 }
112 }
113
114 return true;
115}
116
Geoff Lang48dcae72014-02-05 16:28:24 -0500117LinkedVarying::LinkedVarying()
118{
119}
120
121LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
122 unsigned int semanticIndex, unsigned int semanticIndexCount)
123 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
124{
125}
126
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000127unsigned int ProgramBinary::mCurrentSerial = 1;
128
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500129ProgramBinary::ProgramBinary(rx::Renderer *renderer)
130 : RefCountObject(0),
131 mRenderer(renderer),
Jamie Madill5f562732014-02-14 16:41:24 -0500132 mDynamicHLSL(NULL),
Jamie Madillc5a83002014-02-14 16:41:25 -0500133 mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500134 mPixelExecutable(NULL),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500135 mGeometryExecutable(NULL),
136 mUsedVertexSamplerRange(0),
137 mUsedPixelSamplerRange(0),
138 mUsesPointSize(false),
139 mShaderVersion(100),
140 mVertexUniformStorage(NULL),
141 mFragmentUniformStorage(NULL),
142 mValidated(false),
143 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000144{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000145 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
146 {
147 mSemanticIndex[index] = -1;
148 }
149
150 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
151 {
152 mSamplersPS[index].active = false;
153 }
154
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000155 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000156 {
157 mSamplersVS[index].active = false;
158 }
Jamie Madill5f562732014-02-14 16:41:24 -0500159
160 mDynamicHLSL = new DynamicHLSL(renderer);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000161}
162
163ProgramBinary::~ProgramBinary()
164{
Jamie Madillc5a83002014-02-14 16:41:25 -0500165 while (!mVertexExecutables.empty())
166 {
167 delete mVertexExecutables.back();
168 mVertexExecutables.pop_back();
169 }
170
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500171 SafeDelete(mGeometryExecutable);
Jamie Madillc5a83002014-02-14 16:41:25 -0500172 SafeDelete(mPixelExecutable);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000173
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000174 while (!mUniforms.empty())
175 {
176 delete mUniforms.back();
177 mUniforms.pop_back();
178 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000179
180 while (!mUniformBlocks.empty())
181 {
182 delete mUniformBlocks.back();
183 mUniformBlocks.pop_back();
184 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500185
186 SafeDelete(mVertexUniformStorage);
187 SafeDelete(mFragmentUniformStorage);
Jamie Madill5f562732014-02-14 16:41:24 -0500188 SafeDelete(mDynamicHLSL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000189}
190
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000191unsigned int ProgramBinary::getSerial() const
192{
193 return mSerial;
194}
195
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000196int ProgramBinary::getShaderVersion() const
197{
198 return mShaderVersion;
199}
200
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000201unsigned int ProgramBinary::issueSerial()
202{
203 return mCurrentSerial++;
204}
205
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500206rx::ShaderExecutable *ProgramBinary::getPixelExecutable() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000207{
208 return mPixelExecutable;
209}
210
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400211rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000212{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400213 GLenum signature[MAX_VERTEX_ATTRIBS];
214 mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
215
Jamie Madillc5a83002014-02-14 16:41:25 -0500216 for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
217 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400218 if (mVertexExecutables[executableIndex]->matchesSignature(signature))
Jamie Madillc5a83002014-02-14 16:41:25 -0500219 {
220 return mVertexExecutables[executableIndex]->shaderExecutable();
221 }
222 }
223
Jamie Madillc5ede1a2014-02-14 16:41:27 -0500224 // Generate new dynamic layout with attribute conversions
225 const std::string &layoutHLSL = mDynamicHLSL->generateInputLayoutHLSL(inputLayout, mShaderAttributes);
226
227 // Generate new shader source by replacing the attributes stub with the defined input layout
228 std::string vertexHLSL = mVertexHLSL;
229 size_t insertPos = vertexHLSL.find(DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING);
230 vertexHLSL.replace(insertPos, DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING.length(), layoutHLSL);
231
Jamie Madillc5a83002014-02-14 16:41:25 -0500232 // Generate new vertex executable
233 InfoLog tempInfoLog;
Geoff Lang48dcae72014-02-05 16:28:24 -0500234 rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, vertexHLSL.c_str(),
235 rx::SHADER_VERTEX,
236 mTransformFeedbackLinkedVaryings,
237 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
238 mVertexWorkarounds);
Jamie Madillc5a83002014-02-14 16:41:25 -0500239
240 if (!vertexExecutable)
241 {
242 std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
243 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
244 ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
245 }
246 else
247 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400248 mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, signature, vertexExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -0500249 }
250
251 return vertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000252}
253
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500254rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000255{
256 return mGeometryExecutable;
257}
258
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000259GLuint ProgramBinary::getAttributeLocation(const char *name)
260{
261 if (name)
262 {
263 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
264 {
265 if (mLinkedAttribute[index].name == std::string(name))
266 {
267 return index;
268 }
269 }
270 }
271
272 return -1;
273}
274
275int ProgramBinary::getSemanticIndex(int attributeIndex)
276{
277 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
278
279 return mSemanticIndex[attributeIndex];
280}
281
282// Returns one more than the highest sampler index used.
283GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
284{
285 switch (type)
286 {
287 case SAMPLER_PIXEL:
288 return mUsedPixelSamplerRange;
289 case SAMPLER_VERTEX:
290 return mUsedVertexSamplerRange;
291 default:
292 UNREACHABLE();
293 return 0;
294 }
295}
296
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000297bool ProgramBinary::usesPointSize() const
298{
299 return mUsesPointSize;
300}
301
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000302bool ProgramBinary::usesPointSpriteEmulation() const
303{
304 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
305}
306
307bool ProgramBinary::usesGeometryShader() const
308{
309 return usesPointSpriteEmulation();
310}
311
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000312// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
313// index (0-15 for the pixel shader and 0-3 for the vertex shader).
314GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
315{
316 GLint logicalTextureUnit = -1;
317
318 switch (type)
319 {
320 case SAMPLER_PIXEL:
321 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
322
323 if (mSamplersPS[samplerIndex].active)
324 {
325 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
326 }
327 break;
328 case SAMPLER_VERTEX:
329 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
330
331 if (mSamplersVS[samplerIndex].active)
332 {
333 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
334 }
335 break;
336 default: UNREACHABLE();
337 }
338
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000339 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000340 {
341 return logicalTextureUnit;
342 }
343
344 return -1;
345}
346
347// Returns the texture type for a given Direct3D 9 sampler type and
348// index (0-15 for the pixel shader and 0-3 for the vertex shader).
349TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
350{
351 switch (type)
352 {
353 case SAMPLER_PIXEL:
354 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
355 ASSERT(mSamplersPS[samplerIndex].active);
356 return mSamplersPS[samplerIndex].textureType;
357 case SAMPLER_VERTEX:
358 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
359 ASSERT(mSamplersVS[samplerIndex].active);
360 return mSamplersVS[samplerIndex].textureType;
361 default: UNREACHABLE();
362 }
363
364 return TEXTURE_2D;
365}
366
367GLint ProgramBinary::getUniformLocation(std::string name)
368{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500369 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000370
371 unsigned int numUniforms = mUniformIndex.size();
372 for (unsigned int location = 0; location < numUniforms; location++)
373 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000374 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000375 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000376 const int index = mUniformIndex[location].index;
377 const bool isArray = mUniforms[index]->isArray();
378
379 if ((isArray && mUniformIndex[location].element == subscript) ||
380 (subscript == GL_INVALID_INDEX))
381 {
382 return location;
383 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000384 }
385 }
386
387 return -1;
388}
389
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000390GLuint ProgramBinary::getUniformIndex(std::string name)
391{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500392 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000393
394 // The app is not allowed to specify array indices other than 0 for arrays of basic types
395 if (subscript != 0 && subscript != GL_INVALID_INDEX)
396 {
397 return GL_INVALID_INDEX;
398 }
399
400 unsigned int numUniforms = mUniforms.size();
401 for (unsigned int index = 0; index < numUniforms; index++)
402 {
403 if (mUniforms[index]->name == name)
404 {
405 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
406 {
407 return index;
408 }
409 }
410 }
411
412 return GL_INVALID_INDEX;
413}
414
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000415GLuint ProgramBinary::getUniformBlockIndex(std::string name)
416{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500417 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000418
419 unsigned int numUniformBlocks = mUniformBlocks.size();
420 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
421 {
422 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
423 if (uniformBlock.name == name)
424 {
425 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
426 if (subscript == uniformBlock.elementIndex || arrayElementZero)
427 {
428 return blockIndex;
429 }
430 }
431 }
432
433 return GL_INVALID_INDEX;
434}
435
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000436UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
437{
438 ASSERT(blockIndex < mUniformBlocks.size());
439 return mUniformBlocks[blockIndex];
440}
441
Jamie Madilld1e78c92013-06-20 11:55:50 -0400442GLint ProgramBinary::getFragDataLocation(const char *name) const
443{
444 std::string baseName(name);
445 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500446 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400447
448 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
449 {
450 const VariableLocation &outputVariable = locationIt->second;
451
452 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
453 {
454 return static_cast<GLint>(locationIt->first);
455 }
456 }
457
458 return -1;
459}
460
Geoff Lang48dcae72014-02-05 16:28:24 -0500461size_t ProgramBinary::getTransformFeedbackVaryingCount() const
462{
463 return mTransformFeedbackLinkedVaryings.size();
464}
465
466const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
467{
468 return mTransformFeedbackLinkedVaryings[idx];
469}
470
471GLenum ProgramBinary::getTransformFeedbackBufferMode() const
472{
473 return mTransformFeedbackBufferMode;
474}
475
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000476template <typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400477static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
478{
479 ASSERT(dest != NULL);
480 ASSERT(dirtyFlag != NULL);
481
482 *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
483 *dest = source;
484}
485
486template <typename T>
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000487bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000488{
489 if (location < 0 || location >= (int)mUniformIndex.size())
490 {
491 return false;
492 }
493
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000494 const int components = UniformComponentCount(targetUniformType);
495 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
496
Jamie Madill834e8b72014-04-11 13:33:58 -0400497 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000498
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000499 int elementCount = targetUniform->elementCount();
500
501 if (elementCount == 1 && count > 1)
502 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
503
504 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
505
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000506 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000507 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000508 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000509
510 for (int i = 0; i < count; i++)
511 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000512 for (int c = 0; c < components; c++)
513 {
Geoff Langae1990c2014-05-12 16:57:14 -0400514 SetIfDirty(target + c, v[c], &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000515 }
516 for (int c = components; c < 4; c++)
517 {
Geoff Langae1990c2014-05-12 16:57:14 -0400518 SetIfDirty(target + c, T(0), &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000519 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000520 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000521 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000522 }
523 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000524 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000525 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000526 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000527
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000528 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000530 for (int c = 0; c < components; c++)
531 {
Geoff Langae1990c2014-05-12 16:57:14 -0400532 SetIfDirty(boolParams + c, (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000533 }
534 for (int c = components; c < 4; c++)
535 {
Geoff Langae1990c2014-05-12 16:57:14 -0400536 SetIfDirty(boolParams + c, GL_FALSE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000537 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000538 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000539 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000540 }
541 }
542 else
543 {
544 return false;
545 }
546
547 return true;
548}
549
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000550bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
551{
552 return setUniform(location, count, v, GL_FLOAT);
553}
554
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
556{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000557 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000558}
559
560bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
561{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000562 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000563}
564
565bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
566{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000567 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568}
569
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000570template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400571bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000572{
Geoff Langae1990c2014-05-12 16:57:14 -0400573 bool dirty = false;
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000574 int copyWidth = std::min(targetHeight, srcWidth);
575 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000576
577 for (int x = 0; x < copyWidth; x++)
578 {
579 for (int y = 0; y < copyHeight; y++)
580 {
Geoff Langae1990c2014-05-12 16:57:14 -0400581 SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000582 }
583 }
584 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000585 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000586 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000587 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000588 {
Geoff Langae1990c2014-05-12 16:57:14 -0400589 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000590 }
591 }
592 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000593 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000594 {
595 for (int x = 0; x < targetWidth; x++)
596 {
Geoff Langae1990c2014-05-12 16:57:14 -0400597 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000598 }
599 }
Geoff Langae1990c2014-05-12 16:57:14 -0400600
601 return dirty;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000602}
603
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000604template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400605bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000606{
Geoff Langae1990c2014-05-12 16:57:14 -0400607 bool dirty = false;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000608 int copyWidth = std::min(targetWidth, srcWidth);
609 int copyHeight = std::min(targetHeight, srcHeight);
610
611 for (int y = 0; y < copyHeight; y++)
612 {
613 for (int x = 0; x < copyWidth; x++)
614 {
Geoff Langae1990c2014-05-12 16:57:14 -0400615 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000616 }
617 }
618 // clear unfilled right side
619 for (int y = 0; y < copyHeight; y++)
620 {
621 for (int x = copyWidth; x < targetWidth; x++)
622 {
Geoff Langae1990c2014-05-12 16:57:14 -0400623 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000624 }
625 }
626 // clear unfilled bottom.
627 for (int y = copyHeight; y < targetHeight; y++)
628 {
629 for (int x = 0; x < targetWidth; x++)
630 {
Geoff Langae1990c2014-05-12 16:57:14 -0400631 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000632 }
633 }
Geoff Langae1990c2014-05-12 16:57:14 -0400634
635 return dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000636}
637
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000638template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000639bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000640{
641 if (location < 0 || location >= (int)mUniformIndex.size())
642 {
643 return false;
644 }
645
Jamie Madill834e8b72014-04-11 13:33:58 -0400646 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000647
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000648 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000649 {
650 return false;
651 }
652
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000653 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000655 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000656 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
657
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000658 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000659 const unsigned int targetMatrixStride = (4 * rows);
660 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000661
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000662 for (int i = 0; i < count; i++)
663 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000664 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
665 if (transpose == GL_FALSE)
666 {
Geoff Langae1990c2014-05-12 16:57:14 -0400667 targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000668 }
669 else
670 {
Geoff Langae1990c2014-05-12 16:57:14 -0400671 targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000672 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000673 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000674 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000675 }
676
677 return true;
678}
679
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000680bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000681{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000682 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000683}
684
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000685bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000686{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000687 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000688}
689
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000690bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000691{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000692 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693}
694
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000695bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000696{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000697 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000698}
699
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000700bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000701{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000702 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000703}
704
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000705bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000706{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000707 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000708}
709
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000710bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000711{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000712 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000713}
714
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000715bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000716{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000717 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000718}
719
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000720bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000721{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000722 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000723}
724
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000725bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
726{
727 if (location < 0 || location >= (int)mUniformIndex.size())
728 {
729 return false;
730 }
731
Jamie Madill834e8b72014-04-11 13:33:58 -0400732 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000734 int elementCount = targetUniform->elementCount();
735
736 if (elementCount == 1 && count > 1)
737 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
738
739 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
740
Nicolas Capense6050882013-07-08 10:43:10 -0400741 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000742 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000743 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000744
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000745 for (int i = 0; i < count; i++)
746 {
Geoff Langae1990c2014-05-12 16:57:14 -0400747 SetIfDirty(target + 0, v[0], &targetUniform->dirty);
748 SetIfDirty(target + 1, 0, &targetUniform->dirty);
749 SetIfDirty(target + 2, 0, &targetUniform->dirty);
750 SetIfDirty(target + 3, 0, &targetUniform->dirty);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000751 target += 4;
752 v += 1;
753 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000754 }
755 else if (targetUniform->type == GL_BOOL)
756 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000757 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000758
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000759 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000760 {
Geoff Langae1990c2014-05-12 16:57:14 -0400761 SetIfDirty(boolParams + 0, (v[0] == 0) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
762 SetIfDirty(boolParams + 1, GL_FALSE, &targetUniform->dirty);
763 SetIfDirty(boolParams + 2, GL_FALSE, &targetUniform->dirty);
764 SetIfDirty(boolParams + 3, GL_FALSE, &targetUniform->dirty);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000765 boolParams += 4;
766 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000767 }
768 }
769 else
770 {
771 return false;
772 }
773
774 return true;
775}
776
777bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
778{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000779 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000780}
781
782bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
783{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000784 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000785}
786
787bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
788{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000789 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000790}
791
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000792bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
793{
794 return setUniform(location, count, v, GL_UNSIGNED_INT);
795}
796
797bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
798{
799 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
800}
801
802bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
803{
804 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
805}
806
807bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
808{
809 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
810}
811
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000812template <typename T>
813bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000814{
815 if (location < 0 || location >= (int)mUniformIndex.size())
816 {
817 return false;
818 }
819
Jamie Madill834e8b72014-04-11 13:33:58 -0400820 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000821
822 // sized queries -- ensure the provided buffer is large enough
823 if (bufSize)
824 {
825 int requiredBytes = UniformExternalSize(targetUniform->type);
826 if (*bufSize < requiredBytes)
827 {
828 return false;
829 }
830 }
831
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000832 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000833 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000834 const int rows = VariableRowCount(targetUniform->type);
835 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400836 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 +0000837 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000838 else if (uniformType == UniformComponentType(targetUniform->type))
839 {
840 unsigned int size = UniformComponentCount(targetUniform->type);
841 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
842 size * sizeof(T));
843 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000844 else
845 {
846 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000847 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000848 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000849 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000850 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000851 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000852
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000853 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000854 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000855 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000856 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000857 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000858 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000859
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000860 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000861 {
862 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
863
864 for (unsigned int i = 0; i < size; i++)
865 {
866 params[i] = static_cast<T>(floatParams[i]);
867 }
868 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000869 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000870
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000871 case GL_INT:
872 {
873 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
874
875 for (unsigned int i = 0; i < size; i++)
876 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000877 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000878 }
879 }
880 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000881
882 case GL_UNSIGNED_INT:
883 {
884 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000885
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000886 for (unsigned int i = 0; i < size; i++)
887 {
888 params[i] = static_cast<T>(uintParams[i]);
889 }
890 }
891 break;
892
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000893 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000894 }
895 }
896
897 return true;
898}
899
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000900bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
901{
902 return getUniformv(location, bufSize, params, GL_FLOAT);
903}
904
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000905bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
906{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000907 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000908}
909
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000910bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
911{
912 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
913}
914
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000915void ProgramBinary::dirtyAllUniforms()
916{
917 unsigned int numUniforms = mUniforms.size();
918 for (unsigned int index = 0; index < numUniforms; index++)
919 {
920 mUniforms[index]->dirty = true;
921 }
922}
923
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000924// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000925void ProgramBinary::applyUniforms()
926{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000927 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500928 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000929 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400930 LinkedUniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000931
932 if (targetUniform->dirty)
933 {
Nicolas Capense6050882013-07-08 10:43:10 -0400934 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000935 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000936 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000937 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000938
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000939 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000940 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000941 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000942
943 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000944 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000945 unsigned int samplerIndex = firstIndex + i;
946
947 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000948 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000949 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000950 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000951 }
952 }
953 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000954
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000955 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000956 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000957 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000958
959 for (int i = 0; i < count; i++)
960 {
961 unsigned int samplerIndex = firstIndex + i;
962
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000963 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000964 {
965 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000966 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000967 }
968 }
969 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000970 }
971 }
972 }
973
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500974 mRenderer->applyUniforms(*this);
975
976 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
977 {
978 mUniforms[uniformIndex]->dirty = false;
979 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000980}
981
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000982bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
983{
984 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
985 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
986
987 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
988 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
989
990 ASSERT(boundBuffers.size() == mUniformBlocks.size());
991
992 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
993 {
994 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
995 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
996
997 ASSERT(uniformBlock && uniformBuffer);
998
999 if (uniformBuffer->size() < uniformBlock->dataSize)
1000 {
1001 // undefined behaviour
1002 return false;
1003 }
1004
1005 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
1006
1007 if (uniformBlock->isReferencedByVertexShader())
1008 {
1009 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
1010 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
1011 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
1012 vertexUniformBuffers[registerIndex] = uniformBuffer;
1013 }
1014
1015 if (uniformBlock->isReferencedByFragmentShader())
1016 {
1017 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
1018 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
1019 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
1020 fragmentUniformBuffers[registerIndex] = uniformBuffer;
1021 }
1022 }
1023
1024 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
1025}
1026
Jamie Madill5f562732014-02-14 16:41:24 -05001027bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001028{
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001029 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
1030 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
Jamie Madill5f562732014-02-14 16:41:24 -05001031
1032 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001033 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001034 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001035 bool matched = false;
1036
Jamie Madill5f562732014-02-14 16:41:24 -05001037 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001038 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001039 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001040 if (output->name == input->name)
1041 {
Jamie Madill28167c62013-08-30 13:21:10 -04001042 if (!linkValidateVariables(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001043 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044 return false;
1045 }
1046
Jamie Madill139b9092013-08-30 13:21:06 -04001047 output->registerIndex = input->registerIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001048
1049 matched = true;
1050 break;
1051 }
1052 }
1053
1054 if (!matched)
1055 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001056 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001057 return false;
1058 }
1059 }
1060
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001061 return true;
1062}
1063
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001064bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1065{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001066 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001067
Geoff Lang11c3b302014-05-13 22:33:31 +00001068 int format = 0;
1069 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001070 if (format != GL_PROGRAM_BINARY_ANGLE)
1071 {
1072 infoLog.append("Invalid program binary format.");
1073 return false;
1074 }
1075
Geoff Lang11c3b302014-05-13 22:33:31 +00001076 int majorVersion = 0;
1077 int minorVersion = 0;
1078 stream.read(&majorVersion);
1079 stream.read(&minorVersion);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001080 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -05001081 {
1082 infoLog.append("Invalid program binary version.");
1083 return false;
1084 }
1085
Jamie Madill0aa84f62014-02-13 13:17:23 -05001086 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
Geoff Lang11c3b302014-05-13 22:33:31 +00001087 stream.read(commitString, ANGLE_COMMIT_HASH_SIZE);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001088 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001089 {
1090 infoLog.append("Invalid program binary version.");
1091 return false;
1092 }
1093
Geoff Lang11c3b302014-05-13 22:33:31 +00001094 int compileFlags = 0;
1095 stream.read(&compileFlags);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001096 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1097 {
1098 infoLog.append("Mismatched compilation flags.");
1099 return false;
1100 }
1101
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001102 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1103 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001104 stream.read(&mLinkedAttribute[i].type);
1105 std::string name;
1106 stream.read(&name);
1107 mLinkedAttribute[i].name = name;
1108 stream.read(&mShaderAttributes[i].type);
1109 stream.read(&mShaderAttributes[i].name);
1110 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001111 }
1112
Al Patrick3f2daa82013-08-07 12:58:57 -07001113 initAttributesByLayout();
1114
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001115 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1116 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001117 stream.read(&mSamplersPS[i].active);
1118 stream.read(&mSamplersPS[i].logicalTextureUnit);
1119
1120 int textureType;
1121 stream.read(&textureType);
1122 mSamplersPS[i].textureType = (TextureType) textureType;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001123 }
1124
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001125 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001126 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001127 stream.read(&mSamplersVS[i].active);
1128 stream.read(&mSamplersVS[i].logicalTextureUnit);
1129
1130 int textureType;
1131 stream.read(&textureType);
1132 mSamplersVS[i].textureType = (TextureType) textureType;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001133 }
1134
Geoff Lang11c3b302014-05-13 22:33:31 +00001135 stream.read(&mUsedVertexSamplerRange);
1136 stream.read(&mUsedPixelSamplerRange);
1137 stream.read(&mUsesPointSize);
1138 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001139
Geoff Lang11c3b302014-05-13 22:33:31 +00001140 size_t size;
1141 stream.read(&size);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001142 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001143 {
1144 infoLog.append("Invalid program binary.");
1145 return false;
1146 }
1147
Geoff Lang11c3b302014-05-13 22:33:31 +00001148 mUniforms.resize(size);
1149 for (unsigned int i = 0; i < size; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001150 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001151 GLenum type;
1152 GLenum precision;
1153 std::string name;
1154 unsigned int arraySize;
1155 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001156
Geoff Lang11c3b302014-05-13 22:33:31 +00001157 stream.read(&type);
1158 stream.read(&precision);
1159 stream.read(&name);
1160 stream.read(&arraySize);
1161 stream.read(&blockIndex);
1162
1163 int offset;
1164 int arrayStride;
1165 int matrixStride;
1166 bool isRowMajorMatrix;
1167
1168 stream.read(&offset);
1169 stream.read(&arrayStride);
1170 stream.read(&matrixStride);
1171 stream.read(&isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001172
Jamie Madill834e8b72014-04-11 13:33:58 -04001173 const gl::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001174
Geoff Lang11c3b302014-05-13 22:33:31 +00001175 mUniforms[i] = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001176
Geoff Lang11c3b302014-05-13 22:33:31 +00001177 stream.read(&mUniforms[i]->psRegisterIndex);
1178 stream.read(&mUniforms[i]->vsRegisterIndex);
1179 stream.read(&mUniforms[i]->registerCount);
1180 stream.read(&mUniforms[i]->registerElement);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001181 }
1182
Geoff Lang11c3b302014-05-13 22:33:31 +00001183 stream.read(&size);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001184 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001185 {
1186 infoLog.append("Invalid program binary.");
1187 return false;
1188 }
1189
Geoff Lang11c3b302014-05-13 22:33:31 +00001190 mUniformBlocks.resize(size);
1191 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001192 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001193 std::string name;
1194 unsigned int elementIndex;
1195 unsigned int dataSize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001196
Geoff Lang11c3b302014-05-13 22:33:31 +00001197 stream.read(&name);
1198 stream.read(&elementIndex);
1199 stream.read(&dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001200
Geoff Lang11c3b302014-05-13 22:33:31 +00001201 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001202
Geoff Lang11c3b302014-05-13 22:33:31 +00001203 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1204 stream.read(&uniformBlock.psRegisterIndex);
1205 stream.read(&uniformBlock.vsRegisterIndex);
1206
1207 size_t numMembers;
1208 stream.read(&numMembers);
1209 uniformBlock.memberUniformIndexes.resize(numMembers);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001210 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1211 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001212 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001213 }
1214 }
1215
Geoff Lang11c3b302014-05-13 22:33:31 +00001216 stream.read(&size);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001217 if (stream.error())
1218 {
1219 infoLog.append("Invalid program binary.");
1220 return false;
1221 }
1222
Geoff Lang11c3b302014-05-13 22:33:31 +00001223 mUniformIndex.resize(size);
1224 for (unsigned int i = 0; i < size; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001225 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001226 stream.read(&mUniformIndex[i].name);
1227 stream.read(&mUniformIndex[i].element);
1228 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001229 }
1230
Geoff Lang11c3b302014-05-13 22:33:31 +00001231 stream.read(&mTransformFeedbackBufferMode);
1232 stream.read(&size);
1233 mTransformFeedbackLinkedVaryings.resize(size);
1234 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001235 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001236 LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
Geoff Lang48dcae72014-02-05 16:28:24 -05001237
Geoff Lang11c3b302014-05-13 22:33:31 +00001238 stream.read(&varying.name);
1239 stream.read(&varying.type);
1240 stream.read(&varying.size);
1241 stream.read(&varying.semanticName);
1242 stream.read(&varying.semanticIndex);
1243 stream.read(&varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001244 }
1245
Geoff Lang11c3b302014-05-13 22:33:31 +00001246 stream.read(&mVertexHLSL);
1247 stream.read(&mVertexWorkarounds);
Jamie Madillc5a83002014-02-14 16:41:25 -05001248
Geoff Lang11c3b302014-05-13 22:33:31 +00001249 unsigned int vertexShaderCount;
1250 stream.read(&vertexShaderCount);
Jamie Madillc5a83002014-02-14 16:41:25 -05001251
1252 for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
1253 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001254 VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
Jamie Madillc5a83002014-02-14 16:41:25 -05001255
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001256 for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -05001257 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001258 VertexFormat *vertexInput = &inputLayout[inputIndex];
Geoff Lang11c3b302014-05-13 22:33:31 +00001259 stream.read(&vertexInput->mType);
1260 stream.read(&vertexInput->mNormalized);
1261 stream.read(&vertexInput->mComponents);
1262 stream.read(&vertexInput->mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001263 }
1264
Geoff Lang11c3b302014-05-13 22:33:31 +00001265 unsigned int vertexShaderSize;
1266 stream.read(&vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001267
1268 const char *vertexShaderFunction = (const char*) binary + stream.offset();
1269
1270 rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001271 vertexShaderSize, rx::SHADER_VERTEX,
1272 mTransformFeedbackLinkedVaryings,
1273 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001274 if (!shaderExecutable)
1275 {
1276 infoLog.append("Could not create vertex shader.");
1277 return false;
1278 }
1279
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001280 // generated converted input layout
1281 GLenum signature[MAX_VERTEX_ATTRIBS];
1282 mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
1283
1284 // add new binary
1285 mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, signature, shaderExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -05001286
1287 stream.skip(vertexShaderSize);
1288 }
1289
Geoff Lang11c3b302014-05-13 22:33:31 +00001290 unsigned int pixelShaderSize;
1291 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001292
Jamie Madillc5a83002014-02-14 16:41:25 -05001293 const char *pixelShaderFunction = (const char*) binary + stream.offset();
1294 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001295 pixelShaderSize, rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
1296 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001297 if (!mPixelExecutable)
1298 {
1299 infoLog.append("Could not create pixel shader.");
1300 return false;
1301 }
1302 stream.skip(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001303
Geoff Lang11c3b302014-05-13 22:33:31 +00001304 unsigned int geometryShaderSize;
1305 stream.read(&geometryShaderSize);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001306
Jamie Madillc5a83002014-02-14 16:41:25 -05001307 if (geometryShaderSize > 0)
1308 {
1309 const char *geometryShaderFunction = (const char*) binary + stream.offset();
1310 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001311 geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
1312 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001313 if (!mGeometryExecutable)
1314 {
1315 infoLog.append("Could not create geometry shader.");
1316 SafeDelete(mPixelExecutable);
1317 return false;
1318 }
1319 stream.skip(geometryShaderSize);
1320 }
1321
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001322 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001323
daniel@transgaming.com36038542012-11-28 20:59:26 +00001324 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001325 ptr += sizeof(GUID);
1326
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001327 GUID identifier = mRenderer->getAdapterIdentifier();
1328 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001329 {
1330 infoLog.append("Invalid program binary.");
1331 return false;
1332 }
1333
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001334 initializeUniformStorage();
1335
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001336 return true;
1337}
1338
1339bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1340{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001341 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001342
Geoff Lang11c3b302014-05-13 22:33:31 +00001343 stream.write(GL_PROGRAM_BINARY_ANGLE);
1344 stream.write(ANGLE_MAJOR_VERSION);
1345 stream.write(ANGLE_MINOR_VERSION);
1346 stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE);
1347 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001348
1349 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1350 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001351 stream.write(mLinkedAttribute[i].type);
1352 stream.write(mLinkedAttribute[i].name);
1353 stream.write(mShaderAttributes[i].type);
1354 stream.write(mShaderAttributes[i].name);
1355 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001356 }
1357
1358 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1359 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001360 stream.write(mSamplersPS[i].active);
1361 stream.write(mSamplersPS[i].logicalTextureUnit);
1362 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001363 }
1364
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001365 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001366 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001367 stream.write(mSamplersVS[i].active);
1368 stream.write(mSamplersVS[i].logicalTextureUnit);
1369 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001370 }
1371
Geoff Lang11c3b302014-05-13 22:33:31 +00001372 stream.write(mUsedVertexSamplerRange);
1373 stream.write(mUsedPixelSamplerRange);
1374 stream.write(mUsesPointSize);
1375 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001376
Geoff Lang11c3b302014-05-13 22:33:31 +00001377 stream.write(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001378 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001379 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001380 const LinkedUniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001381
Geoff Lang11c3b302014-05-13 22:33:31 +00001382 stream.write(uniform.type);
1383 stream.write(uniform.precision);
1384 stream.write(uniform.name);
1385 stream.write(uniform.arraySize);
1386 stream.write(uniform.blockIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001387
Geoff Lang11c3b302014-05-13 22:33:31 +00001388 stream.write(uniform.blockInfo.offset);
1389 stream.write(uniform.blockInfo.arrayStride);
1390 stream.write(uniform.blockInfo.matrixStride);
1391 stream.write(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001392
Geoff Lang11c3b302014-05-13 22:33:31 +00001393 stream.write(uniform.psRegisterIndex);
1394 stream.write(uniform.vsRegisterIndex);
1395 stream.write(uniform.registerCount);
1396 stream.write(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001397 }
1398
Geoff Lang11c3b302014-05-13 22:33:31 +00001399 stream.write(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001400 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001401 {
1402 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1403
Geoff Lang11c3b302014-05-13 22:33:31 +00001404 stream.write(uniformBlock.name);
1405 stream.write(uniformBlock.elementIndex);
1406 stream.write(uniformBlock.dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001407
Geoff Lang11c3b302014-05-13 22:33:31 +00001408 stream.write(uniformBlock.memberUniformIndexes.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001409 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1410 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001411 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001412 }
1413
Geoff Lang11c3b302014-05-13 22:33:31 +00001414 stream.write(uniformBlock.psRegisterIndex);
1415 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001416 }
1417
Geoff Lang11c3b302014-05-13 22:33:31 +00001418 stream.write(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001419 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001420 {
Geoff Lang11c3b302014-05-13 22:33:31 +00001421 stream.write(mUniformIndex[i].name);
1422 stream.write(mUniformIndex[i].element);
1423 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001424 }
1425
Geoff Lang11c3b302014-05-13 22:33:31 +00001426 stream.write(mTransformFeedbackBufferMode);
1427 stream.write(mTransformFeedbackLinkedVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001428 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
1429 {
1430 const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
1431
Geoff Lang11c3b302014-05-13 22:33:31 +00001432 stream.write(varying.name);
1433 stream.write(varying.type);
1434 stream.write(varying.size);
1435 stream.write(varying.semanticName);
1436 stream.write(varying.semanticIndex);
1437 stream.write(varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001438 }
1439
Geoff Lang11c3b302014-05-13 22:33:31 +00001440 stream.write(mVertexHLSL);
1441 stream.write(mVertexWorkarounds);
Jamie Madillc5a83002014-02-14 16:41:25 -05001442
Geoff Lang11c3b302014-05-13 22:33:31 +00001443 stream.write(mVertexExecutables.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001444 for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
1445 {
1446 VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
1447
1448 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1449 {
1450 const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
Geoff Lang11c3b302014-05-13 22:33:31 +00001451 stream.write(vertexInput.mType);
1452 stream.write(vertexInput.mNormalized);
1453 stream.write(vertexInput.mComponents);
1454 stream.write(vertexInput.mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001455 }
1456
Geoff Lang11c3b302014-05-13 22:33:31 +00001457 UINT vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
1458 stream.write(vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001459
1460 unsigned char *vertexBlob = static_cast<unsigned char *>(vertexExecutable->shaderExecutable()->getFunction());
Geoff Lang11c3b302014-05-13 22:33:31 +00001461 stream.write(vertexBlob, vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001462 }
1463
Geoff Lang11c3b302014-05-13 22:33:31 +00001464 UINT pixelShaderSize = mPixelExecutable->getLength();
1465 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001466
Jamie Madillc5a83002014-02-14 16:41:25 -05001467 unsigned char *pixelBlob = static_cast<unsigned char *>(mPixelExecutable->getFunction());
Geoff Lang11c3b302014-05-13 22:33:31 +00001468 stream.write(pixelBlob, pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001469
Geoff Lang11c3b302014-05-13 22:33:31 +00001470 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1471 stream.write(geometryShaderSize);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001472
Jamie Madillc5a83002014-02-14 16:41:25 -05001473 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1474 {
1475 unsigned char *geometryBlob = static_cast<unsigned char *>(mGeometryExecutable->getFunction());
Geoff Lang11c3b302014-05-13 22:33:31 +00001476 stream.write(geometryBlob, geometryShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001477 }
1478
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001479 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001480
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001481 GLsizei streamLength = stream.length();
1482 const void *streamData = stream.data();
1483
Jamie Madillc5a83002014-02-14 16:41:25 -05001484 GLsizei totalLength = streamLength + sizeof(GUID);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001485 if (totalLength > bufSize)
1486 {
1487 if (length)
1488 {
1489 *length = 0;
1490 }
1491
1492 return false;
1493 }
1494
1495 if (binary)
1496 {
1497 char *ptr = (char*) binary;
1498
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001499 memcpy(ptr, streamData, streamLength);
1500 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001501
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001502 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001503 ptr += sizeof(GUID);
1504
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001505 ASSERT(ptr - totalLength == binary);
1506 }
1507
1508 if (length)
1509 {
1510 *length = totalLength;
1511 }
1512
1513 return true;
1514}
1515
1516GLint ProgramBinary::getLength()
1517{
1518 GLint length;
1519 if (save(NULL, INT_MAX, &length))
1520 {
1521 return length;
1522 }
1523 else
1524 {
1525 return 0;
1526 }
1527}
1528
Geoff Lang48dcae72014-02-05 16:28:24 -05001529bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader,
1530 const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001531{
1532 if (!fragmentShader || !fragmentShader->isCompiled())
1533 {
1534 return false;
1535 }
1536
1537 if (!vertexShader || !vertexShader->isCompiled())
1538 {
1539 return false;
1540 }
1541
Geoff Lang48dcae72014-02-05 16:28:24 -05001542 mTransformFeedbackLinkedVaryings.clear();
1543 mTransformFeedbackBufferMode = transformFeedbackBufferMode;
1544
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001545 mShaderVersion = vertexShader->getShaderVersion();
1546
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001547 std::string pixelHLSL = fragmentShader->getHLSL();
Jamie Madillc5a83002014-02-14 16:41:25 -05001548 mVertexHLSL = vertexShader->getHLSL();
1549 mVertexWorkarounds = vertexShader->getD3DWorkarounds();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001550
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001551 // Map the varyings to the register file
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001552 VaryingPacking packing = { NULL };
Geoff Lang48dcae72014-02-05 16:28:24 -05001553 int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader, vertexShader, transformFeedbackVaryings);
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001554
1555 if (registers < 0)
1556 {
1557 return false;
1558 }
1559
Jamie Madill5f562732014-02-14 16:41:24 -05001560 if (!linkVaryings(infoLog, fragmentShader, vertexShader))
1561 {
1562 return false;
1563 }
1564
1565 mUsesPointSize = vertexShader->usesPointSize();
Geoff Lang48dcae72014-02-05 16:28:24 -05001566 std::vector<LinkedVarying> linkedVaryings;
Jamie Madillc5a83002014-02-14 16:41:25 -05001567 if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, pixelHLSL, mVertexHLSL,
Geoff Lang48dcae72014-02-05 16:28:24 -05001568 fragmentShader, vertexShader, transformFeedbackVaryings,
1569 &linkedVaryings, &mOutputVariables))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001570 {
1571 return false;
1572 }
1573
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001574 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001575
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001576 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1577 {
1578 success = false;
1579 }
1580
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001581 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001582 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001583 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001584 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001585
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001586 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Jamie Madill5f562732014-02-14 16:41:24 -05001587 if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001588 {
Jamie Madill07d68852014-05-06 16:31:14 -04001589 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, BlockMemberInfo::getDefaultBlockInfo()));
1590 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, BlockMemberInfo::getDefaultBlockInfo()));
1591 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, BlockMemberInfo::getDefaultBlockInfo()));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001592 }
1593
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001594 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1595 {
1596 success = false;
1597 }
1598
Geoff Lang48dcae72014-02-05 16:28:24 -05001599 if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
1600 transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings))
1601 {
1602 success = false;
1603 }
1604
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001605 if (success)
1606 {
Jamie Madillc5a83002014-02-14 16:41:25 -05001607 VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
1608 GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout);
1609
1610 rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
Geoff Lang48dcae72014-02-05 16:28:24 -05001611 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL,
1612 mTransformFeedbackLinkedVaryings,
1613 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1614 fragmentShader->getD3DWorkarounds());
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001615
1616 if (usesGeometryShader())
1617 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001618 std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShader, vertexShader);
Geoff Lang48dcae72014-02-05 16:28:24 -05001619 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY,
1620 mTransformFeedbackLinkedVaryings,
1621 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1622 rx::ANGLE_D3D_WORKAROUND_NONE);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001623 }
1624
Jamie Madillc5a83002014-02-14 16:41:25 -05001625 if (!defaultVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001626 {
1627 infoLog.append("Failed to create D3D shaders.");
1628 success = false;
1629
Jamie Madillc5a83002014-02-14 16:41:25 -05001630 while (!mVertexExecutables.empty())
1631 {
1632 delete mVertexExecutables.back();
1633 mVertexExecutables.pop_back();
1634 }
1635
1636 SafeDelete(mGeometryExecutable);
1637 SafeDelete(mPixelExecutable);
Geoff Lang48dcae72014-02-05 16:28:24 -05001638
1639 mTransformFeedbackLinkedVaryings.clear();
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001640 }
1641 }
1642
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001643 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001644}
1645
1646// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001647bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001648{
1649 unsigned int usedLocations = 0;
Jamie Madill834e8b72014-04-11 13:33:58 -04001650 const std::vector<gl::Attribute> &activeAttributes = vertexShader->activeAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001651
1652 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001653 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001654 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001655 const gl::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001656 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001657
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001658 mShaderAttributes[attributeIndex] = attribute;
1659
Jamie Madilleba4eff2013-06-20 11:55:51 -04001660 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001661 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001662 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001663
1664 if (rows + location > MAX_VERTEX_ATTRIBS)
1665 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001666 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 +00001667
1668 return false;
1669 }
1670
Jamie Madilleba4eff2013-06-20 11:55:51 -04001671 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001672 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001673 const int rowLocation = location + row;
Jamie Madill834e8b72014-04-11 13:33:58 -04001674 gl::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001675
1676 // In GLSL 3.00, attribute aliasing produces a link error
1677 // In GLSL 1.00, attribute aliasing is allowed
1678 if (mShaderVersion >= 300)
1679 {
1680 if (!linkedAttribute.name.empty())
1681 {
1682 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1683 return false;
1684 }
1685 }
1686
1687 linkedAttribute = attribute;
1688 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001689 }
1690 }
1691 }
1692
1693 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001694 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001695 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001696 const gl::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001697 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001698
Jamie Madilleba4eff2013-06-20 11:55:51 -04001699 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001700 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001701 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001702 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1703
1704 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1705 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001706 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001707
1708 return false; // Fail to link
1709 }
1710
Jamie Madilldefb6742013-06-20 11:55:51 -04001711 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001712 }
1713 }
1714
1715 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1716 {
1717 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04001718 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001719
1720 for (int r = 0; r < rows; r++)
1721 {
1722 mSemanticIndex[attributeIndex++] = index++;
1723 }
1724 }
1725
Al Patrick3f2daa82013-08-07 12:58:57 -07001726 initAttributesByLayout();
1727
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001728 return true;
1729}
1730
Jamie Madill834e8b72014-04-11 13:33:58 -04001731bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const gl::ShaderVariable &vertexVariable, const gl::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001732{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001733 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001734 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001735 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001736 return false;
1737 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001738 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001739 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001740 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001741 return false;
1742 }
Jamie Madill28167c62013-08-30 13:21:10 -04001743 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001744 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001745 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001746 return false;
1747 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001748
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001749 return true;
1750}
1751
1752template <class ShaderVarType>
1753bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
1754{
1755 if (vertexVar.fields.size() != fragmentVar.fields.size())
1756 {
1757 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
1758 return false;
1759 }
1760 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001761 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1762 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001763 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
1764 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001765
1766 if (vertexMember.name != fragmentMember.name)
1767 {
Jamie Madill28167c62013-08-30 13:21:10 -04001768 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
1769 memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001770 return false;
1771 }
1772
Jamie Madill28167c62013-08-30 13:21:10 -04001773 const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001774 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001775 {
1776 return false;
1777 }
1778 }
1779
1780 return true;
1781}
1782
Jamie Madill834e8b72014-04-11 13:33:58 -04001783bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const gl::Uniform &vertexUniform, const gl::Uniform &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001784{
Jamie Madill28167c62013-08-30 13:21:10 -04001785 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001786 {
1787 return false;
1788 }
1789
Jamie Madill834e8b72014-04-11 13:33:58 -04001790 if (!linkValidateFields<gl::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001791 {
1792 return false;
1793 }
1794
1795 return true;
1796}
1797
Jamie Madill834e8b72014-04-11 13:33:58 -04001798bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const gl::Varying &vertexVarying, const gl::Varying &fragmentVarying)
Jamie Madill28167c62013-08-30 13:21:10 -04001799{
1800 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1801 {
1802 return false;
1803 }
1804
1805 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1806 {
1807 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1808 return false;
1809 }
1810
Jamie Madill834e8b72014-04-11 13:33:58 -04001811 if (!linkValidateFields<gl::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
Jamie Madill28167c62013-08-30 13:21:10 -04001812 {
1813 return false;
1814 }
1815
1816 return true;
1817}
1818
Jamie Madill834e8b72014-04-11 13:33:58 -04001819bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const gl::InterfaceBlockField &vertexUniform, const gl::InterfaceBlockField &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001820{
Jamie Madill28167c62013-08-30 13:21:10 -04001821 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001822 {
1823 return false;
1824 }
1825
1826 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
1827 {
1828 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1829 return false;
1830 }
1831
Jamie Madill834e8b72014-04-11 13:33:58 -04001832 if (!linkValidateFields<gl::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001833 {
1834 return false;
1835 }
1836
1837 return true;
1838}
1839
Jamie Madill834e8b72014-04-11 13:33:58 -04001840bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<gl::Uniform> &vertexUniforms, const std::vector<gl::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001841{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001842 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madill834e8b72014-04-11 13:33:58 -04001843 typedef std::map<std::string, const gl::Uniform*> UniformMap;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001844 UniformMap linkedUniforms;
1845
1846 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1847 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001848 const gl::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001849 linkedUniforms[vertexUniform.name] = &vertexUniform;
1850 }
1851
1852 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1853 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001854 const gl::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001855 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1856 if (entry != linkedUniforms.end())
1857 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001858 const gl::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001859 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001860 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001861 {
1862 return false;
1863 }
1864 }
1865 }
1866
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001867 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001868 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001869 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001870 {
1871 return false;
1872 }
1873 }
1874
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001875 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001876 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001877 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001878 {
1879 return false;
1880 }
1881 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001882
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001883 initializeUniformStorage();
1884
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001885 return true;
1886}
1887
Jamie Madill834e8b72014-04-11 13:33:58 -04001888int totalRegisterCount(const gl::Uniform &uniform)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001889{
1890 int registerCount = 0;
1891
1892 if (!uniform.fields.empty())
1893 {
1894 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
1895 {
1896 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
1897 }
1898 }
1899 else
1900 {
1901 registerCount = 1;
1902 }
1903
1904 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
1905}
1906
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001907TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
1908{
1909 switch(samplerType)
1910 {
1911 case GL_SAMPLER_2D:
1912 case GL_INT_SAMPLER_2D:
1913 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001914 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001915 return TEXTURE_2D;
1916 case GL_SAMPLER_3D:
1917 case GL_INT_SAMPLER_3D:
1918 case GL_UNSIGNED_INT_SAMPLER_3D:
1919 return TEXTURE_3D;
1920 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001921 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001922 return TEXTURE_CUBE;
1923 case GL_INT_SAMPLER_CUBE:
1924 case GL_UNSIGNED_INT_SAMPLER_CUBE:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001925 return TEXTURE_CUBE;
1926 case GL_SAMPLER_2D_ARRAY:
1927 case GL_INT_SAMPLER_2D_ARRAY:
1928 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001929 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001930 return TEXTURE_2D_ARRAY;
1931 default: UNREACHABLE();
1932 }
1933
1934 return TEXTURE_2D;
1935}
1936
Jamie Madill834e8b72014-04-11 13:33:58 -04001937bool ProgramBinary::defineUniform(GLenum shader, const gl::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001938{
Jamie Madillfcef3362013-11-13 19:37:19 -05001939 if (constant.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001940 {
1941 if (constant.arraySize > 0)
1942 {
1943 unsigned int elementRegisterIndex = constant.registerIndex;
1944
1945 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
1946 {
1947 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1948 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001949 const gl::Uniform &field = constant.fields[fieldIndex];
Jamie Madill5f562732014-02-14 16:41:24 -05001950 const std::string &uniformName = constant.name + ArrayString(elementIndex) + "." + field.name;
Jamie Madill834e8b72014-04-11 13:33:58 -04001951 gl::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
Jamie Madillfcef3362013-11-13 19:37:19 -05001952 elementRegisterIndex, field.elementIndex);
1953
1954 fieldUniform.fields = field.fields;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001955 if (!defineUniform(shader, fieldUniform, infoLog))
1956 {
1957 return false;
1958 }
1959 elementRegisterIndex += totalRegisterCount(field);
1960 }
1961 }
1962 }
1963 else
1964 {
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001965 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1966 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001967 const gl::Uniform &field = constant.fields[fieldIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001968 const std::string &uniformName = constant.name + "." + field.name;
1969
Jamie Madill834e8b72014-04-11 13:33:58 -04001970 gl::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
Jamie Madill56093782013-08-30 13:21:11 -04001971 field.registerIndex, field.elementIndex);
1972
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001973 fieldUniform.fields = field.fields;
1974
1975 if (!defineUniform(shader, fieldUniform, infoLog))
1976 {
1977 return false;
1978 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001979 }
1980 }
1981
1982 return true;
1983 }
1984
Nicolas Capense6050882013-07-08 10:43:10 -04001985 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001986 {
1987 unsigned int samplerIndex = constant.registerIndex;
1988
1989 do
1990 {
1991 if (shader == GL_VERTEX_SHADER)
1992 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001993 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001994 {
1995 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001996 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001997 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1998 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1999 }
2000 else
2001 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002002 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002003 return false;
2004 }
2005 }
2006 else if (shader == GL_FRAGMENT_SHADER)
2007 {
2008 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2009 {
2010 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002011 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002012 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2013 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2014 }
2015 else
2016 {
2017 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2018 return false;
2019 }
2020 }
2021 else UNREACHABLE();
2022
2023 samplerIndex++;
2024 }
2025 while (samplerIndex < constant.registerIndex + constant.arraySize);
2026 }
2027
Jamie Madill834e8b72014-04-11 13:33:58 -04002028 LinkedUniform *uniform = NULL;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002029 GLint location = getUniformLocation(constant.name);
2030
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002031 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002032 {
2033 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002034 }
2035 else
2036 {
Jamie Madill07d68852014-05-06 16:31:14 -04002037 uniform = new LinkedUniform(constant.type, constant.precision, constant.name, constant.arraySize,
2038 -1, BlockMemberInfo::getDefaultBlockInfo());
Jamie Madill56093782013-08-30 13:21:11 -04002039 uniform->registerElement = constant.elementIndex;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002040 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002041
2042 if (!uniform)
2043 {
2044 return false;
2045 }
2046
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002047 if (shader == GL_FRAGMENT_SHADER)
2048 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002049 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002050 }
2051 else if (shader == GL_VERTEX_SHADER)
2052 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002053 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002054 }
2055 else UNREACHABLE();
2056
2057 if (location >= 0)
2058 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002059 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002060 }
2061
2062 mUniforms.push_back(uniform);
2063 unsigned int uniformIndex = mUniforms.size() - 1;
2064
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002065 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002066 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002067 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002068 }
2069
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002070 if (shader == GL_VERTEX_SHADER)
2071 {
2072 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2073 {
2074 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2075 return false;
2076 }
2077 }
2078 else if (shader == GL_FRAGMENT_SHADER)
2079 {
2080 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2081 {
2082 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2083 return false;
2084 }
2085 }
2086 else UNREACHABLE();
2087
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002088 return true;
2089}
2090
Jamie Madill834e8b72014-04-11 13:33:58 -04002091bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const gl::InterfaceBlock &vertexInterfaceBlock, const gl::InterfaceBlock &fragmentInterfaceBlock)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002092{
2093 const char* blockName = vertexInterfaceBlock.name.c_str();
2094
2095 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002096 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002097 {
2098 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2099 return false;
2100 }
2101
2102 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2103 {
2104 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2105 return false;
2106 }
2107
Jamie Madill9060a4e2013-08-12 16:22:57 -07002108 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2109 {
2110 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2111 return false;
2112 }
2113
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002114 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002115 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2116 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002117 const gl::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2118 const gl::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002119
2120 if (vertexMember.name != fragmentMember.name)
2121 {
Jamie Madill28167c62013-08-30 13:21:10 -04002122 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 +00002123 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2124 return false;
2125 }
2126
Jamie Madill28167c62013-08-30 13:21:10 -04002127 std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002128 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002129 {
2130 return false;
2131 }
2132 }
2133
2134 return true;
2135}
2136
Jamie Madill834e8b72014-04-11 13:33:58 -04002137bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const std::vector<gl::InterfaceBlock> &vertexInterfaceBlocks,
2138 const std::vector<gl::InterfaceBlock> &fragmentInterfaceBlocks)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002139{
2140 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jamie Madill834e8b72014-04-11 13:33:58 -04002141 typedef std::map<std::string, const gl::InterfaceBlock*> UniformBlockMap;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002142 UniformBlockMap linkedUniformBlocks;
2143
2144 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2145 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002146 const gl::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002147 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2148 }
2149
2150 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2151 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002152 const gl::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002153 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2154 if (entry != linkedUniformBlocks.end())
2155 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002156 const gl::InterfaceBlock &vertexInterfaceBlock = *entry->second;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002157 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2158 {
2159 return false;
2160 }
2161 }
2162 }
2163
2164 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2165 {
2166 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2167 {
2168 return false;
2169 }
2170 }
2171
2172 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2173 {
2174 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2175 {
2176 return false;
2177 }
2178 }
2179
2180 return true;
2181}
2182
Geoff Lang48dcae72014-02-05 16:28:24 -05002183bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
2184 const std::vector<std::string> &transformFeedbackVaryingNames,
2185 GLenum transformFeedbackBufferMode,
2186 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const
2187{
2188 size_t totalComponents = 0;
2189 const size_t maxSeparateComponents = mRenderer->getMaxTransformFeedbackSeparateComponents();
2190 const size_t maxInterleavedComponents = mRenderer->getMaxTransformFeedbackInterleavedComponents();
2191
2192 // Gather the linked varyings that are used for transform feedback, they should all exist.
2193 outTransformFeedbackLinkedVaryings->clear();
2194 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
2195 {
2196 bool found = false;
2197 for (size_t j = 0; j < linkedVaryings.size(); j++)
2198 {
2199 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
2200 {
2201 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
2202 {
2203 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
2204 {
2205 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
2206 return false;
2207 }
2208 }
2209
2210 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
2211 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
2212 componentCount > maxSeparateComponents)
2213 {
2214 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
2215 linkedVaryings[j].name.c_str(), componentCount, maxSeparateComponents);
2216 return false;
2217 }
2218
2219 totalComponents += componentCount;
2220
2221 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
2222 found = true;
2223 break;
2224 }
2225 }
2226
2227 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2228 ASSERT(found);
2229 }
2230
2231 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > maxInterleavedComponents)
2232 {
2233 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
2234 totalComponents, maxInterleavedComponents);
2235 return false;
2236 }
2237
2238 return true;
2239}
2240
Jamie Madill834e8b72014-04-11 13:33:58 -04002241void ProgramBinary::defineUniformBlockMembers(const std::vector<gl::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002242{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002243 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002244 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002245 const gl::InterfaceBlockField &field = fields[uniformIndex];
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002246 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002247
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002248 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002249 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002250 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002251 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002252 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002253 {
Jamie Madill5f562732014-02-14 16:41:24 -05002254 const std::string uniformElementName = fieldName + ArrayString(arrayElement);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002255 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002256 }
2257 }
2258 else
2259 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002260 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002261 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002262 }
2263 else
2264 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002265 LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
2266 blockIndex, **blockInfoItr);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002267
2268 // add to uniform list, but not index, since uniform block uniforms have no location
2269 blockUniformIndexes->push_back(mUniforms.size());
2270 mUniforms.push_back(newUniform);
2271 (*blockInfoItr)++;
2272 }
2273 }
2274}
2275
Jamie Madill834e8b72014-04-11 13:33:58 -04002276bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const gl::InterfaceBlock &interfaceBlock)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002277{
2278 // create uniform block entries if they do not exist
2279 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2280 {
2281 std::vector<unsigned int> blockUniformIndexes;
2282 const unsigned int blockIndex = mUniformBlocks.size();
2283
2284 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002285 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002286 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002287
2288 // create all the uniform blocks
2289 if (interfaceBlock.arraySize > 0)
2290 {
2291 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2292 {
2293 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2294 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2295 mUniformBlocks.push_back(newUniformBlock);
2296 }
2297 }
2298 else
2299 {
2300 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2301 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2302 mUniformBlocks.push_back(newUniformBlock);
2303 }
2304 }
2305
2306 // Assign registers to the uniform blocks
2307 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2308 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2309 ASSERT(blockIndex != GL_INVALID_INDEX);
2310 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2311
2312 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2313 {
2314 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2315 ASSERT(uniformBlock->name == interfaceBlock.name);
2316
2317 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2318 {
2319 return false;
2320 }
2321 }
2322
2323 return true;
2324}
2325
2326bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2327{
2328 if (shader == GL_VERTEX_SHADER)
2329 {
2330 uniformBlock->vsRegisterIndex = registerIndex;
2331 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2332
2333 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2334 {
2335 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2336 return false;
2337 }
2338 }
2339 else if (shader == GL_FRAGMENT_SHADER)
2340 {
2341 uniformBlock->psRegisterIndex = registerIndex;
2342 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2343
2344 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2345 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002346 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002347 return false;
2348 }
2349 }
2350 else UNREACHABLE();
2351
2352 return true;
2353}
2354
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002355bool ProgramBinary::isValidated() const
2356{
2357 return mValidated;
2358}
2359
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002360void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002361{
2362 // Skip over inactive attributes
2363 unsigned int activeAttribute = 0;
2364 unsigned int attribute;
2365 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2366 {
2367 if (mLinkedAttribute[attribute].name.empty())
2368 {
2369 continue;
2370 }
2371
2372 if (activeAttribute == index)
2373 {
2374 break;
2375 }
2376
2377 activeAttribute++;
2378 }
2379
2380 if (bufsize > 0)
2381 {
2382 const char *string = mLinkedAttribute[attribute].name.c_str();
2383
2384 strncpy(name, string, bufsize);
2385 name[bufsize - 1] = '\0';
2386
2387 if (length)
2388 {
2389 *length = strlen(name);
2390 }
2391 }
2392
2393 *size = 1; // Always a single 'type' instance
2394
2395 *type = mLinkedAttribute[attribute].type;
2396}
2397
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002398GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002399{
2400 int count = 0;
2401
2402 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2403 {
2404 if (!mLinkedAttribute[attributeIndex].name.empty())
2405 {
2406 count++;
2407 }
2408 }
2409
2410 return count;
2411}
2412
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002413GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002414{
2415 int maxLength = 0;
2416
2417 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2418 {
2419 if (!mLinkedAttribute[attributeIndex].name.empty())
2420 {
2421 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2422 }
2423 }
2424
2425 return maxLength;
2426}
2427
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002428void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002429{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002430 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002431
2432 if (bufsize > 0)
2433 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002434 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002435
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002436 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002437 {
2438 string += "[0]";
2439 }
2440
2441 strncpy(name, string.c_str(), bufsize);
2442 name[bufsize - 1] = '\0';
2443
2444 if (length)
2445 {
2446 *length = strlen(name);
2447 }
2448 }
2449
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002450 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002451
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002452 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002453}
2454
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002455GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002456{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002457 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002458}
2459
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002460GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002461{
2462 int maxLength = 0;
2463
2464 unsigned int numUniforms = mUniforms.size();
2465 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2466 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002467 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002468 {
2469 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2470 if (mUniforms[uniformIndex]->isArray())
2471 {
2472 length += 3; // Counting in "[0]".
2473 }
2474 maxLength = std::max(length, maxLength);
2475 }
2476 }
2477
2478 return maxLength;
2479}
2480
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002481GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2482{
Jamie Madill834e8b72014-04-11 13:33:58 -04002483 const gl::LinkedUniform& uniform = *mUniforms[index];
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002484
2485 switch (pname)
2486 {
2487 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2488 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002489 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 +00002490 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002491
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002492 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2493 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2494 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2495 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002496
2497 default:
2498 UNREACHABLE();
2499 break;
2500 }
2501 return 0;
2502}
2503
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002504void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2505{
2506 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2507
2508 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2509
2510 if (bufSize > 0)
2511 {
2512 std::string string = uniformBlock.name;
2513
2514 if (uniformBlock.isArrayElement())
2515 {
Jamie Madill5f562732014-02-14 16:41:24 -05002516 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002517 }
2518
2519 strncpy(uniformBlockName, string.c_str(), bufSize);
2520 uniformBlockName[bufSize - 1] = '\0';
2521
2522 if (length)
2523 {
2524 *length = strlen(uniformBlockName);
2525 }
2526 }
2527}
2528
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002529void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2530{
2531 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2532
2533 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2534
2535 switch (pname)
2536 {
2537 case GL_UNIFORM_BLOCK_DATA_SIZE:
2538 *params = static_cast<GLint>(uniformBlock.dataSize);
2539 break;
2540 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002541 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002542 break;
2543 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2544 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2545 break;
2546 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2547 {
2548 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2549 {
2550 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2551 }
2552 }
2553 break;
2554 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2555 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2556 break;
2557 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2558 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2559 break;
2560 default: UNREACHABLE();
2561 }
2562}
2563
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002564GLuint ProgramBinary::getActiveUniformBlockCount() const
2565{
2566 return mUniformBlocks.size();
2567}
2568
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002569GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2570{
2571 unsigned int maxLength = 0;
2572
2573 unsigned int numUniformBlocks = mUniformBlocks.size();
2574 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2575 {
2576 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2577 if (!uniformBlock.name.empty())
2578 {
2579 const unsigned int length = uniformBlock.name.length() + 1;
2580
2581 // Counting in "[0]".
2582 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2583
2584 maxLength = std::max(length + arrayLength, maxLength);
2585 }
2586 }
2587
2588 return maxLength;
2589}
2590
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002591void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002592{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002593 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002594 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002595 {
2596 mValidated = false;
2597 }
2598 else
2599 {
2600 mValidated = true;
2601 }
2602}
2603
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002604bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002605{
2606 // if any two active samplers in a program are of different types, but refer to the same
2607 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2608 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2609
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002610 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002611 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002612
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002613 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002614 {
2615 textureUnitType[i] = TEXTURE_UNKNOWN;
2616 }
2617
2618 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2619 {
2620 if (mSamplersPS[i].active)
2621 {
2622 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2623
2624 if (unit >= maxCombinedTextureImageUnits)
2625 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002626 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002627 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002628 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002629 }
2630
2631 return false;
2632 }
2633
2634 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2635 {
2636 if (mSamplersPS[i].textureType != textureUnitType[unit])
2637 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002638 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002639 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002640 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002641 }
2642
2643 return false;
2644 }
2645 }
2646 else
2647 {
2648 textureUnitType[unit] = mSamplersPS[i].textureType;
2649 }
2650 }
2651 }
2652
2653 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2654 {
2655 if (mSamplersVS[i].active)
2656 {
2657 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2658
2659 if (unit >= maxCombinedTextureImageUnits)
2660 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002661 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002662 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002663 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664 }
2665
2666 return false;
2667 }
2668
2669 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2670 {
2671 if (mSamplersVS[i].textureType != textureUnitType[unit])
2672 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002673 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002674 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002675 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002676 }
2677
2678 return false;
2679 }
2680 }
2681 else
2682 {
2683 textureUnitType[unit] = mSamplersVS[i].textureType;
2684 }
2685 }
2686 }
2687
2688 return true;
2689}
2690
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002691ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2692{
2693}
2694
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002695struct AttributeSorter
2696{
2697 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2698 : originalIndices(semanticIndices)
2699 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002700 }
2701
2702 bool operator()(int a, int b)
2703 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002704 if (originalIndices[a] == -1) return false;
2705 if (originalIndices[b] == -1) return true;
2706 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002707 }
2708
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002709 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2710};
2711
Al Patrick3f2daa82013-08-07 12:58:57 -07002712void ProgramBinary::initAttributesByLayout()
2713{
2714 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2715 {
2716 mAttributesByLayout[i] = i;
2717 }
2718
2719 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2720}
2721
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002722void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2723{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002724 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2725
2726 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2727 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002728 oldTranslatedAttributes[i] = attributes[i];
2729 }
2730
2731 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2732 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002733 int oldIndex = mAttributesByLayout[i];
2734 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002735 attributes[i] = oldTranslatedAttributes[oldIndex];
2736 }
2737}
2738
Jamie Madill8ff21ae2014-02-04 16:04:05 -05002739void ProgramBinary::initializeUniformStorage()
2740{
2741 // Compute total default block size
2742 unsigned int vertexRegisters = 0;
2743 unsigned int fragmentRegisters = 0;
2744 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2745 {
Jamie Madill834e8b72014-04-11 13:33:58 -04002746 const LinkedUniform &uniform = *mUniforms[uniformIndex];
Jamie Madill8ff21ae2014-02-04 16:04:05 -05002747
2748 if (!IsSampler(uniform.type))
2749 {
2750 if (uniform.isReferencedByVertexShader())
2751 {
2752 vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
2753 }
2754 if (uniform.isReferencedByFragmentShader())
2755 {
2756 fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
2757 }
2758 }
2759 }
2760
2761 mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
2762 mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
2763}
2764
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002765}