blob: 53f3d0e785894e29d6e85b910b8358932d82c1f6 [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"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
Jamie Madill63491ea2013-06-06 11:56:45 -040039std::string arrayString(int i)
40{
41 return "[" + str(i) + "]";
42}
43
Jamie Madill46131a32013-06-20 11:55:50 -040044std::string arrayString(unsigned int i)
45{
46 return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
47}
48
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000049namespace gl_d3d
50{
51 std::string TypeString(GLenum type)
52 {
53 switch (type)
54 {
55 case GL_FLOAT: return "float";
56 case GL_FLOAT_VEC2: return "float2";
57 case GL_FLOAT_VEC3: return "float3";
58 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000059 case GL_INT: return "int";
60 case GL_INT_VEC2: return "int2";
61 case GL_INT_VEC3: return "int3";
62 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000063 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000064 case GL_UNSIGNED_INT_VEC2: return "uint2";
65 case GL_UNSIGNED_INT_VEC3: return "uint3";
66 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000067 case GL_FLOAT_MAT2: return "float2x2";
68 case GL_FLOAT_MAT3: return "float3x3";
69 case GL_FLOAT_MAT4: return "float4x4";
70 case GL_FLOAT_MAT2x3: return "float2x3";
71 case GL_FLOAT_MAT3x2: return "float3x2";
72 case GL_FLOAT_MAT2x4: return "float2x4";
73 case GL_FLOAT_MAT4x2: return "float4x2";
74 case GL_FLOAT_MAT3x4: return "float3x4";
75 case GL_FLOAT_MAT4x3: return "float4x3";
76 default: UNREACHABLE(); return "invalid-gl-type";
77 }
78 }
79}
80
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000081namespace
82{
83
84unsigned int parseAndStripArrayIndex(std::string* name)
85{
86 unsigned int subscript = GL_INVALID_INDEX;
87
88 // Strip any trailing array operator and retrieve the subscript
89 size_t open = name->find_last_of('[');
90 size_t close = name->find_last_of(']');
91 if (open != std::string::npos && close == name->length() - 1)
92 {
93 subscript = atoi(name->substr(open + 1).c_str());
94 name->erase(open);
95 }
96
97 return subscript;
98}
99
100}
101
Jamie Madill63491ea2013-06-06 11:56:45 -0400102VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000103 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000104{
105}
106
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000107unsigned int ProgramBinary::mCurrentSerial = 1;
108
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000109ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000110{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000111 mPixelExecutable = NULL;
112 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000113 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000114
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115 mValidated = false;
116
117 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
118 {
119 mSemanticIndex[index] = -1;
120 }
121
122 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
123 {
124 mSamplersPS[index].active = false;
125 }
126
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000127 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000128 {
129 mSamplersVS[index].active = false;
130 }
131
132 mUsedVertexSamplerRange = 0;
133 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000134 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000135 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136}
137
138ProgramBinary::~ProgramBinary()
139{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000140 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000141 mPixelExecutable = NULL;
142
daniel@transgaming.com95892412012-11-28 20:59:09 +0000143 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000144 mVertexExecutable = NULL;
145
146 delete mGeometryExecutable;
147 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000148
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000149 while (!mUniforms.empty())
150 {
151 delete mUniforms.back();
152 mUniforms.pop_back();
153 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000154
155 while (!mUniformBlocks.empty())
156 {
157 delete mUniformBlocks.back();
158 mUniformBlocks.pop_back();
159 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000160}
161
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000162unsigned int ProgramBinary::getSerial() const
163{
164 return mSerial;
165}
166
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000167int ProgramBinary::getShaderVersion() const
168{
169 return mShaderVersion;
170}
171
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000172unsigned int ProgramBinary::issueSerial()
173{
174 return mCurrentSerial++;
175}
176
daniel@transgaming.com95892412012-11-28 20:59:09 +0000177rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000178{
179 return mPixelExecutable;
180}
181
daniel@transgaming.com95892412012-11-28 20:59:09 +0000182rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000183{
184 return mVertexExecutable;
185}
186
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000187rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
188{
189 return mGeometryExecutable;
190}
191
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000192GLuint ProgramBinary::getAttributeLocation(const char *name)
193{
194 if (name)
195 {
196 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
197 {
198 if (mLinkedAttribute[index].name == std::string(name))
199 {
200 return index;
201 }
202 }
203 }
204
205 return -1;
206}
207
208int ProgramBinary::getSemanticIndex(int attributeIndex)
209{
210 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
211
212 return mSemanticIndex[attributeIndex];
213}
214
215// Returns one more than the highest sampler index used.
216GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
217{
218 switch (type)
219 {
220 case SAMPLER_PIXEL:
221 return mUsedPixelSamplerRange;
222 case SAMPLER_VERTEX:
223 return mUsedVertexSamplerRange;
224 default:
225 UNREACHABLE();
226 return 0;
227 }
228}
229
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000230bool ProgramBinary::usesPointSize() const
231{
232 return mUsesPointSize;
233}
234
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000235bool ProgramBinary::usesPointSpriteEmulation() const
236{
237 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
238}
239
240bool ProgramBinary::usesGeometryShader() const
241{
242 return usesPointSpriteEmulation();
243}
244
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000245// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
246// index (0-15 for the pixel shader and 0-3 for the vertex shader).
247GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
248{
249 GLint logicalTextureUnit = -1;
250
251 switch (type)
252 {
253 case SAMPLER_PIXEL:
254 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
255
256 if (mSamplersPS[samplerIndex].active)
257 {
258 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
259 }
260 break;
261 case SAMPLER_VERTEX:
262 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
263
264 if (mSamplersVS[samplerIndex].active)
265 {
266 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
267 }
268 break;
269 default: UNREACHABLE();
270 }
271
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000272 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000273 {
274 return logicalTextureUnit;
275 }
276
277 return -1;
278}
279
280// Returns the texture type for a given Direct3D 9 sampler type and
281// index (0-15 for the pixel shader and 0-3 for the vertex shader).
282TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
283{
284 switch (type)
285 {
286 case SAMPLER_PIXEL:
287 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
288 ASSERT(mSamplersPS[samplerIndex].active);
289 return mSamplersPS[samplerIndex].textureType;
290 case SAMPLER_VERTEX:
291 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
292 ASSERT(mSamplersVS[samplerIndex].active);
293 return mSamplersVS[samplerIndex].textureType;
294 default: UNREACHABLE();
295 }
296
297 return TEXTURE_2D;
298}
299
300GLint ProgramBinary::getUniformLocation(std::string name)
301{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000302 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000303
304 unsigned int numUniforms = mUniformIndex.size();
305 for (unsigned int location = 0; location < numUniforms; location++)
306 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000307 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000308 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000309 const int index = mUniformIndex[location].index;
310 const bool isArray = mUniforms[index]->isArray();
311
312 if ((isArray && mUniformIndex[location].element == subscript) ||
313 (subscript == GL_INVALID_INDEX))
314 {
315 return location;
316 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000317 }
318 }
319
320 return -1;
321}
322
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000323GLuint ProgramBinary::getUniformIndex(std::string name)
324{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000325 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000326
327 // The app is not allowed to specify array indices other than 0 for arrays of basic types
328 if (subscript != 0 && subscript != GL_INVALID_INDEX)
329 {
330 return GL_INVALID_INDEX;
331 }
332
333 unsigned int numUniforms = mUniforms.size();
334 for (unsigned int index = 0; index < numUniforms; index++)
335 {
336 if (mUniforms[index]->name == name)
337 {
338 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
339 {
340 return index;
341 }
342 }
343 }
344
345 return GL_INVALID_INDEX;
346}
347
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000348GLuint ProgramBinary::getUniformBlockIndex(std::string name)
349{
350 unsigned int subscript = parseAndStripArrayIndex(&name);
351
352 unsigned int numUniformBlocks = mUniformBlocks.size();
353 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
354 {
355 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
356 if (uniformBlock.name == name)
357 {
358 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
359 if (subscript == uniformBlock.elementIndex || arrayElementZero)
360 {
361 return blockIndex;
362 }
363 }
364 }
365
366 return GL_INVALID_INDEX;
367}
368
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000369UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
370{
371 ASSERT(blockIndex < mUniformBlocks.size());
372 return mUniformBlocks[blockIndex];
373}
374
Jamie Madilld1e78c92013-06-20 11:55:50 -0400375GLint ProgramBinary::getFragDataLocation(const char *name) const
376{
377 std::string baseName(name);
378 unsigned int arrayIndex;
379 arrayIndex = parseAndStripArrayIndex(&baseName);
380
381 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
382 {
383 const VariableLocation &outputVariable = locationIt->second;
384
385 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
386 {
387 return static_cast<GLint>(locationIt->first);
388 }
389 }
390
391 return -1;
392}
393
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000394template <typename T>
395bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000396{
397 if (location < 0 || location >= (int)mUniformIndex.size())
398 {
399 return false;
400 }
401
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000402 const int components = UniformComponentCount(targetUniformType);
403 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
404
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
406 targetUniform->dirty = true;
407
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000408 int elementCount = targetUniform->elementCount();
409
410 if (elementCount == 1 && count > 1)
411 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
412
413 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
414
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000415 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000416 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000417 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000418
419 for (int i = 0; i < count; i++)
420 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000421 for (int c = 0; c < components; c++)
422 {
423 target[c] = v[c];
424 }
425 for (int c = components; c < 4; c++)
426 {
427 target[c] = 0;
428 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000429 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000430 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000431 }
432 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000433 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000434 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000435 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000436
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000437 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000439 for (int c = 0; c < components; c++)
440 {
441 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
442 }
443 for (int c = components; c < 4; c++)
444 {
445 boolParams[c] = GL_FALSE;
446 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000447 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000448 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000449 }
450 }
451 else
452 {
453 return false;
454 }
455
456 return true;
457}
458
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000459bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
460{
461 return setUniform(location, count, v, GL_FLOAT);
462}
463
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000464bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
465{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000466 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000467}
468
469bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
470{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000471 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000472}
473
474bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
475{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000476 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000477}
478
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000479template<typename T>
480void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000481{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000482 int copyWidth = std::min(targetHeight, srcWidth);
483 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000484
485 for (int x = 0; x < copyWidth; x++)
486 {
487 for (int y = 0; y < copyHeight; y++)
488 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000489 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000490 }
491 }
492 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000493 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000494 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000495 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000496 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000497 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000498 }
499 }
500 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000501 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000502 {
503 for (int x = 0; x < targetWidth; x++)
504 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000505 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000506 }
507 }
508}
509
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000510template<typename T>
511void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
512{
513 int copyWidth = std::min(targetWidth, srcWidth);
514 int copyHeight = std::min(targetHeight, srcHeight);
515
516 for (int y = 0; y < copyHeight; y++)
517 {
518 for (int x = 0; x < copyWidth; x++)
519 {
520 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
521 }
522 }
523 // clear unfilled right side
524 for (int y = 0; y < copyHeight; y++)
525 {
526 for (int x = copyWidth; x < targetWidth; x++)
527 {
528 target[y * targetWidth + x] = static_cast<T>(0);
529 }
530 }
531 // clear unfilled bottom.
532 for (int y = copyHeight; y < targetHeight; y++)
533 {
534 for (int x = 0; x < targetWidth; x++)
535 {
536 target[y * targetWidth + x] = static_cast<T>(0);
537 }
538 }
539}
540
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000541template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000542bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000543{
544 if (location < 0 || location >= (int)mUniformIndex.size())
545 {
546 return false;
547 }
548
549 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
550 targetUniform->dirty = true;
551
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000552 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000553 {
554 return false;
555 }
556
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000557 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000558
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000559 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000560 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
561
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000562 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000563 const unsigned int targetMatrixStride = (4 * rows);
564 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000565
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000566 for (int i = 0; i < count; i++)
567 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000568 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
569 if (transpose == GL_FALSE)
570 {
571 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
572 }
573 else
574 {
575 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
576 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000577 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000578 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000579 }
580
581 return true;
582}
583
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000584bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000585{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000586 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000587}
588
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000589bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000590{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000591 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000592}
593
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000594bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000595{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000596 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000597}
598
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000599bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000600{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000601 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000602}
603
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000604bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000605{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000606 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000607}
608
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000609bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000610{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000611 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000612}
613
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000614bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000615{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000616 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000617}
618
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000619bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000620{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000621 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000622}
623
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000624bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000625{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000626 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000627}
628
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
630{
631 if (location < 0 || location >= (int)mUniformIndex.size())
632 {
633 return false;
634 }
635
636 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
637 targetUniform->dirty = true;
638
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000639 int elementCount = targetUniform->elementCount();
640
641 if (elementCount == 1 && count > 1)
642 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
643
644 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
645
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000646 if (targetUniform->type == GL_INT ||
647 targetUniform->type == GL_SAMPLER_2D ||
648 targetUniform->type == GL_SAMPLER_CUBE)
649 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000650 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000651
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000652 for (int i = 0; i < count; i++)
653 {
654 target[0] = v[0];
655 target[1] = 0;
656 target[2] = 0;
657 target[3] = 0;
658 target += 4;
659 v += 1;
660 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000661 }
662 else if (targetUniform->type == GL_BOOL)
663 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000664 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000666 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000668 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
669 boolParams[1] = GL_FALSE;
670 boolParams[2] = GL_FALSE;
671 boolParams[3] = GL_FALSE;
672 boolParams += 4;
673 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000674 }
675 }
676 else
677 {
678 return false;
679 }
680
681 return true;
682}
683
684bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
685{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000686 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000687}
688
689bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
690{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000691 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692}
693
694bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
695{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000696 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697}
698
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000699bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
700{
701 return setUniform(location, count, v, GL_UNSIGNED_INT);
702}
703
704bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
705{
706 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
707}
708
709bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
710{
711 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
712}
713
714bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
715{
716 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
717}
718
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000719template <typename T>
720bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000721{
722 if (location < 0 || location >= (int)mUniformIndex.size())
723 {
724 return false;
725 }
726
727 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
728
729 // sized queries -- ensure the provided buffer is large enough
730 if (bufSize)
731 {
732 int requiredBytes = UniformExternalSize(targetUniform->type);
733 if (*bufSize < requiredBytes)
734 {
735 return false;
736 }
737 }
738
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000740 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000741 const int rows = VariableRowCount(targetUniform->type);
742 const int cols = VariableColumnCount(targetUniform->type);
743 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
744 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000745 else if (uniformType == UniformComponentType(targetUniform->type))
746 {
747 unsigned int size = UniformComponentCount(targetUniform->type);
748 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
749 size * sizeof(T));
750 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000751 else
752 {
753 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000754 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000756 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000757 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000758 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000759
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000760 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000762 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000763 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000764 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000765 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000766
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000767 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000768 {
769 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
770
771 for (unsigned int i = 0; i < size; i++)
772 {
773 params[i] = static_cast<T>(floatParams[i]);
774 }
775 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000776 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000777
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000778 case GL_INT:
779 {
780 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
781
782 for (unsigned int i = 0; i < size; i++)
783 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000784 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000785 }
786 }
787 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000788
789 case GL_UNSIGNED_INT:
790 {
791 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000792
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000793 for (unsigned int i = 0; i < size; i++)
794 {
795 params[i] = static_cast<T>(uintParams[i]);
796 }
797 }
798 break;
799
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000800 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000801 }
802 }
803
804 return true;
805}
806
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000807bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
808{
809 return getUniformv(location, bufSize, params, GL_FLOAT);
810}
811
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000812bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
813{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000814 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000815}
816
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000817bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
818{
819 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
820}
821
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000822void ProgramBinary::dirtyAllUniforms()
823{
824 unsigned int numUniforms = mUniforms.size();
825 for (unsigned int index = 0; index < numUniforms; index++)
826 {
827 mUniforms[index]->dirty = true;
828 }
829}
830
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000831// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000832void ProgramBinary::applyUniforms()
833{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000834 // Retrieve sampler uniform values
835 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
836 {
837 Uniform *targetUniform = *ub;
838
839 if (targetUniform->dirty)
840 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000841 if (targetUniform->type == GL_SAMPLER_2D ||
842 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000843 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000844 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000845 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000846
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000847 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000848 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000849 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000850
851 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000852 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000853 unsigned int samplerIndex = firstIndex + i;
854
855 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000856 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000857 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000858 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000859 }
860 }
861 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000862
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000863 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000864 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000865 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000866
867 for (int i = 0; i < count; i++)
868 {
869 unsigned int samplerIndex = firstIndex + i;
870
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000871 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000872 {
873 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000874 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000875 }
876 }
877 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000878 }
879 }
880 }
881
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000882 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000883}
884
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000885bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
886{
887 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
888 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
889
890 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
891 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
892
893 ASSERT(boundBuffers.size() == mUniformBlocks.size());
894
895 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
896 {
897 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
898 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
899
900 ASSERT(uniformBlock && uniformBuffer);
901
902 if (uniformBuffer->size() < uniformBlock->dataSize)
903 {
904 // undefined behaviour
905 return false;
906 }
907
908 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
909
910 if (uniformBlock->isReferencedByVertexShader())
911 {
912 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
913 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
914 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
915 vertexUniformBuffers[registerIndex] = uniformBuffer;
916 }
917
918 if (uniformBlock->isReferencedByFragmentShader())
919 {
920 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
921 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
922 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
923 fragmentUniformBuffers[registerIndex] = uniformBuffer;
924 }
925 }
926
927 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
928}
929
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000930// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
931// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000932int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000933{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000934 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000935
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000936 fragmentShader->resetVaryingsRegisterAssignment();
937
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000938 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
939 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000940 GLenum transposedType = TransposeMatrixType(varying->type);
941 int n = VariableRowCount(transposedType) * varying->size;
942 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000943 bool success = false;
944
945 if (m == 2 || m == 3 || m == 4)
946 {
947 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
948 {
949 bool available = true;
950
951 for (int y = 0; y < n && available; y++)
952 {
953 for (int x = 0; x < m && available; x++)
954 {
955 if (packing[r + y][x])
956 {
957 available = false;
958 }
959 }
960 }
961
962 if (available)
963 {
964 varying->reg = r;
965 varying->col = 0;
966
967 for (int y = 0; y < n; y++)
968 {
969 for (int x = 0; x < m; x++)
970 {
971 packing[r + y][x] = &*varying;
972 }
973 }
974
975 success = true;
976 }
977 }
978
979 if (!success && m == 2)
980 {
981 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
982 {
983 bool available = true;
984
985 for (int y = 0; y < n && available; y++)
986 {
987 for (int x = 2; x < 4 && available; x++)
988 {
989 if (packing[r + y][x])
990 {
991 available = false;
992 }
993 }
994 }
995
996 if (available)
997 {
998 varying->reg = r;
999 varying->col = 2;
1000
1001 for (int y = 0; y < n; y++)
1002 {
1003 for (int x = 2; x < 4; x++)
1004 {
1005 packing[r + y][x] = &*varying;
1006 }
1007 }
1008
1009 success = true;
1010 }
1011 }
1012 }
1013 }
1014 else if (m == 1)
1015 {
1016 int space[4] = {0};
1017
1018 for (int y = 0; y < maxVaryingVectors; y++)
1019 {
1020 for (int x = 0; x < 4; x++)
1021 {
1022 space[x] += packing[y][x] ? 0 : 1;
1023 }
1024 }
1025
1026 int column = 0;
1027
1028 for (int x = 0; x < 4; x++)
1029 {
1030 if (space[x] >= n && space[x] < space[column])
1031 {
1032 column = x;
1033 }
1034 }
1035
1036 if (space[column] >= n)
1037 {
1038 for (int r = 0; r < maxVaryingVectors; r++)
1039 {
1040 if (!packing[r][column])
1041 {
1042 varying->reg = r;
1043
1044 for (int y = r; y < r + n; y++)
1045 {
1046 packing[y][column] = &*varying;
1047 }
1048
1049 break;
1050 }
1051 }
1052
1053 varying->col = column;
1054
1055 success = true;
1056 }
1057 }
1058 else UNREACHABLE();
1059
1060 if (!success)
1061 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001062 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001063
1064 return -1;
1065 }
1066 }
1067
1068 // Return the number of used registers
1069 int registers = 0;
1070
1071 for (int r = 0; r < maxVaryingVectors; r++)
1072 {
1073 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1074 {
1075 registers++;
1076 }
1077 }
1078
1079 return registers;
1080}
1081
Jamie Madill46131a32013-06-20 11:55:50 -04001082void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1083{
1084 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1085
1086 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1087 {
1088 const sh::ShaderVariable &outputVariable = outputVars[outputVariableIndex];
1089 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1090
1091 if (outputVariable.arraySize > 0)
1092 {
1093 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1094 {
1095 const int location = baseLocation + elementIndex;
1096 ASSERT(mOutputVariables.count(location) == 0);
1097 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1098 }
1099 }
1100 else
1101 {
1102 ASSERT(mOutputVariables.count(baseLocation) == 0);
1103 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1104 }
1105 }
1106}
1107
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001108bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1109 std::string& pixelHLSL, std::string& vertexHLSL,
1110 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001111{
1112 if (pixelHLSL.empty() || vertexHLSL.empty())
1113 {
1114 return false;
1115 }
1116
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001117 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1118 bool usesFragColor = fragmentShader->mUsesFragColor;
1119 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001120 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001121 {
1122 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1123 return false;
1124 }
1125
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001126 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001127 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001128 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001129
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001130 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1131
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001132 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1133 // - with a 3.0 context, the output color is copied to channel 0
1134 // - with a 2.0 context, the output color is broadcast to all channels
1135 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1136 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1137
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001138 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001139 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001140 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001141
1142 return false;
1143 }
1144
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001145 vertexShader->resetVaryingsRegisterAssignment();
1146
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001147 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1148 {
1149 bool matched = false;
1150
1151 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1152 {
1153 if (output->name == input->name)
1154 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001155 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001156 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001157 infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001158
1159 return false;
1160 }
1161
1162 output->reg = input->reg;
1163 output->col = input->col;
1164
1165 matched = true;
1166 break;
1167 }
1168 }
1169
1170 if (!matched)
1171 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001172 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001173
1174 return false;
1175 }
1176 }
1177
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001178 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001179 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001180 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001181 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1182
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001183 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1184
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001185 // special varyings that use reserved registers
1186 int reservedRegisterIndex = registers;
1187 std::string fragCoordSemantic;
1188 std::string pointCoordSemantic;
1189
1190 if (fragmentShader->mUsesFragCoord)
1191 {
1192 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1193 }
1194
1195 if (fragmentShader->mUsesPointCoord)
1196 {
1197 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1198 // In DX11 we compute this in the GS.
1199 if (shaderModel == 3)
1200 {
1201 pointCoordSemantic = "TEXCOORD0";
1202 }
1203 else if (shaderModel >= 4)
1204 {
1205 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1206 }
1207 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208
1209 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001210 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001211
1212 int semanticIndex = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04001213 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
1214 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001215 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001216 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1217 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1218 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001219
Jamie Madilldefb6742013-06-20 11:55:51 -04001220 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001221 }
1222
1223 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001224 "\n"
1225 "struct VS_OUTPUT\n"
1226 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001227
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001228 if (shaderModel < 4)
1229 {
1230 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1231 }
1232
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001233 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234
1235 if (fragmentShader->mUsesFragCoord)
1236 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001237 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001238 }
1239
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001240 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001241 {
1242 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1243 }
1244
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001245 if (shaderModel >= 4)
1246 {
1247 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1248 }
1249
1250 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001251 "\n"
1252 "VS_OUTPUT main(VS_INPUT input)\n"
1253 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001254
Jamie Madilldefb6742013-06-20 11:55:51 -04001255 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001256 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001257 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1258 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001259
Jamie Madilldefb6742013-06-20 11:55:51 -04001260 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001261 {
1262 vertexHLSL += "transpose";
1263 }
1264
Jamie Madilldefb6742013-06-20 11:55:51 -04001265 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001266 }
1267
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001268 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1269 {
1270 vertexHLSL += "\n"
1271 " dx_initConstantBuffers();\n";
1272 }
1273
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001274 if (shaderModel >= 4)
1275 {
1276 vertexHLSL += "\n"
1277 " gl_main();\n"
1278 "\n"
1279 " VS_OUTPUT output;\n"
1280 " output.gl_Position.x = gl_Position.x;\n"
1281 " output.gl_Position.y = -gl_Position.y;\n"
1282 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1283 " output.gl_Position.w = gl_Position.w;\n";
1284 }
1285 else
1286 {
1287 vertexHLSL += "\n"
1288 " gl_main();\n"
1289 "\n"
1290 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001291 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1292 " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001293 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1294 " output.gl_Position.w = gl_Position.w;\n";
1295 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001296
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001297 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001299 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001300 }
1301
1302 if (fragmentShader->mUsesFragCoord)
1303 {
1304 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1305 }
1306
1307 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1308 {
1309 if (varying->reg >= 0)
1310 {
1311 for (int i = 0; i < varying->size; i++)
1312 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001313 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314
1315 for (int j = 0; j < rows; j++)
1316 {
1317 int r = varying->reg + i * rows + j;
1318 vertexHLSL += " output.v" + str(r);
1319
1320 bool sharedRegister = false; // Register used by multiple varyings
1321
1322 for (int x = 0; x < 4; x++)
1323 {
1324 if (packing[r][x] && packing[r][x] != packing[r][0])
1325 {
1326 sharedRegister = true;
1327 break;
1328 }
1329 }
1330
1331 if(sharedRegister)
1332 {
1333 vertexHLSL += ".";
1334
1335 for (int x = 0; x < 4; x++)
1336 {
1337 if (packing[r][x] == &*varying)
1338 {
1339 switch(x)
1340 {
1341 case 0: vertexHLSL += "x"; break;
1342 case 1: vertexHLSL += "y"; break;
1343 case 2: vertexHLSL += "z"; break;
1344 case 3: vertexHLSL += "w"; break;
1345 }
1346 }
1347 }
1348 }
1349
1350 vertexHLSL += " = " + varying->name;
1351
1352 if (varying->array)
1353 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001354 vertexHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001355 }
1356
1357 if (rows > 1)
1358 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001359 vertexHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001360 }
1361
1362 vertexHLSL += ";\n";
1363 }
1364 }
1365 }
1366 }
1367
1368 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001369 " return output;\n"
1370 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001371
1372 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001373 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001374
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001375 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001376
1377 if (fragmentShader->mUsesFragCoord)
1378 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001379 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001380 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001381
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001382 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1383 {
1384 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1385 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001386
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001387 // Must consume the PSIZE element if the geometry shader is not active
1388 // We won't know if we use a GS until we draw
1389 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1390 {
1391 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1392 }
1393
1394 if (fragmentShader->mUsesFragCoord)
1395 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001396 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001397 {
1398 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1399 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001400 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001401 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001402 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1403 }
1404 }
1405
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001406 pixelHLSL += "};\n"
1407 "\n"
1408 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001409 "{\n";
1410
Jamie Madill46131a32013-06-20 11:55:50 -04001411 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001412 {
Jamie Madill46131a32013-06-20 11:55:50 -04001413 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1414 {
1415 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1416 }
1417 }
1418 else
1419 {
1420 defineOutputVariables(fragmentShader);
1421
1422 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1423 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1424 {
1425 const VariableLocation &outputLocation = locationIt->second;
1426 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1427 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1428
1429 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1430 " out_" + outputLocation.name + elementString +
1431 " : " + targetSemantic + str(locationIt->first) + ";\n";
1432 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001433 }
1434
1435 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001436 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001437
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001438 if (fragmentShader->mUsesFrontFacing)
1439 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001440 if (shaderModel >= 4)
1441 {
1442 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1443 "{\n";
1444 }
1445 else
1446 {
1447 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1448 "{\n";
1449 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001450 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001451 else
1452 {
1453 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1454 "{\n";
1455 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001456
1457 if (fragmentShader->mUsesFragCoord)
1458 {
1459 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1460
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001461 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001462 {
1463 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1464 " gl_FragCoord.y = input.dx_VPos.y;\n";
1465 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001466 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001468 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001469 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001470 }
1471 else
1472 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001473 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1474 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1475 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001476 }
1477
daniel@transgaming.com12985182012-12-20 20:56:31 +00001478 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001479 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001480 }
1481
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001482 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001483 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001484 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1485 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001486 }
1487
1488 if (fragmentShader->mUsesFrontFacing)
1489 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001490 if (shaderModel <= 3)
1491 {
1492 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1493 }
1494 else
1495 {
1496 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1497 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001498 }
1499
1500 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1501 {
1502 if (varying->reg >= 0)
1503 {
1504 for (int i = 0; i < varying->size; i++)
1505 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001506 GLenum transposedType = TransposeMatrixType(varying->type);
1507 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001508 for (int j = 0; j < rows; j++)
1509 {
1510 std::string n = str(varying->reg + i * rows + j);
1511 pixelHLSL += " " + varying->name;
1512
1513 if (varying->array)
1514 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001515 pixelHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001516 }
1517
1518 if (rows > 1)
1519 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001520 pixelHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001521 }
1522
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001523 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001524 {
1525 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1526 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1527 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1528 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1529 default: UNREACHABLE();
1530 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001531 }
1532 }
1533 }
1534 else UNREACHABLE();
1535 }
1536
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001537 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1538 {
1539 pixelHLSL += "\n"
1540 " dx_initConstantBuffers();\n";
1541 }
1542
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001543 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001544 " gl_main();\n"
1545 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001546 " PS_OUTPUT output;\n";
1547
Jamie Madill46131a32013-06-20 11:55:50 -04001548 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001549 {
Jamie Madill46131a32013-06-20 11:55:50 -04001550 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1551 {
1552 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001553
Jamie Madill46131a32013-06-20 11:55:50 -04001554 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1555 }
1556 }
1557 else
1558 {
1559 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1560 {
1561 const VariableLocation &outputLocation = locationIt->second;
1562 const std::string &variableName = "out_" + outputLocation.name;
1563 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1564 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1565
1566 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1567 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001568 }
1569
1570 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001571 " return output;\n"
1572 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001573
1574 return true;
1575}
1576
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001577std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1578{
1579 std::string varyingHLSL;
1580
1581 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1582 {
1583 if (varying->reg >= 0)
1584 {
1585 for (int i = 0; i < varying->size; i++)
1586 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001587 GLenum transposedType = TransposeMatrixType(varying->type);
1588 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001589 for (int j = 0; j < rows; j++)
1590 {
1591 switch (varying->interpolation)
1592 {
1593 case Smooth: varyingHLSL += " "; break;
1594 case Flat: varyingHLSL += " nointerpolation "; break;
1595 case Centroid: varyingHLSL += " centroid "; break;
1596 default: UNREACHABLE();
1597 }
1598
1599 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001600 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001601
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001602 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001603 }
1604 }
1605 }
1606 else UNREACHABLE();
1607 }
1608
1609 return varyingHLSL;
1610}
1611
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001612bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1613{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001614 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001615
1616 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001617 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618 if (format != GL_PROGRAM_BINARY_ANGLE)
1619 {
1620 infoLog.append("Invalid program binary format.");
1621 return false;
1622 }
1623
1624 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001625 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001626 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 {
1628 infoLog.append("Invalid program binary version.");
1629 return false;
1630 }
1631
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001632 int compileFlags = 0;
1633 stream.read(&compileFlags);
1634 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1635 {
1636 infoLog.append("Mismatched compilation flags.");
1637 return false;
1638 }
1639
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1641 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001642 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001644 stream.read(&name);
1645 mLinkedAttribute[i].name = name;
1646 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001647 }
1648
1649 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1650 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001651 stream.read(&mSamplersPS[i].active);
1652 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001653
1654 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656 mSamplersPS[i].textureType = (TextureType) textureType;
1657 }
1658
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001659 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001661 stream.read(&mSamplersVS[i].active);
1662 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001663
1664 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001665 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666 mSamplersVS[i].textureType = (TextureType) textureType;
1667 }
1668
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 stream.read(&mUsedVertexSamplerRange);
1670 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001671 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001672 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001674 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001675 stream.read(&size);
1676 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001677 {
1678 infoLog.append("Invalid program binary.");
1679 return false;
1680 }
1681
1682 mUniforms.resize(size);
1683 for (unsigned int i = 0; i < size; ++i)
1684 {
1685 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001686 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001687 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001689 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001690
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001691 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001692 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001693 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001694 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001695 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001697 int offset;
1698 int arrayStride;
1699 int matrixStride;
1700 bool isRowMajorMatrix;
1701
1702 stream.read(&offset);
1703 stream.read(&arrayStride);
1704 stream.read(&matrixStride);
1705 stream.read(&isRowMajorMatrix);
1706
1707 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1708
1709 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001711 stream.read(&mUniforms[i]->psRegisterIndex);
1712 stream.read(&mUniforms[i]->vsRegisterIndex);
1713 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001714 }
1715
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001716 stream.read(&size);
1717 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001718 {
1719 infoLog.append("Invalid program binary.");
1720 return false;
1721 }
1722
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001723 mUniformBlocks.resize(size);
1724 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1725 {
1726 std::string name;
1727 unsigned int elementIndex;
1728 unsigned int dataSize;
1729
1730 stream.read(&name);
1731 stream.read(&elementIndex);
1732 stream.read(&dataSize);
1733
1734 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1735
1736 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1737 stream.read(&uniformBlock.psRegisterIndex);
1738 stream.read(&uniformBlock.vsRegisterIndex);
1739
1740 size_t numMembers;
1741 stream.read(&numMembers);
1742 uniformBlock.memberUniformIndexes.resize(numMembers);
1743 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1744 {
1745 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1746 }
1747 }
1748
1749 stream.read(&size);
1750 if (stream.error())
1751 {
1752 infoLog.append("Invalid program binary.");
1753 return false;
1754 }
1755
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001756 mUniformIndex.resize(size);
1757 for (unsigned int i = 0; i < size; ++i)
1758 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001759 stream.read(&mUniformIndex[i].name);
1760 stream.read(&mUniformIndex[i].element);
1761 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 }
1763
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001765 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001766
1767 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001768 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001770 unsigned int geometryShaderSize;
1771 stream.read(&geometryShaderSize);
1772
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001773 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774
daniel@transgaming.com36038542012-11-28 20:59:26 +00001775 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776 ptr += sizeof(GUID);
1777
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001778 GUID identifier = mRenderer->getAdapterIdentifier();
1779 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780 {
1781 infoLog.append("Invalid program binary.");
1782 return false;
1783 }
1784
1785 const char *pixelShaderFunction = ptr;
1786 ptr += pixelShaderSize;
1787
1788 const char *vertexShaderFunction = ptr;
1789 ptr += vertexShaderSize;
1790
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001791 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1792 ptr += geometryShaderSize;
1793
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001794 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001795 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001796 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001797 {
1798 infoLog.append("Could not create pixel shader.");
1799 return false;
1800 }
1801
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001802 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001803 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001804 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805 {
1806 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001807 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 mPixelExecutable = NULL;
1809 return false;
1810 }
1811
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001812 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1813 {
1814 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1815 geometryShaderSize, rx::SHADER_GEOMETRY);
1816 if (!mGeometryExecutable)
1817 {
1818 infoLog.append("Could not create geometry shader.");
1819 delete mPixelExecutable;
1820 mPixelExecutable = NULL;
1821 delete mVertexExecutable;
1822 mVertexExecutable = NULL;
1823 return false;
1824 }
1825 }
1826 else
1827 {
1828 mGeometryExecutable = NULL;
1829 }
1830
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831 return true;
1832}
1833
1834bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1835{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001836 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001838 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001839 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001840 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001841
1842 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1843 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001844 stream.write(mLinkedAttribute[i].type);
1845 stream.write(mLinkedAttribute[i].name);
1846 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001847 }
1848
1849 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1850 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001851 stream.write(mSamplersPS[i].active);
1852 stream.write(mSamplersPS[i].logicalTextureUnit);
1853 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854 }
1855
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001856 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001858 stream.write(mSamplersVS[i].active);
1859 stream.write(mSamplersVS[i].logicalTextureUnit);
1860 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001861 }
1862
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001863 stream.write(mUsedVertexSamplerRange);
1864 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001865 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001866 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001867
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001868 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001869 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001870 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001871 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001872
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001873 stream.write(uniform.type);
1874 stream.write(uniform.precision);
1875 stream.write(uniform.name);
1876 stream.write(uniform.arraySize);
1877 stream.write(uniform.blockIndex);
1878
1879 stream.write(uniform.blockInfo.offset);
1880 stream.write(uniform.blockInfo.arrayStride);
1881 stream.write(uniform.blockInfo.matrixStride);
1882 stream.write(uniform.blockInfo.isRowMajorMatrix);
1883
1884 stream.write(uniform.psRegisterIndex);
1885 stream.write(uniform.vsRegisterIndex);
1886 stream.write(uniform.registerCount);
1887 }
1888
1889 stream.write(mUniformBlocks.size());
1890 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1891 {
1892 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1893
1894 stream.write(uniformBlock.name);
1895 stream.write(uniformBlock.elementIndex);
1896 stream.write(uniformBlock.dataSize);
1897
1898 stream.write(uniformBlock.memberUniformIndexes.size());
1899 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1900 {
1901 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1902 }
1903
1904 stream.write(uniformBlock.psRegisterIndex);
1905 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001906 }
1907
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001908 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001909 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1910 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001911 stream.write(mUniformIndex[i].name);
1912 stream.write(mUniformIndex[i].element);
1913 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001914 }
1915
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001916 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001917 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001918
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001919 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001920 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001921
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001922 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1923 stream.write(geometryShaderSize);
1924
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001925 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001926
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001927 GLsizei streamLength = stream.length();
1928 const void *streamData = stream.data();
1929
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001930 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001931 if (totalLength > bufSize)
1932 {
1933 if (length)
1934 {
1935 *length = 0;
1936 }
1937
1938 return false;
1939 }
1940
1941 if (binary)
1942 {
1943 char *ptr = (char*) binary;
1944
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001945 memcpy(ptr, streamData, streamLength);
1946 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001947
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001948 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001949 ptr += sizeof(GUID);
1950
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001951 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001952 ptr += pixelShaderSize;
1953
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001954 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001955 ptr += vertexShaderSize;
1956
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001957 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1958 {
1959 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1960 ptr += geometryShaderSize;
1961 }
1962
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001963 ASSERT(ptr - totalLength == binary);
1964 }
1965
1966 if (length)
1967 {
1968 *length = totalLength;
1969 }
1970
1971 return true;
1972}
1973
1974GLint ProgramBinary::getLength()
1975{
1976 GLint length;
1977 if (save(NULL, INT_MAX, &length))
1978 {
1979 return length;
1980 }
1981 else
1982 {
1983 return 0;
1984 }
1985}
1986
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001987bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001988{
1989 if (!fragmentShader || !fragmentShader->isCompiled())
1990 {
1991 return false;
1992 }
1993
1994 if (!vertexShader || !vertexShader->isCompiled())
1995 {
1996 return false;
1997 }
1998
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001999 mShaderVersion = vertexShader->getShaderVersion();
2000
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002001 std::string pixelHLSL = fragmentShader->getHLSL();
2002 std::string vertexHLSL = vertexShader->getHLSL();
2003
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002004 // Map the varyings to the register file
2005 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
2006 int registers = packVaryings(infoLog, packing, fragmentShader);
2007
2008 if (registers < 0)
2009 {
2010 return false;
2011 }
2012
2013 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002014 {
2015 return false;
2016 }
2017
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002018 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00002019 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
2020 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002021
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002022 if (usesGeometryShader())
2023 {
2024 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2025 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2026 }
2027
2028 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002029 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00002030 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002031 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00002032
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00002033 delete mVertexExecutable;
2034 mVertexExecutable = NULL;
2035 delete mPixelExecutable;
2036 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002037 delete mGeometryExecutable;
2038 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002039 }
2040
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002041 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2042 {
2043 success = false;
2044 }
2045
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002046 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002047 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002048 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002049 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002050
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002051 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2052 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2053 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002054 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2055 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2056 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 +00002057 }
2058
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002059 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2060 {
2061 success = false;
2062 }
2063
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002064 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002065}
2066
2067// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002068bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002069{
2070 unsigned int usedLocations = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04002071 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002072
2073 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002074 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002075 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002076 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002077 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002078
Jamie Madilleba4eff2013-06-20 11:55:51 -04002079 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002080 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002081 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082
2083 if (rows + location > MAX_VERTEX_ATTRIBS)
2084 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002085 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 +00002086
2087 return false;
2088 }
2089
Jamie Madilleba4eff2013-06-20 11:55:51 -04002090 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002091 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002092 const int rowLocation = location + row;
2093 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2094
2095 // In GLSL 3.00, attribute aliasing produces a link error
2096 // In GLSL 1.00, attribute aliasing is allowed
2097 if (mShaderVersion >= 300)
2098 {
2099 if (!linkedAttribute.name.empty())
2100 {
2101 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2102 return false;
2103 }
2104 }
2105
2106 linkedAttribute = attribute;
2107 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002108 }
2109 }
2110 }
2111
2112 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002113 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002114 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002115 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002116 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002117
Jamie Madilleba4eff2013-06-20 11:55:51 -04002118 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002119 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002120 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2122
2123 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2124 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002125 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002126
2127 return false; // Fail to link
2128 }
2129
Jamie Madilldefb6742013-06-20 11:55:51 -04002130 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002131 }
2132 }
2133
2134 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2135 {
2136 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002137 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002138
2139 for (int r = 0; r < rows; r++)
2140 {
2141 mSemanticIndex[attributeIndex++] = index++;
2142 }
2143 }
2144
2145 return true;
2146}
2147
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002148bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2149{
2150 if (vertexUniform.type != fragmentUniform.type)
2151 {
2152 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2153 return false;
2154 }
2155 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2156 {
2157 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2158 return false;
2159 }
2160 else if (vertexUniform.precision != fragmentUniform.precision)
2161 {
2162 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2163 return false;
2164 }
2165 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2166 {
2167 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2168 }
Jamie Madill010fffa2013-06-20 11:55:53 -04002169 else if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2170 {
2171 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2172 return false;
2173 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002174
2175 const unsigned int numMembers = vertexUniform.fields.size();
2176 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2177 {
2178 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2179 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2180
2181 if (vertexMember.name != fragmentMember.name)
2182 {
2183 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2184 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2185 return false;
2186 }
2187
2188 const std::string memberName = uniformName + "." + vertexUniform.name;
2189 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2190 {
2191 return false;
2192 }
2193 }
2194
2195 return true;
2196}
2197
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002198bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002200 // Check that uniforms defined in the vertex and fragment shaders are identical
2201 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2202 UniformMap linkedUniforms;
2203
2204 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2205 {
2206 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2207 linkedUniforms[vertexUniform.name] = &vertexUniform;
2208 }
2209
2210 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2211 {
2212 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2213 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2214 if (entry != linkedUniforms.end())
2215 {
2216 const sh::Uniform &vertexUniform = *entry->second;
2217 const std::string &uniformName = "uniform " + vertexUniform.name;
2218 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2219 {
2220 return false;
2221 }
2222 }
2223 }
2224
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002225 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002226 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002227 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002228 {
2229 return false;
2230 }
2231 }
2232
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002233 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002234 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002235 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002236 {
2237 return false;
2238 }
2239 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002240
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002241 return true;
2242}
2243
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002244int totalRegisterCount(const sh::Uniform &uniform)
2245{
2246 int registerCount = 0;
2247
2248 if (!uniform.fields.empty())
2249 {
2250 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2251 {
2252 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2253 }
2254 }
2255 else
2256 {
2257 registerCount = 1;
2258 }
2259
2260 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2261}
2262
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002263bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002264{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002265 if (!constant.fields.empty())
2266 {
2267 if (constant.arraySize > 0)
2268 {
2269 unsigned int elementRegisterIndex = constant.registerIndex;
2270
2271 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2272 {
2273 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2274 {
2275 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002276 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madill010fffa2013-06-20 11:55:53 -04002277 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002278 if (!defineUniform(shader, fieldUniform, infoLog))
2279 {
2280 return false;
2281 }
2282 elementRegisterIndex += totalRegisterCount(field);
2283 }
2284 }
2285 }
2286 else
2287 {
2288 unsigned int fieldRegisterIndex = constant.registerIndex;
2289
2290 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2291 {
2292 const sh::Uniform &field = constant.fields[fieldIndex];
2293 const std::string &uniformName = constant.name + "." + field.name;
2294
Jamie Madill010fffa2013-06-20 11:55:53 -04002295 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002296 fieldUniform.fields = field.fields;
2297
2298 if (!defineUniform(shader, fieldUniform, infoLog))
2299 {
2300 return false;
2301 }
2302 fieldRegisterIndex += totalRegisterCount(field);
2303 }
2304 }
2305
2306 return true;
2307 }
2308
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002309 if (constant.type == GL_SAMPLER_2D ||
2310 constant.type == GL_SAMPLER_CUBE)
2311 {
2312 unsigned int samplerIndex = constant.registerIndex;
2313
2314 do
2315 {
2316 if (shader == GL_VERTEX_SHADER)
2317 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002318 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002319 {
2320 mSamplersVS[samplerIndex].active = true;
2321 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2322 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2323 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2324 }
2325 else
2326 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002327 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002328 return false;
2329 }
2330 }
2331 else if (shader == GL_FRAGMENT_SHADER)
2332 {
2333 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2334 {
2335 mSamplersPS[samplerIndex].active = true;
2336 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2337 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2338 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2339 }
2340 else
2341 {
2342 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2343 return false;
2344 }
2345 }
2346 else UNREACHABLE();
2347
2348 samplerIndex++;
2349 }
2350 while (samplerIndex < constant.registerIndex + constant.arraySize);
2351 }
2352
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002353 Uniform *uniform = NULL;
2354 GLint location = getUniformLocation(constant.name);
2355
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002356 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002357 {
2358 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002359 }
2360 else
2361 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002362 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002363 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002364
2365 if (!uniform)
2366 {
2367 return false;
2368 }
2369
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002370 if (shader == GL_FRAGMENT_SHADER)
2371 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002372 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002373 }
2374 else if (shader == GL_VERTEX_SHADER)
2375 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002376 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002377 }
2378 else UNREACHABLE();
2379
2380 if (location >= 0)
2381 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002382 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002383 }
2384
2385 mUniforms.push_back(uniform);
2386 unsigned int uniformIndex = mUniforms.size() - 1;
2387
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002388 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002389 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002390 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002391 }
2392
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002393 if (shader == GL_VERTEX_SHADER)
2394 {
2395 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2396 {
2397 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2398 return false;
2399 }
2400 }
2401 else if (shader == GL_FRAGMENT_SHADER)
2402 {
2403 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2404 {
2405 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2406 return false;
2407 }
2408 }
2409 else UNREACHABLE();
2410
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002411 return true;
2412}
2413
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002414bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2415{
2416 const char* blockName = vertexInterfaceBlock.name.c_str();
2417
2418 // validate blocks for the same member types
2419 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2420 {
2421 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2422 return false;
2423 }
2424
2425 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2426 {
2427 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2428 return false;
2429 }
2430
2431 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2432 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2433 {
2434 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2435 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2436
2437 if (vertexMember.name != fragmentMember.name)
2438 {
2439 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2440 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2441 return false;
2442 }
2443
2444 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2445 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2446 {
2447 return false;
2448 }
2449 }
2450
2451 return true;
2452}
2453
2454bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2455{
2456 // Check that interface blocks defined in the vertex and fragment shaders are identical
2457 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2458 UniformBlockMap linkedUniformBlocks;
2459
2460 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2461 {
2462 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2463 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2464 }
2465
2466 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2467 {
2468 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2469 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2470 if (entry != linkedUniformBlocks.end())
2471 {
2472 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2473 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2474 {
2475 return false;
2476 }
2477 }
2478 }
2479
2480 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2481 {
2482 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2483 {
2484 return false;
2485 }
2486 }
2487
2488 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2489 {
2490 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2491 {
2492 return false;
2493 }
2494 }
2495
2496 return true;
2497}
2498
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002499void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2500{
2501 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2502 {
2503 const sh::Uniform &uniform = uniforms[uniformIndex];
Jamie Madillacdd70f2013-06-07 14:39:56 -04002504 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002505
2506 if (!uniform.fields.empty())
2507 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002508 if (uniform.arraySize > 0)
2509 {
2510 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2511 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002512 const std::string uniformElementName = uniformName + arrayString(arrayElement);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002513 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2514 }
2515 }
2516 else
2517 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002518 defineUniformBlockMembers(uniform.fields, uniformName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002519 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002520 }
2521 else
2522 {
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002523 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2524 blockIndex, **blockInfoItr);
2525
2526 // add to uniform list, but not index, since uniform block uniforms have no location
2527 blockUniformIndexes->push_back(mUniforms.size());
2528 mUniforms.push_back(newUniform);
2529 (*blockInfoItr)++;
2530 }
2531 }
2532}
2533
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002534bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2535{
2536 // create uniform block entries if they do not exist
2537 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2538 {
2539 std::vector<unsigned int> blockUniformIndexes;
2540 const unsigned int blockIndex = mUniformBlocks.size();
2541
2542 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002543 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2544 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002545
2546 // create all the uniform blocks
2547 if (interfaceBlock.arraySize > 0)
2548 {
2549 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2550 {
2551 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2552 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2553 mUniformBlocks.push_back(newUniformBlock);
2554 }
2555 }
2556 else
2557 {
2558 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2559 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2560 mUniformBlocks.push_back(newUniformBlock);
2561 }
2562 }
2563
2564 // Assign registers to the uniform blocks
2565 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2566 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2567 ASSERT(blockIndex != GL_INVALID_INDEX);
2568 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2569
2570 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2571 {
2572 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2573 ASSERT(uniformBlock->name == interfaceBlock.name);
2574
2575 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2576 {
2577 return false;
2578 }
2579 }
2580
2581 return true;
2582}
2583
2584bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2585{
2586 if (shader == GL_VERTEX_SHADER)
2587 {
2588 uniformBlock->vsRegisterIndex = registerIndex;
2589 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2590
2591 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2592 {
2593 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2594 return false;
2595 }
2596 }
2597 else if (shader == GL_FRAGMENT_SHADER)
2598 {
2599 uniformBlock->psRegisterIndex = registerIndex;
2600 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2601
2602 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2603 {
2604 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2605 return false;
2606 }
2607 }
2608 else UNREACHABLE();
2609
2610 return true;
2611}
2612
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002613std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2614{
2615 // for now we only handle point sprite emulation
2616 ASSERT(usesPointSpriteEmulation());
2617 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2618}
2619
2620std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2621{
2622 ASSERT(registers >= 0);
2623 ASSERT(vertexShader->mUsesPointSize);
2624 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2625
2626 std::string geomHLSL;
2627
2628 std::string varyingSemantic = "TEXCOORD";
2629
2630 std::string fragCoordSemantic;
2631 std::string pointCoordSemantic;
2632
2633 int reservedRegisterIndex = registers;
2634
2635 if (fragmentShader->mUsesFragCoord)
2636 {
2637 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2638 }
2639
2640 if (fragmentShader->mUsesPointCoord)
2641 {
2642 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2643 }
2644
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002645 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2646 "\n"
2647 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002648 "{\n";
2649
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002650 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002651
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002652 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002653
2654 if (fragmentShader->mUsesFragCoord)
2655 {
2656 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2657 }
2658
2659 geomHLSL += " float gl_PointSize : PSIZE;\n"
2660 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002661 "};\n"
2662 "\n"
2663 "struct GS_OUTPUT\n"
2664 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002665
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002666 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002667
2668 if (fragmentShader->mUsesFragCoord)
2669 {
2670 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2671 }
2672
2673 if (fragmentShader->mUsesPointCoord)
2674 {
2675 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2676 }
2677
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002678 geomHLSL += " float gl_PointSize : PSIZE;\n"
2679 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002680 "};\n"
2681 "\n"
2682 "static float2 pointSpriteCorners[] = \n"
2683 "{\n"
2684 " float2( 0.5f, -0.5f),\n"
2685 " float2( 0.5f, 0.5f),\n"
2686 " float2(-0.5f, -0.5f),\n"
2687 " float2(-0.5f, 0.5f)\n"
2688 "};\n"
2689 "\n"
2690 "static float2 pointSpriteTexcoords[] = \n"
2691 "{\n"
2692 " float2(1.0f, 1.0f),\n"
2693 " float2(1.0f, 0.0f),\n"
2694 " float2(0.0f, 1.0f),\n"
2695 " float2(0.0f, 0.0f)\n"
2696 "};\n"
2697 "\n"
2698 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2699 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2700 "\n"
2701 "[maxvertexcount(4)]\n"
2702 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2703 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002704 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2705 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002706
2707 for (int r = 0; r < registers; r++)
2708 {
2709 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2710 }
2711
2712 if (fragmentShader->mUsesFragCoord)
2713 {
2714 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2715 }
2716
2717 geomHLSL += " \n"
2718 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2719 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002720 " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002721
2722 for (int corner = 0; corner < 4; corner++)
2723 {
2724 geomHLSL += " \n"
2725 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2726
2727 if (fragmentShader->mUsesPointCoord)
2728 {
2729 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2730 }
2731
2732 geomHLSL += " outStream.Append(output);\n";
2733 }
2734
2735 geomHLSL += " \n"
2736 " outStream.RestartStrip();\n"
2737 "}\n";
2738
2739 return geomHLSL;
2740}
2741
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002742// This method needs to match OutputHLSL::decorate
2743std::string ProgramBinary::decorateAttribute(const std::string &name)
2744{
2745 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2746 {
2747 return "_" + name;
2748 }
2749
2750 return name;
2751}
2752
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002753bool ProgramBinary::isValidated() const
2754{
2755 return mValidated;
2756}
2757
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002758void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002759{
2760 // Skip over inactive attributes
2761 unsigned int activeAttribute = 0;
2762 unsigned int attribute;
2763 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2764 {
2765 if (mLinkedAttribute[attribute].name.empty())
2766 {
2767 continue;
2768 }
2769
2770 if (activeAttribute == index)
2771 {
2772 break;
2773 }
2774
2775 activeAttribute++;
2776 }
2777
2778 if (bufsize > 0)
2779 {
2780 const char *string = mLinkedAttribute[attribute].name.c_str();
2781
2782 strncpy(name, string, bufsize);
2783 name[bufsize - 1] = '\0';
2784
2785 if (length)
2786 {
2787 *length = strlen(name);
2788 }
2789 }
2790
2791 *size = 1; // Always a single 'type' instance
2792
2793 *type = mLinkedAttribute[attribute].type;
2794}
2795
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002796GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002797{
2798 int count = 0;
2799
2800 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2801 {
2802 if (!mLinkedAttribute[attributeIndex].name.empty())
2803 {
2804 count++;
2805 }
2806 }
2807
2808 return count;
2809}
2810
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002811GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002812{
2813 int maxLength = 0;
2814
2815 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2816 {
2817 if (!mLinkedAttribute[attributeIndex].name.empty())
2818 {
2819 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2820 }
2821 }
2822
2823 return maxLength;
2824}
2825
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002826void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002827{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002828 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002829
2830 if (bufsize > 0)
2831 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002832 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002833
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002834 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002835 {
2836 string += "[0]";
2837 }
2838
2839 strncpy(name, string.c_str(), bufsize);
2840 name[bufsize - 1] = '\0';
2841
2842 if (length)
2843 {
2844 *length = strlen(name);
2845 }
2846 }
2847
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002848 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002849
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002850 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002851}
2852
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002853GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002854{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002855 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002856}
2857
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002858GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002859{
2860 int maxLength = 0;
2861
2862 unsigned int numUniforms = mUniforms.size();
2863 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2864 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002865 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002866 {
2867 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2868 if (mUniforms[uniformIndex]->isArray())
2869 {
2870 length += 3; // Counting in "[0]".
2871 }
2872 maxLength = std::max(length, maxLength);
2873 }
2874 }
2875
2876 return maxLength;
2877}
2878
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002879GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2880{
2881 const gl::Uniform& uniform = *mUniforms[index];
2882
2883 switch (pname)
2884 {
2885 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2886 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002887 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 +00002888 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002889
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002890 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2891 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2892 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2893 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002894
2895 default:
2896 UNREACHABLE();
2897 break;
2898 }
2899 return 0;
2900}
2901
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002902void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2903{
2904 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2905
2906 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2907
2908 if (bufSize > 0)
2909 {
2910 std::string string = uniformBlock.name;
2911
2912 if (uniformBlock.isArrayElement())
2913 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002914 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002915 }
2916
2917 strncpy(uniformBlockName, string.c_str(), bufSize);
2918 uniformBlockName[bufSize - 1] = '\0';
2919
2920 if (length)
2921 {
2922 *length = strlen(uniformBlockName);
2923 }
2924 }
2925}
2926
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002927void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2928{
2929 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2930
2931 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2932
2933 switch (pname)
2934 {
2935 case GL_UNIFORM_BLOCK_DATA_SIZE:
2936 *params = static_cast<GLint>(uniformBlock.dataSize);
2937 break;
2938 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002939 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002940 break;
2941 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2942 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2943 break;
2944 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2945 {
2946 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2947 {
2948 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2949 }
2950 }
2951 break;
2952 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2953 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2954 break;
2955 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2956 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2957 break;
2958 default: UNREACHABLE();
2959 }
2960}
2961
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002962GLuint ProgramBinary::getActiveUniformBlockCount() const
2963{
2964 return mUniformBlocks.size();
2965}
2966
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002967GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2968{
2969 unsigned int maxLength = 0;
2970
2971 unsigned int numUniformBlocks = mUniformBlocks.size();
2972 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2973 {
2974 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2975 if (!uniformBlock.name.empty())
2976 {
2977 const unsigned int length = uniformBlock.name.length() + 1;
2978
2979 // Counting in "[0]".
2980 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2981
2982 maxLength = std::max(length + arrayLength, maxLength);
2983 }
2984 }
2985
2986 return maxLength;
2987}
2988
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002989void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002990{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002991 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002992 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002993 {
2994 mValidated = false;
2995 }
2996 else
2997 {
2998 mValidated = true;
2999 }
3000}
3001
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003002bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003003{
3004 // if any two active samplers in a program are of different types, but refer to the same
3005 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3006 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3007
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00003008 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003009 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003010
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003011 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003012 {
3013 textureUnitType[i] = TEXTURE_UNKNOWN;
3014 }
3015
3016 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3017 {
3018 if (mSamplersPS[i].active)
3019 {
3020 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3021
3022 if (unit >= maxCombinedTextureImageUnits)
3023 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003024 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003025 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003026 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003027 }
3028
3029 return false;
3030 }
3031
3032 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3033 {
3034 if (mSamplersPS[i].textureType != textureUnitType[unit])
3035 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003036 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003037 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003038 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003039 }
3040
3041 return false;
3042 }
3043 }
3044 else
3045 {
3046 textureUnitType[unit] = mSamplersPS[i].textureType;
3047 }
3048 }
3049 }
3050
3051 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3052 {
3053 if (mSamplersVS[i].active)
3054 {
3055 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3056
3057 if (unit >= maxCombinedTextureImageUnits)
3058 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003059 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003060 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003061 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003062 }
3063
3064 return false;
3065 }
3066
3067 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3068 {
3069 if (mSamplersVS[i].textureType != textureUnitType[unit])
3070 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003071 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003072 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003073 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003074 }
3075
3076 return false;
3077 }
3078 }
3079 else
3080 {
3081 textureUnitType[unit] = mSamplersVS[i].textureType;
3082 }
3083 }
3084 }
3085
3086 return true;
3087}
3088
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003089ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3090{
3091}
3092
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003093struct AttributeSorter
3094{
3095 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3096 : originalIndices(semanticIndices)
3097 {
3098 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3099 {
3100 indices[i] = i;
3101 }
3102
3103 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3104 }
3105
3106 bool operator()(int a, int b)
3107 {
3108 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3109 }
3110
3111 int indices[MAX_VERTEX_ATTRIBS];
3112 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3113};
3114
3115void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3116{
3117 AttributeSorter sorter(mSemanticIndex);
3118
3119 int oldIndices[MAX_VERTEX_ATTRIBS];
3120 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3121
3122 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3123 {
3124 oldIndices[i] = mSemanticIndex[i];
3125 oldTranslatedAttributes[i] = attributes[i];
3126 }
3127
3128 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3129 {
3130 int oldIndex = sorter.indices[i];
3131 sortedSemanticIndices[i] = oldIndices[oldIndex];
3132 attributes[i] = oldTranslatedAttributes[oldIndex];
3133 }
3134}
3135
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003136}