blob: 7e3942b5cba67ab6299fba30307ec4c81f107ede [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//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
Nicolas Capense6050882013-07-08 10:43:10 -040024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
Jamie Madill5f562732014-02-14 16:41:24 -050026#include "libGLESv2/DynamicHLSL.h"
Jamie Madillc2141fb2013-08-30 13:21:08 -040027
daniel@transgaming.com88853c52012-12-20 20:56:40 +000028#undef near
29#undef far
30
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031namespace gl
32{
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000033
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000034namespace
35{
36
Jamie Madill8ff21ae2014-02-04 16:04:05 -050037unsigned int ParseAndStripArrayIndex(std::string* name)
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000038{
39 unsigned int subscript = GL_INVALID_INDEX;
40
41 // Strip any trailing array operator and retrieve the subscript
42 size_t open = name->find_last_of('[');
43 size_t close = name->find_last_of(']');
44 if (open != std::string::npos && close == name->length() - 1)
45 {
46 subscript = atoi(name->substr(open + 1).c_str());
47 name->erase(open);
48 }
49
50 return subscript;
51}
52
Jamie Madillc5a83002014-02-14 16:41:25 -050053void GetInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
54{
55 for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
56 {
57 const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
58 VertexFormat *defaultFormat = &inputLayout[attributeIndex];
59
60 if (shaderAttr.type != GL_NONE)
61 {
62 defaultFormat->mType = UniformComponentType(shaderAttr.type);
63 defaultFormat->mNormalized = false;
64 defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
65 defaultFormat->mComponents = UniformComponentCount(shaderAttr.type);
66 }
67 }
68}
69
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000070}
71
Jamie Madill63491ea2013-06-06 11:56:45 -040072VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +000073 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000074{
75}
76
Jamie Madillc5a83002014-02-14 16:41:25 -050077ProgramBinary::VertexExecutable::VertexExecutable(rx::Renderer *const renderer,
78 const VertexFormat inputLayout[],
79 rx::ShaderExecutable *shaderExecutable)
80 : mShaderExecutable(shaderExecutable)
81{
82 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
83 {
84 mInputs[attributeIndex] = inputLayout[attributeIndex];
85 }
86}
87
88bool ProgramBinary::VertexExecutable::matchesInputLayout(const VertexFormat attributes[]) const
89{
90 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
91 {
92 if (mInputs[attributeIndex] != attributes[attributeIndex])
93 {
94 return false;
95 }
96 }
97
98 return true;
99}
100
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000101unsigned int ProgramBinary::mCurrentSerial = 1;
102
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500103ProgramBinary::ProgramBinary(rx::Renderer *renderer)
104 : RefCountObject(0),
105 mRenderer(renderer),
Jamie Madill5f562732014-02-14 16:41:24 -0500106 mDynamicHLSL(NULL),
Jamie Madillc5a83002014-02-14 16:41:25 -0500107 mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500108 mPixelExecutable(NULL),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500109 mGeometryExecutable(NULL),
110 mUsedVertexSamplerRange(0),
111 mUsedPixelSamplerRange(0),
112 mUsesPointSize(false),
113 mShaderVersion(100),
114 mVertexUniformStorage(NULL),
115 mFragmentUniformStorage(NULL),
116 mValidated(false),
117 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000119 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
120 {
121 mSemanticIndex[index] = -1;
122 }
123
124 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
125 {
126 mSamplersPS[index].active = false;
127 }
128
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000129 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000130 {
131 mSamplersVS[index].active = false;
132 }
Jamie Madill5f562732014-02-14 16:41:24 -0500133
134 mDynamicHLSL = new DynamicHLSL(renderer);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135}
136
137ProgramBinary::~ProgramBinary()
138{
Jamie Madillc5a83002014-02-14 16:41:25 -0500139 while (!mVertexExecutables.empty())
140 {
141 delete mVertexExecutables.back();
142 mVertexExecutables.pop_back();
143 }
144
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500145 SafeDelete(mGeometryExecutable);
Jamie Madillc5a83002014-02-14 16:41:25 -0500146 SafeDelete(mPixelExecutable);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000147
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000148 while (!mUniforms.empty())
149 {
150 delete mUniforms.back();
151 mUniforms.pop_back();
152 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000153
154 while (!mUniformBlocks.empty())
155 {
156 delete mUniformBlocks.back();
157 mUniformBlocks.pop_back();
158 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500159
160 SafeDelete(mVertexUniformStorage);
161 SafeDelete(mFragmentUniformStorage);
Jamie Madill5f562732014-02-14 16:41:24 -0500162 SafeDelete(mDynamicHLSL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000163}
164
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000165unsigned int ProgramBinary::getSerial() const
166{
167 return mSerial;
168}
169
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000170int ProgramBinary::getShaderVersion() const
171{
172 return mShaderVersion;
173}
174
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000175unsigned int ProgramBinary::issueSerial()
176{
177 return mCurrentSerial++;
178}
179
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500180rx::ShaderExecutable *ProgramBinary::getPixelExecutable() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000181{
182 return mPixelExecutable;
183}
184
Jamie Madillc5a83002014-02-14 16:41:25 -0500185rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000186{
Jamie Madillc5a83002014-02-14 16:41:25 -0500187 for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
188 {
189 if (mVertexExecutables[executableIndex]->matchesInputLayout(inputLayout))
190 {
191 return mVertexExecutables[executableIndex]->shaderExecutable();
192 }
193 }
194
Jamie Madillc5ede1a2014-02-14 16:41:27 -0500195 // Generate new dynamic layout with attribute conversions
196 const std::string &layoutHLSL = mDynamicHLSL->generateInputLayoutHLSL(inputLayout, mShaderAttributes);
197
198 // Generate new shader source by replacing the attributes stub with the defined input layout
199 std::string vertexHLSL = mVertexHLSL;
200 size_t insertPos = vertexHLSL.find(DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING);
201 vertexHLSL.replace(insertPos, DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING.length(), layoutHLSL);
202
Jamie Madillc5a83002014-02-14 16:41:25 -0500203 // Generate new vertex executable
204 InfoLog tempInfoLog;
Jamie Madillc5ede1a2014-02-14 16:41:27 -0500205 rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, mVertexWorkarounds);
Jamie Madillc5a83002014-02-14 16:41:25 -0500206
207 if (!vertexExecutable)
208 {
209 std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
210 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
211 ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
212 }
213 else
214 {
215 mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, vertexExecutable));
216 }
217
218 return vertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000219}
220
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500221rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000222{
223 return mGeometryExecutable;
224}
225
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000226GLuint ProgramBinary::getAttributeLocation(const char *name)
227{
228 if (name)
229 {
230 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
231 {
232 if (mLinkedAttribute[index].name == std::string(name))
233 {
234 return index;
235 }
236 }
237 }
238
239 return -1;
240}
241
242int ProgramBinary::getSemanticIndex(int attributeIndex)
243{
244 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
245
246 return mSemanticIndex[attributeIndex];
247}
248
249// Returns one more than the highest sampler index used.
250GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
251{
252 switch (type)
253 {
254 case SAMPLER_PIXEL:
255 return mUsedPixelSamplerRange;
256 case SAMPLER_VERTEX:
257 return mUsedVertexSamplerRange;
258 default:
259 UNREACHABLE();
260 return 0;
261 }
262}
263
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000264bool ProgramBinary::usesPointSize() const
265{
266 return mUsesPointSize;
267}
268
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000269bool ProgramBinary::usesPointSpriteEmulation() const
270{
271 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
272}
273
274bool ProgramBinary::usesGeometryShader() const
275{
276 return usesPointSpriteEmulation();
277}
278
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000279// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
280// index (0-15 for the pixel shader and 0-3 for the vertex shader).
281GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
282{
283 GLint logicalTextureUnit = -1;
284
285 switch (type)
286 {
287 case SAMPLER_PIXEL:
288 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
289
290 if (mSamplersPS[samplerIndex].active)
291 {
292 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
293 }
294 break;
295 case SAMPLER_VERTEX:
296 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
297
298 if (mSamplersVS[samplerIndex].active)
299 {
300 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
301 }
302 break;
303 default: UNREACHABLE();
304 }
305
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000306 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000307 {
308 return logicalTextureUnit;
309 }
310
311 return -1;
312}
313
314// Returns the texture type for a given Direct3D 9 sampler type and
315// index (0-15 for the pixel shader and 0-3 for the vertex shader).
316TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
317{
318 switch (type)
319 {
320 case SAMPLER_PIXEL:
321 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
322 ASSERT(mSamplersPS[samplerIndex].active);
323 return mSamplersPS[samplerIndex].textureType;
324 case SAMPLER_VERTEX:
325 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
326 ASSERT(mSamplersVS[samplerIndex].active);
327 return mSamplersVS[samplerIndex].textureType;
328 default: UNREACHABLE();
329 }
330
331 return TEXTURE_2D;
332}
333
334GLint ProgramBinary::getUniformLocation(std::string name)
335{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500336 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000337
338 unsigned int numUniforms = mUniformIndex.size();
339 for (unsigned int location = 0; location < numUniforms; location++)
340 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000341 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000342 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000343 const int index = mUniformIndex[location].index;
344 const bool isArray = mUniforms[index]->isArray();
345
346 if ((isArray && mUniformIndex[location].element == subscript) ||
347 (subscript == GL_INVALID_INDEX))
348 {
349 return location;
350 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000351 }
352 }
353
354 return -1;
355}
356
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000357GLuint ProgramBinary::getUniformIndex(std::string name)
358{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500359 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000360
361 // The app is not allowed to specify array indices other than 0 for arrays of basic types
362 if (subscript != 0 && subscript != GL_INVALID_INDEX)
363 {
364 return GL_INVALID_INDEX;
365 }
366
367 unsigned int numUniforms = mUniforms.size();
368 for (unsigned int index = 0; index < numUniforms; index++)
369 {
370 if (mUniforms[index]->name == name)
371 {
372 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
373 {
374 return index;
375 }
376 }
377 }
378
379 return GL_INVALID_INDEX;
380}
381
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000382GLuint ProgramBinary::getUniformBlockIndex(std::string name)
383{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500384 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000385
386 unsigned int numUniformBlocks = mUniformBlocks.size();
387 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
388 {
389 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
390 if (uniformBlock.name == name)
391 {
392 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
393 if (subscript == uniformBlock.elementIndex || arrayElementZero)
394 {
395 return blockIndex;
396 }
397 }
398 }
399
400 return GL_INVALID_INDEX;
401}
402
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000403UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
404{
405 ASSERT(blockIndex < mUniformBlocks.size());
406 return mUniformBlocks[blockIndex];
407}
408
Jamie Madilld1e78c92013-06-20 11:55:50 -0400409GLint ProgramBinary::getFragDataLocation(const char *name) const
410{
411 std::string baseName(name);
412 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500413 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400414
415 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
416 {
417 const VariableLocation &outputVariable = locationIt->second;
418
419 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
420 {
421 return static_cast<GLint>(locationIt->first);
422 }
423 }
424
425 return -1;
426}
427
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000428template <typename T>
429bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000430{
431 if (location < 0 || location >= (int)mUniformIndex.size())
432 {
433 return false;
434 }
435
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000436 const int components = UniformComponentCount(targetUniformType);
437 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
438
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
440 targetUniform->dirty = true;
441
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000442 int elementCount = targetUniform->elementCount();
443
444 if (elementCount == 1 && count > 1)
445 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
446
447 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
448
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000449 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000450 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000451 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452
453 for (int i = 0; i < count; i++)
454 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000455 for (int c = 0; c < components; c++)
456 {
457 target[c] = v[c];
458 }
459 for (int c = components; c < 4; c++)
460 {
461 target[c] = 0;
462 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000463 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000464 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000465 }
466 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000467 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000468 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000469 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000470
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000471 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000472 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000473 for (int c = 0; c < components; c++)
474 {
475 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
476 }
477 for (int c = components; c < 4; c++)
478 {
479 boolParams[c] = GL_FALSE;
480 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000481 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000482 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000483 }
484 }
485 else
486 {
487 return false;
488 }
489
490 return true;
491}
492
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000493bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
494{
495 return setUniform(location, count, v, GL_FLOAT);
496}
497
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000498bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
499{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000500 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501}
502
503bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
504{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000505 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000506}
507
508bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
509{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000510 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000511}
512
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000513template<typename T>
514void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000515{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000516 int copyWidth = std::min(targetHeight, srcWidth);
517 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000518
519 for (int x = 0; x < copyWidth; x++)
520 {
521 for (int y = 0; y < copyHeight; y++)
522 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000523 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524 }
525 }
526 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000527 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000528 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000529 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000530 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000531 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000532 }
533 }
534 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000535 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000536 {
537 for (int x = 0; x < targetWidth; x++)
538 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000539 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000540 }
541 }
542}
543
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000544template<typename T>
545void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
546{
547 int copyWidth = std::min(targetWidth, srcWidth);
548 int copyHeight = std::min(targetHeight, srcHeight);
549
550 for (int y = 0; y < copyHeight; y++)
551 {
552 for (int x = 0; x < copyWidth; x++)
553 {
554 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
555 }
556 }
557 // clear unfilled right side
558 for (int y = 0; y < copyHeight; y++)
559 {
560 for (int x = copyWidth; x < targetWidth; x++)
561 {
562 target[y * targetWidth + x] = static_cast<T>(0);
563 }
564 }
565 // clear unfilled bottom.
566 for (int y = copyHeight; y < targetHeight; y++)
567 {
568 for (int x = 0; x < targetWidth; x++)
569 {
570 target[y * targetWidth + x] = static_cast<T>(0);
571 }
572 }
573}
574
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000575template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000576bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000577{
578 if (location < 0 || location >= (int)mUniformIndex.size())
579 {
580 return false;
581 }
582
583 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
584 targetUniform->dirty = true;
585
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000586 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000587 {
588 return false;
589 }
590
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000591 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000592
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000593 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000594 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
595
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000596 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000597 const unsigned int targetMatrixStride = (4 * rows);
598 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000599
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600 for (int i = 0; i < count; i++)
601 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000602 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
603 if (transpose == GL_FALSE)
604 {
605 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
606 }
607 else
608 {
609 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
610 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000611 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000612 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613 }
614
615 return true;
616}
617
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000618bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000619{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000620 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000621}
622
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000623bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000625 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000626}
627
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000628bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000630 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631}
632
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000633bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000634{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000635 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000636}
637
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000638bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000639{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000640 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000641}
642
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000643bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000644{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000645 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000646}
647
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000648bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000649{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000650 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000651}
652
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000653bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000654{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000655 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000656}
657
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000658bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000659{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000660 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000661}
662
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000663bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
664{
665 if (location < 0 || location >= (int)mUniformIndex.size())
666 {
667 return false;
668 }
669
670 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
671 targetUniform->dirty = true;
672
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000673 int elementCount = targetUniform->elementCount();
674
675 if (elementCount == 1 && count > 1)
676 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
677
678 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
679
Nicolas Capense6050882013-07-08 10:43:10 -0400680 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000681 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000682 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000683
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000684 for (int i = 0; i < count; i++)
685 {
686 target[0] = v[0];
687 target[1] = 0;
688 target[2] = 0;
689 target[3] = 0;
690 target += 4;
691 v += 1;
692 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693 }
694 else if (targetUniform->type == GL_BOOL)
695 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000696 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000698 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000699 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000700 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
701 boolParams[1] = GL_FALSE;
702 boolParams[2] = GL_FALSE;
703 boolParams[3] = GL_FALSE;
704 boolParams += 4;
705 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000706 }
707 }
708 else
709 {
710 return false;
711 }
712
713 return true;
714}
715
716bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
717{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000718 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000719}
720
721bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
722{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000723 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000724}
725
726bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
727{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000728 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000729}
730
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000731bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
732{
733 return setUniform(location, count, v, GL_UNSIGNED_INT);
734}
735
736bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
737{
738 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
739}
740
741bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
742{
743 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
744}
745
746bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
747{
748 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
749}
750
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000751template <typename T>
752bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000753{
754 if (location < 0 || location >= (int)mUniformIndex.size())
755 {
756 return false;
757 }
758
759 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
760
761 // sized queries -- ensure the provided buffer is large enough
762 if (bufSize)
763 {
764 int requiredBytes = UniformExternalSize(targetUniform->type);
765 if (*bufSize < requiredBytes)
766 {
767 return false;
768 }
769 }
770
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000771 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000772 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000773 const int rows = VariableRowCount(targetUniform->type);
774 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400775 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 +0000776 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000777 else if (uniformType == UniformComponentType(targetUniform->type))
778 {
779 unsigned int size = UniformComponentCount(targetUniform->type);
780 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
781 size * sizeof(T));
782 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000783 else
784 {
785 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000786 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000787 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000788 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000790 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000791
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000792 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000793 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000794 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000795 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000796 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000797 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000798
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000799 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000800 {
801 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
802
803 for (unsigned int i = 0; i < size; i++)
804 {
805 params[i] = static_cast<T>(floatParams[i]);
806 }
807 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000808 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000809
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000810 case GL_INT:
811 {
812 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
813
814 for (unsigned int i = 0; i < size; i++)
815 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000816 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000817 }
818 }
819 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000820
821 case GL_UNSIGNED_INT:
822 {
823 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000824
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000825 for (unsigned int i = 0; i < size; i++)
826 {
827 params[i] = static_cast<T>(uintParams[i]);
828 }
829 }
830 break;
831
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000832 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000833 }
834 }
835
836 return true;
837}
838
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000839bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
840{
841 return getUniformv(location, bufSize, params, GL_FLOAT);
842}
843
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000844bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
845{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000846 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000847}
848
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000849bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
850{
851 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
852}
853
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000854void ProgramBinary::dirtyAllUniforms()
855{
856 unsigned int numUniforms = mUniforms.size();
857 for (unsigned int index = 0; index < numUniforms; index++)
858 {
859 mUniforms[index]->dirty = true;
860 }
861}
862
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000863// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000864void ProgramBinary::applyUniforms()
865{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000866 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500867 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000868 {
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500869 Uniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000870
871 if (targetUniform->dirty)
872 {
Nicolas Capense6050882013-07-08 10:43:10 -0400873 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000874 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000875 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000876 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000877
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000878 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000879 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000880 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000881
882 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000883 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000884 unsigned int samplerIndex = firstIndex + i;
885
886 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000887 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000888 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000889 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000890 }
891 }
892 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000893
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000894 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000895 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000896 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000897
898 for (int i = 0; i < count; i++)
899 {
900 unsigned int samplerIndex = firstIndex + i;
901
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000902 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000903 {
904 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000905 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000906 }
907 }
908 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000909 }
910 }
911 }
912
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500913 mRenderer->applyUniforms(*this);
914
915 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
916 {
917 mUniforms[uniformIndex]->dirty = false;
918 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000919}
920
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000921bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
922{
923 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
924 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
925
926 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
927 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
928
929 ASSERT(boundBuffers.size() == mUniformBlocks.size());
930
931 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
932 {
933 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
934 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
935
936 ASSERT(uniformBlock && uniformBuffer);
937
938 if (uniformBuffer->size() < uniformBlock->dataSize)
939 {
940 // undefined behaviour
941 return false;
942 }
943
944 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
945
946 if (uniformBlock->isReferencedByVertexShader())
947 {
948 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
949 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
950 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
951 vertexUniformBuffers[registerIndex] = uniformBuffer;
952 }
953
954 if (uniformBlock->isReferencedByFragmentShader())
955 {
956 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
957 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
958 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
959 fragmentUniformBuffers[registerIndex] = uniformBuffer;
960 }
961 }
962
963 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
964}
965
Jamie Madill5f562732014-02-14 16:41:24 -0500966bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000967{
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000968 vertexShader->resetVaryingsRegisterAssignment();
969
Jamie Madill5f562732014-02-14 16:41:24 -0500970 std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
971 std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
972
973 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000974 {
Jamie Madill5f562732014-02-14 16:41:24 -0500975 sh::Varying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000976 bool matched = false;
977
Jamie Madill5f562732014-02-14 16:41:24 -0500978 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000979 {
Jamie Madill5f562732014-02-14 16:41:24 -0500980 sh::Varying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000981 if (output->name == input->name)
982 {
Jamie Madill28167c62013-08-30 13:21:10 -0400983 if (!linkValidateVariables(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000984 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000985 return false;
986 }
987
Jamie Madill139b9092013-08-30 13:21:06 -0400988 output->registerIndex = input->registerIndex;
989 output->elementIndex = input->elementIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000990
991 matched = true;
992 break;
993 }
994 }
995
996 if (!matched)
997 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000998 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000999 return false;
1000 }
1001 }
1002
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001003 return true;
1004}
1005
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001006bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1007{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001008 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001009
1010 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001011 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001012 if (format != GL_PROGRAM_BINARY_ANGLE)
1013 {
1014 infoLog.append("Invalid program binary format.");
1015 return false;
1016 }
1017
Jamie Madill049108d2013-11-19 10:41:49 -05001018 int majorVersion = 0;
1019 int minorVersion = 0;
1020 stream.read(&majorVersion);
1021 stream.read(&minorVersion);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001022 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -05001023 {
1024 infoLog.append("Invalid program binary version.");
1025 return false;
1026 }
1027
Jamie Madill0aa84f62014-02-13 13:17:23 -05001028 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
1029 stream.read(commitString, ANGLE_COMMIT_HASH_SIZE);
1030 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001031 {
1032 infoLog.append("Invalid program binary version.");
1033 return false;
1034 }
1035
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001036 int compileFlags = 0;
1037 stream.read(&compileFlags);
1038 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1039 {
1040 infoLog.append("Mismatched compilation flags.");
1041 return false;
1042 }
1043
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001044 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1045 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001046 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001047 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001048 stream.read(&name);
1049 mLinkedAttribute[i].name = name;
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001050 stream.read(&mShaderAttributes[i].type);
1051 stream.read(&mShaderAttributes[i].name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001052 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001053 }
1054
Al Patrick3f2daa82013-08-07 12:58:57 -07001055 initAttributesByLayout();
1056
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001057 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1058 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001059 stream.read(&mSamplersPS[i].active);
1060 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001061
1062 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001063 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001064 mSamplersPS[i].textureType = (TextureType) textureType;
1065 }
1066
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001067 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001068 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001069 stream.read(&mSamplersVS[i].active);
1070 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001071
1072 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001073 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001074 mSamplersVS[i].textureType = (TextureType) textureType;
1075 }
1076
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001077 stream.read(&mUsedVertexSamplerRange);
1078 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001079 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001080 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001081
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001082 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001083 stream.read(&size);
1084 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001085 {
1086 infoLog.append("Invalid program binary.");
1087 return false;
1088 }
1089
1090 mUniforms.resize(size);
1091 for (unsigned int i = 0; i < size; ++i)
1092 {
1093 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001094 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001095 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001096 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001097 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001098
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001099 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001100 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001101 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001102 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001103 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001104
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001105 int offset;
1106 int arrayStride;
1107 int matrixStride;
1108 bool isRowMajorMatrix;
1109
1110 stream.read(&offset);
1111 stream.read(&arrayStride);
1112 stream.read(&matrixStride);
1113 stream.read(&isRowMajorMatrix);
1114
1115 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1116
1117 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001118
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001119 stream.read(&mUniforms[i]->psRegisterIndex);
1120 stream.read(&mUniforms[i]->vsRegisterIndex);
1121 stream.read(&mUniforms[i]->registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001122 stream.read(&mUniforms[i]->registerElement);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001123 }
1124
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001125 stream.read(&size);
1126 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001127 {
1128 infoLog.append("Invalid program binary.");
1129 return false;
1130 }
1131
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001132 mUniformBlocks.resize(size);
1133 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1134 {
1135 std::string name;
1136 unsigned int elementIndex;
1137 unsigned int dataSize;
1138
1139 stream.read(&name);
1140 stream.read(&elementIndex);
1141 stream.read(&dataSize);
1142
1143 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1144
1145 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1146 stream.read(&uniformBlock.psRegisterIndex);
1147 stream.read(&uniformBlock.vsRegisterIndex);
1148
1149 size_t numMembers;
1150 stream.read(&numMembers);
1151 uniformBlock.memberUniformIndexes.resize(numMembers);
1152 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1153 {
1154 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1155 }
1156 }
1157
1158 stream.read(&size);
1159 if (stream.error())
1160 {
1161 infoLog.append("Invalid program binary.");
1162 return false;
1163 }
1164
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001165 mUniformIndex.resize(size);
1166 for (unsigned int i = 0; i < size; ++i)
1167 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001168 stream.read(&mUniformIndex[i].name);
1169 stream.read(&mUniformIndex[i].element);
1170 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001171 }
1172
Jamie Madillc5a83002014-02-14 16:41:25 -05001173 stream.read(&mVertexHLSL);
1174 stream.read(&mVertexWorkarounds);
1175
1176 unsigned int vertexShaderCount;
1177 stream.read(&vertexShaderCount);
1178
1179 for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
1180 {
1181 VertexFormat vertexInputs[gl::MAX_VERTEX_ATTRIBS];
1182
1183 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1184 {
1185 VertexFormat *vertexInput = &vertexInputs[inputIndex];
1186 stream.read(&vertexInput->mType);
1187 stream.read(&vertexInput->mNormalized);
1188 stream.read(&vertexInput->mComponents);
1189 stream.read(&vertexInput->mPureInteger);
1190 }
1191
1192 unsigned int vertexShaderSize;
1193 stream.read(&vertexShaderSize);
1194
1195 const char *vertexShaderFunction = (const char*) binary + stream.offset();
1196
1197 rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
1198 vertexShaderSize, rx::SHADER_VERTEX);
1199 if (!shaderExecutable)
1200 {
1201 infoLog.append("Could not create vertex shader.");
1202 return false;
1203 }
1204
1205 mVertexExecutables.push_back(new VertexExecutable(mRenderer, vertexInputs, shaderExecutable));
1206
1207 stream.skip(vertexShaderSize);
1208 }
1209
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001210 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001211 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001212
Jamie Madillc5a83002014-02-14 16:41:25 -05001213 const char *pixelShaderFunction = (const char*) binary + stream.offset();
1214 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
1215 pixelShaderSize, rx::SHADER_PIXEL);
1216 if (!mPixelExecutable)
1217 {
1218 infoLog.append("Could not create pixel shader.");
1219 return false;
1220 }
1221 stream.skip(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001222
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001223 unsigned int geometryShaderSize;
1224 stream.read(&geometryShaderSize);
1225
Jamie Madillc5a83002014-02-14 16:41:25 -05001226 if (geometryShaderSize > 0)
1227 {
1228 const char *geometryShaderFunction = (const char*) binary + stream.offset();
1229 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1230 geometryShaderSize, rx::SHADER_GEOMETRY);
1231 if (!mGeometryExecutable)
1232 {
1233 infoLog.append("Could not create geometry shader.");
1234 SafeDelete(mPixelExecutable);
1235 return false;
1236 }
1237 stream.skip(geometryShaderSize);
1238 }
1239
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001240 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001241
daniel@transgaming.com36038542012-11-28 20:59:26 +00001242 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001243 ptr += sizeof(GUID);
1244
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001245 GUID identifier = mRenderer->getAdapterIdentifier();
1246 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001247 {
1248 infoLog.append("Invalid program binary.");
1249 return false;
1250 }
1251
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001252 initializeUniformStorage();
1253
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001254 return true;
1255}
1256
1257bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1258{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001259 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001260
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001261 stream.write(GL_PROGRAM_BINARY_ANGLE);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001262 stream.write(ANGLE_MAJOR_VERSION);
1263 stream.write(ANGLE_MINOR_VERSION);
1264 stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001265 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001266
1267 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1268 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001269 stream.write(mLinkedAttribute[i].type);
1270 stream.write(mLinkedAttribute[i].name);
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001271 stream.write(mShaderAttributes[i].type);
1272 stream.write(mShaderAttributes[i].name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001273 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001274 }
1275
1276 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1277 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001278 stream.write(mSamplersPS[i].active);
1279 stream.write(mSamplersPS[i].logicalTextureUnit);
1280 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001281 }
1282
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001283 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001284 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001285 stream.write(mSamplersVS[i].active);
1286 stream.write(mSamplersVS[i].logicalTextureUnit);
1287 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001288 }
1289
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001290 stream.write(mUsedVertexSamplerRange);
1291 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001292 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001293 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001294
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001295 stream.write(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001296 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001297 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001298 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001299
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001300 stream.write(uniform.type);
1301 stream.write(uniform.precision);
1302 stream.write(uniform.name);
1303 stream.write(uniform.arraySize);
1304 stream.write(uniform.blockIndex);
1305
1306 stream.write(uniform.blockInfo.offset);
1307 stream.write(uniform.blockInfo.arrayStride);
1308 stream.write(uniform.blockInfo.matrixStride);
1309 stream.write(uniform.blockInfo.isRowMajorMatrix);
1310
1311 stream.write(uniform.psRegisterIndex);
1312 stream.write(uniform.vsRegisterIndex);
1313 stream.write(uniform.registerCount);
Jamie Madill5b085dc2013-08-30 13:21:11 -04001314 stream.write(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001315 }
1316
1317 stream.write(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001318 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001319 {
1320 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1321
1322 stream.write(uniformBlock.name);
1323 stream.write(uniformBlock.elementIndex);
1324 stream.write(uniformBlock.dataSize);
1325
1326 stream.write(uniformBlock.memberUniformIndexes.size());
1327 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1328 {
1329 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1330 }
1331
1332 stream.write(uniformBlock.psRegisterIndex);
1333 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001334 }
1335
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001336 stream.write(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001337 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001338 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001339 stream.write(mUniformIndex[i].name);
1340 stream.write(mUniformIndex[i].element);
1341 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001342 }
1343
Jamie Madillc5a83002014-02-14 16:41:25 -05001344 stream.write(mVertexHLSL);
1345 stream.write(mVertexWorkarounds);
1346
1347 UINT vertexShadersTotalSize = 0;
1348
1349 stream.write(mVertexExecutables.size());
1350 for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
1351 {
1352 VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
1353
1354 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1355 {
1356 const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
1357 stream.write(vertexInput.mType);
1358 stream.write(vertexInput.mNormalized);
1359 stream.write(vertexInput.mComponents);
1360 stream.write(vertexInput.mPureInteger);
1361 }
1362
1363 UINT vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
1364 stream.write(vertexShaderSize);
1365
1366 unsigned char *vertexBlob = static_cast<unsigned char *>(vertexExecutable->shaderExecutable()->getFunction());
1367 stream.write(vertexBlob, vertexShaderSize);
1368 }
1369
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001370 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001371 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001372
Jamie Madillc5a83002014-02-14 16:41:25 -05001373 unsigned char *pixelBlob = static_cast<unsigned char *>(mPixelExecutable->getFunction());
1374 stream.write(pixelBlob, pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001375
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001376 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1377 stream.write(geometryShaderSize);
1378
Jamie Madillc5a83002014-02-14 16:41:25 -05001379 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1380 {
1381 unsigned char *geometryBlob = static_cast<unsigned char *>(mGeometryExecutable->getFunction());
1382 stream.write(geometryBlob, geometryShaderSize);
1383 }
1384
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001385 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001386
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001387 GLsizei streamLength = stream.length();
1388 const void *streamData = stream.data();
1389
Jamie Madillc5a83002014-02-14 16:41:25 -05001390 GLsizei totalLength = streamLength + sizeof(GUID);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001391 if (totalLength > bufSize)
1392 {
1393 if (length)
1394 {
1395 *length = 0;
1396 }
1397
1398 return false;
1399 }
1400
1401 if (binary)
1402 {
1403 char *ptr = (char*) binary;
1404
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001405 memcpy(ptr, streamData, streamLength);
1406 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001407
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001408 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001409 ptr += sizeof(GUID);
1410
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001411 ASSERT(ptr - totalLength == binary);
1412 }
1413
1414 if (length)
1415 {
1416 *length = totalLength;
1417 }
1418
1419 return true;
1420}
1421
1422GLint ProgramBinary::getLength()
1423{
1424 GLint length;
1425 if (save(NULL, INT_MAX, &length))
1426 {
1427 return length;
1428 }
1429 else
1430 {
1431 return 0;
1432 }
1433}
1434
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001435bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001436{
1437 if (!fragmentShader || !fragmentShader->isCompiled())
1438 {
1439 return false;
1440 }
1441
1442 if (!vertexShader || !vertexShader->isCompiled())
1443 {
1444 return false;
1445 }
1446
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001447 mShaderVersion = vertexShader->getShaderVersion();
1448
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001449 std::string pixelHLSL = fragmentShader->getHLSL();
Jamie Madillc5a83002014-02-14 16:41:25 -05001450 mVertexHLSL = vertexShader->getHLSL();
1451 mVertexWorkarounds = vertexShader->getD3DWorkarounds();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001452
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001453 // Map the varyings to the register file
Jamie Madilla6da33a2013-08-30 13:21:07 -04001454 const sh::ShaderVariable *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
Jamie Madill5f562732014-02-14 16:41:24 -05001455 int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader);
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001456
1457 if (registers < 0)
1458 {
1459 return false;
1460 }
1461
Jamie Madill5f562732014-02-14 16:41:24 -05001462 if (!linkVaryings(infoLog, fragmentShader, vertexShader))
1463 {
1464 return false;
1465 }
1466
1467 mUsesPointSize = vertexShader->usesPointSize();
Jamie Madillc5a83002014-02-14 16:41:25 -05001468 if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, pixelHLSL, mVertexHLSL,
1469 fragmentShader, vertexShader, &mOutputVariables))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001470 {
1471 return false;
1472 }
1473
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001474 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001475
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001476 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1477 {
1478 success = false;
1479 }
1480
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001481 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001482 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001483 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001484 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001485
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001486 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Jamie Madill5f562732014-02-14 16:41:24 -05001487 if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001488 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001489 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1490 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1491 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001492 }
1493
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001494 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1495 {
1496 success = false;
1497 }
1498
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001499 if (success)
1500 {
Jamie Madillc5a83002014-02-14 16:41:25 -05001501 VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
1502 GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout);
1503
1504 rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
1505 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, fragmentShader->getD3DWorkarounds());
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001506
1507 if (usesGeometryShader())
1508 {
Jamie Madill5f562732014-02-14 16:41:24 -05001509 std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
Jamie Madill3c9eeb92013-11-04 11:09:26 -05001510 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001511 }
1512
Jamie Madillc5a83002014-02-14 16:41:25 -05001513 if (!defaultVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001514 {
1515 infoLog.append("Failed to create D3D shaders.");
1516 success = false;
1517
Jamie Madillc5a83002014-02-14 16:41:25 -05001518 while (!mVertexExecutables.empty())
1519 {
1520 delete mVertexExecutables.back();
1521 mVertexExecutables.pop_back();
1522 }
1523
1524 SafeDelete(mGeometryExecutable);
1525 SafeDelete(mPixelExecutable);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001526 }
1527 }
1528
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001529 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001530}
1531
1532// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001533bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001534{
1535 unsigned int usedLocations = 0;
Jamie Madill5f562732014-02-14 16:41:24 -05001536 const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001537
1538 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001539 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001540 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001541 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001542 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001543
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001544 mShaderAttributes[attributeIndex] = attribute;
1545
Jamie Madilleba4eff2013-06-20 11:55:51 -04001546 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001547 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001548 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001549
1550 if (rows + location > MAX_VERTEX_ATTRIBS)
1551 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001552 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 +00001553
1554 return false;
1555 }
1556
Jamie Madilleba4eff2013-06-20 11:55:51 -04001557 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001558 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001559 const int rowLocation = location + row;
1560 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
1561
1562 // In GLSL 3.00, attribute aliasing produces a link error
1563 // In GLSL 1.00, attribute aliasing is allowed
1564 if (mShaderVersion >= 300)
1565 {
1566 if (!linkedAttribute.name.empty())
1567 {
1568 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1569 return false;
1570 }
1571 }
1572
1573 linkedAttribute = attribute;
1574 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001575 }
1576 }
1577 }
1578
1579 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04001580 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001581 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001582 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001583 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001584
Jamie Madilleba4eff2013-06-20 11:55:51 -04001585 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001586 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001587 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001588 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1589
1590 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1591 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001592 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001593
1594 return false; // Fail to link
1595 }
1596
Jamie Madilldefb6742013-06-20 11:55:51 -04001597 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001598 }
1599 }
1600
1601 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1602 {
1603 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04001604 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001605
1606 for (int r = 0; r < rows; r++)
1607 {
1608 mSemanticIndex[attributeIndex++] = index++;
1609 }
1610 }
1611
Al Patrick3f2daa82013-08-07 12:58:57 -07001612 initAttributesByLayout();
1613
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001614 return true;
1615}
1616
Jamie Madill28167c62013-08-30 13:21:10 -04001617bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001618{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001619 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001620 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001621 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001622 return false;
1623 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001624 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001625 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001626 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001627 return false;
1628 }
Jamie Madill28167c62013-08-30 13:21:10 -04001629 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001630 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001631 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001632 return false;
1633 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001634
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001635 return true;
1636}
1637
1638template <class ShaderVarType>
1639bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
1640{
1641 if (vertexVar.fields.size() != fragmentVar.fields.size())
1642 {
1643 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
1644 return false;
1645 }
1646 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001647 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1648 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001649 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
1650 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001651
1652 if (vertexMember.name != fragmentMember.name)
1653 {
Jamie Madill28167c62013-08-30 13:21:10 -04001654 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
1655 memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001656 return false;
1657 }
1658
Jamie Madill28167c62013-08-30 13:21:10 -04001659 const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001660 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001661 {
1662 return false;
1663 }
1664 }
1665
1666 return true;
1667}
1668
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001669bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1670{
Jamie Madill28167c62013-08-30 13:21:10 -04001671 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001672 {
1673 return false;
1674 }
1675
1676 if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
1677 {
1678 return false;
1679 }
1680
1681 return true;
1682}
1683
Jamie Madill28167c62013-08-30 13:21:10 -04001684bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
1685{
1686 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1687 {
1688 return false;
1689 }
1690
1691 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1692 {
1693 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1694 return false;
1695 }
1696
1697 if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
1698 {
1699 return false;
1700 }
1701
1702 return true;
1703}
1704
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001705bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
1706{
Jamie Madill28167c62013-08-30 13:21:10 -04001707 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001708 {
1709 return false;
1710 }
1711
1712 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
1713 {
1714 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1715 return false;
1716 }
1717
1718 if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
1719 {
1720 return false;
1721 }
1722
1723 return true;
1724}
1725
1726bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001727{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001728 // Check that uniforms defined in the vertex and fragment shaders are identical
1729 typedef std::map<std::string, const sh::Uniform*> UniformMap;
1730 UniformMap linkedUniforms;
1731
1732 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1733 {
1734 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
1735 linkedUniforms[vertexUniform.name] = &vertexUniform;
1736 }
1737
1738 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1739 {
1740 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
1741 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1742 if (entry != linkedUniforms.end())
1743 {
1744 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001745 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001746 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001747 {
1748 return false;
1749 }
1750 }
1751 }
1752
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001753 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001754 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001755 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001756 {
1757 return false;
1758 }
1759 }
1760
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001761 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001762 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001763 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001764 {
1765 return false;
1766 }
1767 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001768
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001769 initializeUniformStorage();
1770
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001771 return true;
1772}
1773
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001774int totalRegisterCount(const sh::Uniform &uniform)
1775{
1776 int registerCount = 0;
1777
1778 if (!uniform.fields.empty())
1779 {
1780 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
1781 {
1782 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
1783 }
1784 }
1785 else
1786 {
1787 registerCount = 1;
1788 }
1789
1790 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
1791}
1792
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001793TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
1794{
1795 switch(samplerType)
1796 {
1797 case GL_SAMPLER_2D:
1798 case GL_INT_SAMPLER_2D:
1799 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001800 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001801 return TEXTURE_2D;
1802 case GL_SAMPLER_3D:
1803 case GL_INT_SAMPLER_3D:
1804 case GL_UNSIGNED_INT_SAMPLER_3D:
1805 return TEXTURE_3D;
1806 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001807 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001808 return TEXTURE_CUBE;
1809 case GL_INT_SAMPLER_CUBE:
1810 case GL_UNSIGNED_INT_SAMPLER_CUBE:
1811 //UNIMPLEMENTED();
1812 infoLog.append("Integer cube texture sampling is currently not supported by ANGLE and returns a black color.");
1813 return TEXTURE_CUBE;
1814 case GL_SAMPLER_2D_ARRAY:
1815 case GL_INT_SAMPLER_2D_ARRAY:
1816 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04001817 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001818 return TEXTURE_2D_ARRAY;
1819 default: UNREACHABLE();
1820 }
1821
1822 return TEXTURE_2D;
1823}
1824
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001825bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001826{
Jamie Madillfcef3362013-11-13 19:37:19 -05001827 if (constant.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001828 {
1829 if (constant.arraySize > 0)
1830 {
1831 unsigned int elementRegisterIndex = constant.registerIndex;
1832
1833 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
1834 {
1835 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1836 {
1837 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill5f562732014-02-14 16:41:24 -05001838 const std::string &uniformName = constant.name + ArrayString(elementIndex) + "." + field.name;
Jamie Madillfcef3362013-11-13 19:37:19 -05001839 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
1840 elementRegisterIndex, field.elementIndex);
1841
1842 fieldUniform.fields = field.fields;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001843 if (!defineUniform(shader, fieldUniform, infoLog))
1844 {
1845 return false;
1846 }
1847 elementRegisterIndex += totalRegisterCount(field);
1848 }
1849 }
1850 }
1851 else
1852 {
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001853 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
1854 {
1855 const sh::Uniform &field = constant.fields[fieldIndex];
1856 const std::string &uniformName = constant.name + "." + field.name;
1857
Jamie Madill56093782013-08-30 13:21:11 -04001858 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
1859 field.registerIndex, field.elementIndex);
1860
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001861 fieldUniform.fields = field.fields;
1862
1863 if (!defineUniform(shader, fieldUniform, infoLog))
1864 {
1865 return false;
1866 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001867 }
1868 }
1869
1870 return true;
1871 }
1872
Nicolas Capense6050882013-07-08 10:43:10 -04001873 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001874 {
1875 unsigned int samplerIndex = constant.registerIndex;
1876
1877 do
1878 {
1879 if (shader == GL_VERTEX_SHADER)
1880 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001881 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001882 {
1883 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001884 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001885 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
1886 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
1887 }
1888 else
1889 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001890 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001891 return false;
1892 }
1893 }
1894 else if (shader == GL_FRAGMENT_SHADER)
1895 {
1896 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1897 {
1898 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04001899 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001900 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
1901 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
1902 }
1903 else
1904 {
1905 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
1906 return false;
1907 }
1908 }
1909 else UNREACHABLE();
1910
1911 samplerIndex++;
1912 }
1913 while (samplerIndex < constant.registerIndex + constant.arraySize);
1914 }
1915
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001916 Uniform *uniform = NULL;
1917 GLint location = getUniformLocation(constant.name);
1918
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001919 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001920 {
1921 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001922 }
1923 else
1924 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001925 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
Jamie Madill56093782013-08-30 13:21:11 -04001926 uniform->registerElement = constant.elementIndex;
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001927 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001928
1929 if (!uniform)
1930 {
1931 return false;
1932 }
1933
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001934 if (shader == GL_FRAGMENT_SHADER)
1935 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001936 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001937 }
1938 else if (shader == GL_VERTEX_SHADER)
1939 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001940 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001941 }
1942 else UNREACHABLE();
1943
1944 if (location >= 0)
1945 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00001946 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001947 }
1948
1949 mUniforms.push_back(uniform);
1950 unsigned int uniformIndex = mUniforms.size() - 1;
1951
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001952 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001953 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001954 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001955 }
1956
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001957 if (shader == GL_VERTEX_SHADER)
1958 {
1959 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
1960 {
1961 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
1962 return false;
1963 }
1964 }
1965 else if (shader == GL_FRAGMENT_SHADER)
1966 {
1967 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
1968 {
1969 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
1970 return false;
1971 }
1972 }
1973 else UNREACHABLE();
1974
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001975 return true;
1976}
1977
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001978bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
1979{
1980 const char* blockName = vertexInterfaceBlock.name.c_str();
1981
1982 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001983 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001984 {
1985 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
1986 return false;
1987 }
1988
1989 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1990 {
1991 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
1992 return false;
1993 }
1994
Jamie Madill9060a4e2013-08-12 16:22:57 -07001995 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1996 {
1997 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
1998 return false;
1999 }
2000
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002001 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002002 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2003 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002004 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2005 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002006
2007 if (vertexMember.name != fragmentMember.name)
2008 {
Jamie Madill28167c62013-08-30 13:21:10 -04002009 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 +00002010 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2011 return false;
2012 }
2013
Jamie Madill28167c62013-08-30 13:21:10 -04002014 std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002015 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002016 {
2017 return false;
2018 }
2019 }
2020
2021 return true;
2022}
2023
2024bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2025{
2026 // Check that interface blocks defined in the vertex and fragment shaders are identical
2027 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2028 UniformBlockMap linkedUniformBlocks;
2029
2030 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2031 {
2032 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2033 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2034 }
2035
2036 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2037 {
2038 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2039 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2040 if (entry != linkedUniformBlocks.end())
2041 {
2042 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2043 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2044 {
2045 return false;
2046 }
2047 }
2048 }
2049
2050 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2051 {
2052 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2053 {
2054 return false;
2055 }
2056 }
2057
2058 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2059 {
2060 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2061 {
2062 return false;
2063 }
2064 }
2065
2066 return true;
2067}
2068
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002069void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002070{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002071 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002072 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002073 const sh::InterfaceBlockField &field = fields[uniformIndex];
2074 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002075
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002076 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002077 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002078 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002079 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002080 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002081 {
Jamie Madill5f562732014-02-14 16:41:24 -05002082 const std::string uniformElementName = fieldName + ArrayString(arrayElement);
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002083 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002084 }
2085 }
2086 else
2087 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002088 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002089 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002090 }
2091 else
2092 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002093 Uniform *newUniform = new Uniform(field.type, field.precision, fieldName, field.arraySize,
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002094 blockIndex, **blockInfoItr);
2095
2096 // add to uniform list, but not index, since uniform block uniforms have no location
2097 blockUniformIndexes->push_back(mUniforms.size());
2098 mUniforms.push_back(newUniform);
2099 (*blockInfoItr)++;
2100 }
2101 }
2102}
2103
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002104bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2105{
2106 // create uniform block entries if they do not exist
2107 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2108 {
2109 std::vector<unsigned int> blockUniformIndexes;
2110 const unsigned int blockIndex = mUniformBlocks.size();
2111
2112 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002113 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002114 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002115
2116 // create all the uniform blocks
2117 if (interfaceBlock.arraySize > 0)
2118 {
2119 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2120 {
2121 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2122 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2123 mUniformBlocks.push_back(newUniformBlock);
2124 }
2125 }
2126 else
2127 {
2128 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2129 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2130 mUniformBlocks.push_back(newUniformBlock);
2131 }
2132 }
2133
2134 // Assign registers to the uniform blocks
2135 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2136 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2137 ASSERT(blockIndex != GL_INVALID_INDEX);
2138 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2139
2140 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2141 {
2142 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2143 ASSERT(uniformBlock->name == interfaceBlock.name);
2144
2145 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2146 {
2147 return false;
2148 }
2149 }
2150
2151 return true;
2152}
2153
2154bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2155{
2156 if (shader == GL_VERTEX_SHADER)
2157 {
2158 uniformBlock->vsRegisterIndex = registerIndex;
2159 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2160
2161 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2162 {
2163 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2164 return false;
2165 }
2166 }
2167 else if (shader == GL_FRAGMENT_SHADER)
2168 {
2169 uniformBlock->psRegisterIndex = registerIndex;
2170 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2171
2172 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2173 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002174 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002175 return false;
2176 }
2177 }
2178 else UNREACHABLE();
2179
2180 return true;
2181}
2182
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002183bool ProgramBinary::isValidated() const
2184{
2185 return mValidated;
2186}
2187
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002188void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002189{
2190 // Skip over inactive attributes
2191 unsigned int activeAttribute = 0;
2192 unsigned int attribute;
2193 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2194 {
2195 if (mLinkedAttribute[attribute].name.empty())
2196 {
2197 continue;
2198 }
2199
2200 if (activeAttribute == index)
2201 {
2202 break;
2203 }
2204
2205 activeAttribute++;
2206 }
2207
2208 if (bufsize > 0)
2209 {
2210 const char *string = mLinkedAttribute[attribute].name.c_str();
2211
2212 strncpy(name, string, bufsize);
2213 name[bufsize - 1] = '\0';
2214
2215 if (length)
2216 {
2217 *length = strlen(name);
2218 }
2219 }
2220
2221 *size = 1; // Always a single 'type' instance
2222
2223 *type = mLinkedAttribute[attribute].type;
2224}
2225
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002226GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002227{
2228 int count = 0;
2229
2230 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2231 {
2232 if (!mLinkedAttribute[attributeIndex].name.empty())
2233 {
2234 count++;
2235 }
2236 }
2237
2238 return count;
2239}
2240
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002241GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002242{
2243 int maxLength = 0;
2244
2245 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2246 {
2247 if (!mLinkedAttribute[attributeIndex].name.empty())
2248 {
2249 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2250 }
2251 }
2252
2253 return maxLength;
2254}
2255
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002256void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002257{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002258 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002259
2260 if (bufsize > 0)
2261 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002262 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002263
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002264 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002265 {
2266 string += "[0]";
2267 }
2268
2269 strncpy(name, string.c_str(), bufsize);
2270 name[bufsize - 1] = '\0';
2271
2272 if (length)
2273 {
2274 *length = strlen(name);
2275 }
2276 }
2277
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002278 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002279
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002280 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002281}
2282
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002283GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002284{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002285 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002286}
2287
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002288GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002289{
2290 int maxLength = 0;
2291
2292 unsigned int numUniforms = mUniforms.size();
2293 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2294 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002295 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002296 {
2297 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2298 if (mUniforms[uniformIndex]->isArray())
2299 {
2300 length += 3; // Counting in "[0]".
2301 }
2302 maxLength = std::max(length, maxLength);
2303 }
2304 }
2305
2306 return maxLength;
2307}
2308
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002309GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2310{
2311 const gl::Uniform& uniform = *mUniforms[index];
2312
2313 switch (pname)
2314 {
2315 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2316 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002317 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 +00002318 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002319
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002320 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2321 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2322 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2323 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002324
2325 default:
2326 UNREACHABLE();
2327 break;
2328 }
2329 return 0;
2330}
2331
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002332void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2333{
2334 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2335
2336 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2337
2338 if (bufSize > 0)
2339 {
2340 std::string string = uniformBlock.name;
2341
2342 if (uniformBlock.isArrayElement())
2343 {
Jamie Madill5f562732014-02-14 16:41:24 -05002344 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002345 }
2346
2347 strncpy(uniformBlockName, string.c_str(), bufSize);
2348 uniformBlockName[bufSize - 1] = '\0';
2349
2350 if (length)
2351 {
2352 *length = strlen(uniformBlockName);
2353 }
2354 }
2355}
2356
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002357void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2358{
2359 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2360
2361 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2362
2363 switch (pname)
2364 {
2365 case GL_UNIFORM_BLOCK_DATA_SIZE:
2366 *params = static_cast<GLint>(uniformBlock.dataSize);
2367 break;
2368 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002369 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002370 break;
2371 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2372 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2373 break;
2374 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2375 {
2376 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2377 {
2378 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2379 }
2380 }
2381 break;
2382 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2383 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2384 break;
2385 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2386 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2387 break;
2388 default: UNREACHABLE();
2389 }
2390}
2391
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002392GLuint ProgramBinary::getActiveUniformBlockCount() const
2393{
2394 return mUniformBlocks.size();
2395}
2396
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002397GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2398{
2399 unsigned int maxLength = 0;
2400
2401 unsigned int numUniformBlocks = mUniformBlocks.size();
2402 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2403 {
2404 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2405 if (!uniformBlock.name.empty())
2406 {
2407 const unsigned int length = uniformBlock.name.length() + 1;
2408
2409 // Counting in "[0]".
2410 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2411
2412 maxLength = std::max(length + arrayLength, maxLength);
2413 }
2414 }
2415
2416 return maxLength;
2417}
2418
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002419void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002420{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002421 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002422 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002423 {
2424 mValidated = false;
2425 }
2426 else
2427 {
2428 mValidated = true;
2429 }
2430}
2431
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002432bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002433{
2434 // if any two active samplers in a program are of different types, but refer to the same
2435 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2436 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2437
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002438 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002439 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002440
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002441 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002442 {
2443 textureUnitType[i] = TEXTURE_UNKNOWN;
2444 }
2445
2446 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2447 {
2448 if (mSamplersPS[i].active)
2449 {
2450 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2451
2452 if (unit >= maxCombinedTextureImageUnits)
2453 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002454 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002455 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002456 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002457 }
2458
2459 return false;
2460 }
2461
2462 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2463 {
2464 if (mSamplersPS[i].textureType != textureUnitType[unit])
2465 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002466 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002467 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002468 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002469 }
2470
2471 return false;
2472 }
2473 }
2474 else
2475 {
2476 textureUnitType[unit] = mSamplersPS[i].textureType;
2477 }
2478 }
2479 }
2480
2481 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2482 {
2483 if (mSamplersVS[i].active)
2484 {
2485 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2486
2487 if (unit >= maxCombinedTextureImageUnits)
2488 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002489 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002490 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002491 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002492 }
2493
2494 return false;
2495 }
2496
2497 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2498 {
2499 if (mSamplersVS[i].textureType != textureUnitType[unit])
2500 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002501 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002502 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002503 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002504 }
2505
2506 return false;
2507 }
2508 }
2509 else
2510 {
2511 textureUnitType[unit] = mSamplersVS[i].textureType;
2512 }
2513 }
2514 }
2515
2516 return true;
2517}
2518
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002519ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2520{
2521}
2522
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002523struct AttributeSorter
2524{
2525 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2526 : originalIndices(semanticIndices)
2527 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002528 }
2529
2530 bool operator()(int a, int b)
2531 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002532 if (originalIndices[a] == -1) return false;
2533 if (originalIndices[b] == -1) return true;
2534 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002535 }
2536
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002537 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2538};
2539
Al Patrick3f2daa82013-08-07 12:58:57 -07002540void ProgramBinary::initAttributesByLayout()
2541{
2542 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2543 {
2544 mAttributesByLayout[i] = i;
2545 }
2546
2547 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2548}
2549
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002550void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2551{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002552 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2553
2554 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2555 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002556 oldTranslatedAttributes[i] = attributes[i];
2557 }
2558
2559 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2560 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002561 int oldIndex = mAttributesByLayout[i];
2562 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002563 attributes[i] = oldTranslatedAttributes[oldIndex];
2564 }
2565}
2566
Jamie Madill8ff21ae2014-02-04 16:04:05 -05002567void ProgramBinary::initializeUniformStorage()
2568{
2569 // Compute total default block size
2570 unsigned int vertexRegisters = 0;
2571 unsigned int fragmentRegisters = 0;
2572 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2573 {
2574 const Uniform &uniform = *mUniforms[uniformIndex];
2575
2576 if (!IsSampler(uniform.type))
2577 {
2578 if (uniform.isReferencedByVertexShader())
2579 {
2580 vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
2581 }
2582 if (uniform.isReferencedByFragmentShader())
2583 {
2584 fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
2585 }
2586 }
2587 }
2588
2589 mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
2590 mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
2591}
2592
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002593}