blob: 116cc9451b771e702b4ad520497f2776cbc48622 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
Nicolas Capense6050882013-07-08 10:43:10 -040024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
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
Nicolas Capense6050882013-07-08 10:43:10 -0400646 if (targetUniform->type == GL_INT || IsSampler(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000647 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000648 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000649
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000650 for (int i = 0; i < count; i++)
651 {
652 target[0] = v[0];
653 target[1] = 0;
654 target[2] = 0;
655 target[3] = 0;
656 target += 4;
657 v += 1;
658 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000659 }
660 else if (targetUniform->type == GL_BOOL)
661 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000662 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000663
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000664 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000665 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000666 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
667 boolParams[1] = GL_FALSE;
668 boolParams[2] = GL_FALSE;
669 boolParams[3] = GL_FALSE;
670 boolParams += 4;
671 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000672 }
673 }
674 else
675 {
676 return false;
677 }
678
679 return true;
680}
681
682bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
683{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000684 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000685}
686
687bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
688{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000689 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000690}
691
692bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
693{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000694 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000695}
696
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000697bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
698{
699 return setUniform(location, count, v, GL_UNSIGNED_INT);
700}
701
702bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
703{
704 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
705}
706
707bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
708{
709 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
710}
711
712bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
713{
714 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
715}
716
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000717template <typename T>
718bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000719{
720 if (location < 0 || location >= (int)mUniformIndex.size())
721 {
722 return false;
723 }
724
725 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
726
727 // sized queries -- ensure the provided buffer is large enough
728 if (bufSize)
729 {
730 int requiredBytes = UniformExternalSize(targetUniform->type);
731 if (*bufSize < requiredBytes)
732 {
733 return false;
734 }
735 }
736
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000737 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000738 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 const int rows = VariableRowCount(targetUniform->type);
740 const int cols = VariableColumnCount(targetUniform->type);
741 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
742 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000743 else if (uniformType == UniformComponentType(targetUniform->type))
744 {
745 unsigned int size = UniformComponentCount(targetUniform->type);
746 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
747 size * sizeof(T));
748 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000749 else
750 {
751 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000752 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000753 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000754 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000756 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000757
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000758 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000759 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000760 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000762 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000763 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000764
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000765 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000766 {
767 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
768
769 for (unsigned int i = 0; i < size; i++)
770 {
771 params[i] = static_cast<T>(floatParams[i]);
772 }
773 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000774 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000775
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000776 case GL_INT:
777 {
778 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
779
780 for (unsigned int i = 0; i < size; i++)
781 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000782 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000783 }
784 }
785 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000786
787 case GL_UNSIGNED_INT:
788 {
789 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000790
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000791 for (unsigned int i = 0; i < size; i++)
792 {
793 params[i] = static_cast<T>(uintParams[i]);
794 }
795 }
796 break;
797
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000798 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000799 }
800 }
801
802 return true;
803}
804
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000805bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
806{
807 return getUniformv(location, bufSize, params, GL_FLOAT);
808}
809
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000810bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
811{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000812 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000813}
814
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000815bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
816{
817 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
818}
819
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000820void ProgramBinary::dirtyAllUniforms()
821{
822 unsigned int numUniforms = mUniforms.size();
823 for (unsigned int index = 0; index < numUniforms; index++)
824 {
825 mUniforms[index]->dirty = true;
826 }
827}
828
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000829// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000830void ProgramBinary::applyUniforms()
831{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000832 // Retrieve sampler uniform values
833 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
834 {
835 Uniform *targetUniform = *ub;
836
837 if (targetUniform->dirty)
838 {
Nicolas Capense6050882013-07-08 10:43:10 -0400839 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000840 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000841 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000842 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000843
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000844 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000845 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000846 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000847
848 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000849 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000850 unsigned int samplerIndex = firstIndex + i;
851
852 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000853 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000854 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000855 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000856 }
857 }
858 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000859
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000860 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000861 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000862 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000863
864 for (int i = 0; i < count; i++)
865 {
866 unsigned int samplerIndex = firstIndex + i;
867
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000868 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000869 {
870 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000871 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000872 }
873 }
874 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000875 }
876 }
877 }
878
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000879 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000880}
881
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000882bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
883{
884 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
885 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
886
887 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
888 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
889
890 ASSERT(boundBuffers.size() == mUniformBlocks.size());
891
892 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
893 {
894 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
895 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
896
897 ASSERT(uniformBlock && uniformBuffer);
898
899 if (uniformBuffer->size() < uniformBlock->dataSize)
900 {
901 // undefined behaviour
902 return false;
903 }
904
905 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
906
907 if (uniformBlock->isReferencedByVertexShader())
908 {
909 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
910 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
911 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
912 vertexUniformBuffers[registerIndex] = uniformBuffer;
913 }
914
915 if (uniformBlock->isReferencedByFragmentShader())
916 {
917 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
918 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
919 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
920 fragmentUniformBuffers[registerIndex] = uniformBuffer;
921 }
922 }
923
924 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
925}
926
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000927// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
928// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000929int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000930{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000931 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000932
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000933 fragmentShader->resetVaryingsRegisterAssignment();
934
Jamie Madillce79dda2013-08-30 13:21:06 -0400935 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000936 {
Jamie Madillce79dda2013-08-30 13:21:06 -0400937 Varying *varying = &fragmentShader->mVaryings[varyingIndex];
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000938 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill139b9092013-08-30 13:21:06 -0400939 int n = VariableRowCount(transposedType) * varying->elementCount();
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000940 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000941 bool success = false;
942
943 if (m == 2 || m == 3 || m == 4)
944 {
945 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
946 {
947 bool available = true;
948
949 for (int y = 0; y < n && available; y++)
950 {
951 for (int x = 0; x < m && available; x++)
952 {
953 if (packing[r + y][x])
954 {
955 available = false;
956 }
957 }
958 }
959
960 if (available)
961 {
Jamie Madill139b9092013-08-30 13:21:06 -0400962 varying->registerIndex = r;
963 varying->elementIndex = 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000964
965 for (int y = 0; y < n; y++)
966 {
967 for (int x = 0; x < m; x++)
968 {
969 packing[r + y][x] = &*varying;
970 }
971 }
972
973 success = true;
974 }
975 }
976
977 if (!success && m == 2)
978 {
979 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
980 {
981 bool available = true;
982
983 for (int y = 0; y < n && available; y++)
984 {
985 for (int x = 2; x < 4 && available; x++)
986 {
987 if (packing[r + y][x])
988 {
989 available = false;
990 }
991 }
992 }
993
994 if (available)
995 {
Jamie Madill139b9092013-08-30 13:21:06 -0400996 varying->registerIndex = r;
997 varying->elementIndex = 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000998
999 for (int y = 0; y < n; y++)
1000 {
1001 for (int x = 2; x < 4; x++)
1002 {
1003 packing[r + y][x] = &*varying;
1004 }
1005 }
1006
1007 success = true;
1008 }
1009 }
1010 }
1011 }
1012 else if (m == 1)
1013 {
1014 int space[4] = {0};
1015
1016 for (int y = 0; y < maxVaryingVectors; y++)
1017 {
1018 for (int x = 0; x < 4; x++)
1019 {
1020 space[x] += packing[y][x] ? 0 : 1;
1021 }
1022 }
1023
1024 int column = 0;
1025
1026 for (int x = 0; x < 4; x++)
1027 {
1028 if (space[x] >= n && space[x] < space[column])
1029 {
1030 column = x;
1031 }
1032 }
1033
1034 if (space[column] >= n)
1035 {
1036 for (int r = 0; r < maxVaryingVectors; r++)
1037 {
1038 if (!packing[r][column])
1039 {
Jamie Madill139b9092013-08-30 13:21:06 -04001040 varying->registerIndex = r;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001041
1042 for (int y = r; y < r + n; y++)
1043 {
1044 packing[y][column] = &*varying;
1045 }
1046
1047 break;
1048 }
1049 }
1050
Jamie Madill139b9092013-08-30 13:21:06 -04001051 varying->elementIndex = column;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052
1053 success = true;
1054 }
1055 }
1056 else UNREACHABLE();
1057
1058 if (!success)
1059 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001060 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001061
1062 return -1;
1063 }
1064 }
1065
1066 // Return the number of used registers
1067 int registers = 0;
1068
1069 for (int r = 0; r < maxVaryingVectors; r++)
1070 {
1071 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1072 {
1073 registers++;
1074 }
1075 }
1076
1077 return registers;
1078}
1079
Jamie Madill46131a32013-06-20 11:55:50 -04001080void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1081{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001082 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001083
1084 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1085 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001086 const sh::Attribute &outputVariable = outputVars[outputVariableIndex];
Jamie Madill46131a32013-06-20 11:55:50 -04001087 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1088
1089 if (outputVariable.arraySize > 0)
1090 {
1091 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1092 {
1093 const int location = baseLocation + elementIndex;
1094 ASSERT(mOutputVariables.count(location) == 0);
1095 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1096 }
1097 }
1098 else
1099 {
1100 ASSERT(mOutputVariables.count(baseLocation) == 0);
1101 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1102 }
1103 }
1104}
1105
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001106bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1107 std::string& pixelHLSL, std::string& vertexHLSL,
1108 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001109{
1110 if (pixelHLSL.empty() || vertexHLSL.empty())
1111 {
1112 return false;
1113 }
1114
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001115 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1116 bool usesFragColor = fragmentShader->mUsesFragColor;
1117 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001118 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001119 {
1120 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1121 return false;
1122 }
1123
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001124 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001125 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001126 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001127
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001128 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1129
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001130 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1131 // - with a 3.0 context, the output color is copied to channel 0
1132 // - with a 2.0 context, the output color is broadcast to all channels
1133 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1134 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1135
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001136 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001137 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001138 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001139
1140 return false;
1141 }
1142
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001143 vertexShader->resetVaryingsRegisterAssignment();
1144
Jamie Madillce79dda2013-08-30 13:21:06 -04001145 for (unsigned int fragVaryingIndex = 0; fragVaryingIndex < fragmentShader->mVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001146 {
Jamie Madillce79dda2013-08-30 13:21:06 -04001147 Varying *input = &fragmentShader->mVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001148 bool matched = false;
1149
Jamie Madillce79dda2013-08-30 13:21:06 -04001150 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001151 {
Jamie Madillce79dda2013-08-30 13:21:06 -04001152 Varying *output = &vertexShader->mVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001153 if (output->name == input->name)
1154 {
Jamie Madill139b9092013-08-30 13:21:06 -04001155 if (output->type != input->type || output->arraySize != input->arraySize || 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
Jamie Madill139b9092013-08-30 13:21:06 -04001162 output->registerIndex = input->registerIndex;
1163 output->elementIndex = input->elementIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001164
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";
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001182 std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001183
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001184 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1185
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001186 // special varyings that use reserved registers
1187 int reservedRegisterIndex = registers;
1188 std::string fragCoordSemantic;
1189 std::string pointCoordSemantic;
1190
1191 if (fragmentShader->mUsesFragCoord)
1192 {
1193 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1194 }
1195
1196 if (fragmentShader->mUsesPointCoord)
1197 {
1198 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1199 // In DX11 we compute this in the GS.
1200 if (shaderModel == 3)
1201 {
1202 pointCoordSemantic = "TEXCOORD0";
1203 }
1204 else if (shaderModel >= 4)
1205 {
1206 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1207 }
1208 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001209
1210 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001211 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001212
1213 int semanticIndex = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001214 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
Jamie Madilldefb6742013-06-20 11:55:51 -04001215 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001216 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001217 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilldefb6742013-06-20 11:55:51 -04001218 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1219 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001220
Jamie Madilldefb6742013-06-20 11:55:51 -04001221 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001222 }
1223
1224 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001225 "\n"
1226 "struct VS_OUTPUT\n"
1227 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001228
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001229 if (shaderModel < 4)
1230 {
1231 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1232 }
1233
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001234 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001235
1236 if (fragmentShader->mUsesFragCoord)
1237 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001238 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239 }
1240
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001241 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242 {
1243 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1244 }
1245
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001246 if (shaderModel >= 4)
1247 {
1248 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1249 }
1250
1251 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001252 "\n"
1253 "VS_OUTPUT main(VS_INPUT input)\n"
1254 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001255
Jamie Madilldefb6742013-06-20 11:55:51 -04001256 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001257 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001258 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1259 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001260
Jamie Madilldefb6742013-06-20 11:55:51 -04001261 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262 {
1263 vertexHLSL += "transpose";
1264 }
1265
Jamie Madilldefb6742013-06-20 11:55:51 -04001266 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001267 }
1268
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001269 if (shaderModel >= 4)
1270 {
1271 vertexHLSL += "\n"
1272 " gl_main();\n"
1273 "\n"
1274 " VS_OUTPUT output;\n"
1275 " output.gl_Position.x = gl_Position.x;\n"
1276 " output.gl_Position.y = -gl_Position.y;\n"
1277 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1278 " output.gl_Position.w = gl_Position.w;\n";
1279 }
1280 else
1281 {
1282 vertexHLSL += "\n"
1283 " gl_main();\n"
1284 "\n"
1285 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001286 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1287 " 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 +00001288 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1289 " output.gl_Position.w = gl_Position.w;\n";
1290 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001291
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001292 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001293 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001294 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295 }
1296
1297 if (fragmentShader->mUsesFragCoord)
1298 {
1299 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1300 }
1301
Jamie Madillce79dda2013-08-30 13:21:06 -04001302 for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001303 {
Jamie Madillce79dda2013-08-30 13:21:06 -04001304 Varying *varying = &vertexShader->mVaryings[vertVaryingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001305 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001306 {
Jamie Madill139b9092013-08-30 13:21:06 -04001307 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001308 {
Jamie Madill139b9092013-08-30 13:21:06 -04001309 int variableRows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310
Jamie Madill139b9092013-08-30 13:21:06 -04001311 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001312 {
Jamie Madill139b9092013-08-30 13:21:06 -04001313 int r = varying->registerIndex + elementIndex * variableRows + row;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314 vertexHLSL += " output.v" + str(r);
1315
1316 bool sharedRegister = false; // Register used by multiple varyings
1317
1318 for (int x = 0; x < 4; x++)
1319 {
1320 if (packing[r][x] && packing[r][x] != packing[r][0])
1321 {
1322 sharedRegister = true;
1323 break;
1324 }
1325 }
1326
1327 if(sharedRegister)
1328 {
1329 vertexHLSL += ".";
1330
1331 for (int x = 0; x < 4; x++)
1332 {
1333 if (packing[r][x] == &*varying)
1334 {
1335 switch(x)
1336 {
1337 case 0: vertexHLSL += "x"; break;
1338 case 1: vertexHLSL += "y"; break;
1339 case 2: vertexHLSL += "z"; break;
1340 case 3: vertexHLSL += "w"; break;
1341 }
1342 }
1343 }
1344 }
1345
Jamie Madill139b9092013-08-30 13:21:06 -04001346 vertexHLSL += " = _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001347
Jamie Madill139b9092013-08-30 13:21:06 -04001348 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349 {
Jamie Madill139b9092013-08-30 13:21:06 -04001350 vertexHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001351 }
1352
Jamie Madill139b9092013-08-30 13:21:06 -04001353 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001354 {
Jamie Madill139b9092013-08-30 13:21:06 -04001355 vertexHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001356 }
1357
1358 vertexHLSL += ";\n";
1359 }
1360 }
1361 }
1362 }
1363
1364 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001365 " return output;\n"
1366 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001367
1368 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001369 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001370
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001371 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001372
1373 if (fragmentShader->mUsesFragCoord)
1374 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001375 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001376 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001377
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001378 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1379 {
1380 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1381 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001382
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001383 // Must consume the PSIZE element if the geometry shader is not active
1384 // We won't know if we use a GS until we draw
1385 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1386 {
1387 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1388 }
1389
1390 if (fragmentShader->mUsesFragCoord)
1391 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001392 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001393 {
1394 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1395 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001396 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001397 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001398 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1399 }
1400 }
1401
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001402 pixelHLSL += "};\n"
1403 "\n"
1404 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001405 "{\n";
1406
Jamie Madill46131a32013-06-20 11:55:50 -04001407 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001408 {
Jamie Madill46131a32013-06-20 11:55:50 -04001409 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1410 {
1411 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1412 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001413
1414 if (fragmentShader->mUsesFragDepth)
1415 {
1416 pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
1417 }
Jamie Madill46131a32013-06-20 11:55:50 -04001418 }
1419 else
1420 {
1421 defineOutputVariables(fragmentShader);
1422
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001423 const std::vector<sh::Attribute> &outputVars = fragmentShader->getOutputVariables();
Jamie Madill46131a32013-06-20 11:55:50 -04001424 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1425 {
1426 const VariableLocation &outputLocation = locationIt->second;
1427 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1428 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1429
1430 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1431 " out_" + outputLocation.name + elementString +
1432 " : " + targetSemantic + str(locationIt->first) + ";\n";
1433 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001434 }
1435
1436 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001437 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001438
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001439 if (fragmentShader->mUsesFrontFacing)
1440 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001441 if (shaderModel >= 4)
1442 {
1443 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1444 "{\n";
1445 }
1446 else
1447 {
1448 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1449 "{\n";
1450 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001452 else
1453 {
1454 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1455 "{\n";
1456 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001457
1458 if (fragmentShader->mUsesFragCoord)
1459 {
1460 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1461
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001462 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001463 {
1464 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1465 " gl_FragCoord.y = input.dx_VPos.y;\n";
1466 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001467 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001468 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001469 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001470 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001471 }
1472 else
1473 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001474 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1475 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1476 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001477 }
1478
daniel@transgaming.com12985182012-12-20 20:56:31 +00001479 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001480 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001481 }
1482
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001483 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001484 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001485 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1486 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001487 }
1488
1489 if (fragmentShader->mUsesFrontFacing)
1490 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001491 if (shaderModel <= 3)
1492 {
1493 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1494 }
1495 else
1496 {
1497 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1498 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001499 }
1500
Jamie Madillce79dda2013-08-30 13:21:06 -04001501 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001502 {
Jamie Madillce79dda2013-08-30 13:21:06 -04001503 Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001504 if (varying->registerAssigned())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001505 {
Jamie Madill139b9092013-08-30 13:21:06 -04001506 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001507 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001508 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill139b9092013-08-30 13:21:06 -04001509 int variableRows = VariableRowCount(transposedType);
1510 for (int row = 0; row < variableRows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001511 {
Jamie Madill139b9092013-08-30 13:21:06 -04001512 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
1513 pixelHLSL += " _" + varying->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001514
Jamie Madill139b9092013-08-30 13:21:06 -04001515 if (varying->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001516 {
Jamie Madill139b9092013-08-30 13:21:06 -04001517 pixelHLSL += arrayString(elementIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001518 }
1519
Jamie Madill139b9092013-08-30 13:21:06 -04001520 if (variableRows > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001521 {
Jamie Madill139b9092013-08-30 13:21:06 -04001522 pixelHLSL += arrayString(row);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001523 }
1524
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001525 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001526 {
1527 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1528 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1529 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1530 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1531 default: UNREACHABLE();
1532 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001533 }
1534 }
1535 }
1536 else UNREACHABLE();
1537 }
1538
1539 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001540 " gl_main();\n"
1541 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001542 " PS_OUTPUT output;\n";
1543
Jamie Madill46131a32013-06-20 11:55:50 -04001544 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001545 {
Jamie Madill46131a32013-06-20 11:55:50 -04001546 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1547 {
1548 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001549
Jamie Madill46131a32013-06-20 11:55:50 -04001550 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1551 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001552
1553 if (fragmentShader->mUsesFragDepth)
1554 {
1555 pixelHLSL += " output.gl_Depth = gl_Depth;\n";
1556 }
Jamie Madill46131a32013-06-20 11:55:50 -04001557 }
1558 else
1559 {
1560 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1561 {
1562 const VariableLocation &outputLocation = locationIt->second;
1563 const std::string &variableName = "out_" + outputLocation.name;
1564 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1565 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1566
1567 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1568 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001569 }
1570
1571 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001572 " return output;\n"
1573 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001574
1575 return true;
1576}
1577
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001578std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1579{
1580 std::string varyingHLSL;
1581
Jamie Madillce79dda2013-08-30 13:21:06 -04001582 for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001583 {
Jamie Madillce79dda2013-08-30 13:21:06 -04001584 Varying *varying = &fragmentShader->mVaryings[varyingIndex];
Jamie Madill139b9092013-08-30 13:21:06 -04001585 if (varying->registerAssigned())
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001586 {
Jamie Madill139b9092013-08-30 13:21:06 -04001587 for (unsigned int elementIndex = 0; elementIndex < varying->elementCount(); elementIndex++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001588 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001589 GLenum transposedType = TransposeMatrixType(varying->type);
Jamie Madill139b9092013-08-30 13:21:06 -04001590 int variableRows = VariableRowCount(transposedType);
1591 for (int row = 0; row < variableRows; row++)
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001592 {
1593 switch (varying->interpolation)
1594 {
Jamie Madill139b9092013-08-30 13:21:06 -04001595 case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break;
1596 case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break;
1597 case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break;
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001598 default: UNREACHABLE();
1599 }
1600
Jamie Madill139b9092013-08-30 13:21:06 -04001601 std::string n = str(varying->registerIndex + elementIndex * variableRows + row);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001602 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001603
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001604 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001605 }
1606 }
1607 }
1608 else UNREACHABLE();
1609 }
1610
1611 return varyingHLSL;
1612}
1613
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1615{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001616 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617
1618 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001619 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001620 if (format != GL_PROGRAM_BINARY_ANGLE)
1621 {
1622 infoLog.append("Invalid program binary format.");
1623 return false;
1624 }
1625
1626 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001627 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001628 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629 {
1630 infoLog.append("Invalid program binary version.");
1631 return false;
1632 }
1633
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001634 int compileFlags = 0;
1635 stream.read(&compileFlags);
1636 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1637 {
1638 infoLog.append("Mismatched compilation flags.");
1639 return false;
1640 }
1641
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001642 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1643 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001644 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001645 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001646 stream.read(&name);
1647 mLinkedAttribute[i].name = name;
1648 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649 }
1650
1651 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1652 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001653 stream.read(&mSamplersPS[i].active);
1654 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655
1656 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001657 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001658 mSamplersPS[i].textureType = (TextureType) textureType;
1659 }
1660
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001661 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&mSamplersVS[i].active);
1664 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665
1666 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001668 mSamplersVS[i].textureType = (TextureType) textureType;
1669 }
1670
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 stream.read(&mUsedVertexSamplerRange);
1672 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001673 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001674 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001676 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001677 stream.read(&size);
1678 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 {
1680 infoLog.append("Invalid program binary.");
1681 return false;
1682 }
1683
1684 mUniforms.resize(size);
1685 for (unsigned int i = 0; i < size; ++i)
1686 {
1687 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001688 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001689 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001690 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001691 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001692
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001693 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001694 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001695 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001696 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001697 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001698
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001699 int offset;
1700 int arrayStride;
1701 int matrixStride;
1702 bool isRowMajorMatrix;
1703
1704 stream.read(&offset);
1705 stream.read(&arrayStride);
1706 stream.read(&matrixStride);
1707 stream.read(&isRowMajorMatrix);
1708
1709 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1710
1711 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001713 stream.read(&mUniforms[i]->psRegisterIndex);
1714 stream.read(&mUniforms[i]->vsRegisterIndex);
1715 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001716 }
1717
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001718 stream.read(&size);
1719 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001720 {
1721 infoLog.append("Invalid program binary.");
1722 return false;
1723 }
1724
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001725 mUniformBlocks.resize(size);
1726 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1727 {
1728 std::string name;
1729 unsigned int elementIndex;
1730 unsigned int dataSize;
1731
1732 stream.read(&name);
1733 stream.read(&elementIndex);
1734 stream.read(&dataSize);
1735
1736 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1737
1738 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1739 stream.read(&uniformBlock.psRegisterIndex);
1740 stream.read(&uniformBlock.vsRegisterIndex);
1741
1742 size_t numMembers;
1743 stream.read(&numMembers);
1744 uniformBlock.memberUniformIndexes.resize(numMembers);
1745 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1746 {
1747 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1748 }
1749 }
1750
1751 stream.read(&size);
1752 if (stream.error())
1753 {
1754 infoLog.append("Invalid program binary.");
1755 return false;
1756 }
1757
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758 mUniformIndex.resize(size);
1759 for (unsigned int i = 0; i < size; ++i)
1760 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001761 stream.read(&mUniformIndex[i].name);
1762 stream.read(&mUniformIndex[i].element);
1763 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764 }
1765
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001766 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001768
1769 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001770 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001772 unsigned int geometryShaderSize;
1773 stream.read(&geometryShaderSize);
1774
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001775 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776
daniel@transgaming.com36038542012-11-28 20:59:26 +00001777 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778 ptr += sizeof(GUID);
1779
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001780 GUID identifier = mRenderer->getAdapterIdentifier();
1781 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001782 {
1783 infoLog.append("Invalid program binary.");
1784 return false;
1785 }
1786
1787 const char *pixelShaderFunction = ptr;
1788 ptr += pixelShaderSize;
1789
1790 const char *vertexShaderFunction = ptr;
1791 ptr += vertexShaderSize;
1792
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001793 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1794 ptr += geometryShaderSize;
1795
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001796 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001797 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001798 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001799 {
1800 infoLog.append("Could not create pixel shader.");
1801 return false;
1802 }
1803
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001804 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001805 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001806 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001807 {
1808 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001809 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001810 mPixelExecutable = NULL;
1811 return false;
1812 }
1813
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001814 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1815 {
1816 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1817 geometryShaderSize, rx::SHADER_GEOMETRY);
1818 if (!mGeometryExecutable)
1819 {
1820 infoLog.append("Could not create geometry shader.");
1821 delete mPixelExecutable;
1822 mPixelExecutable = NULL;
1823 delete mVertexExecutable;
1824 mVertexExecutable = NULL;
1825 return false;
1826 }
1827 }
1828 else
1829 {
1830 mGeometryExecutable = NULL;
1831 }
1832
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001833 return true;
1834}
1835
1836bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1837{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001838 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001839
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001840 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001841 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001842 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001843
1844 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1845 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001846 stream.write(mLinkedAttribute[i].type);
1847 stream.write(mLinkedAttribute[i].name);
1848 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001849 }
1850
1851 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1852 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001853 stream.write(mSamplersPS[i].active);
1854 stream.write(mSamplersPS[i].logicalTextureUnit);
1855 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001856 }
1857
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001858 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001859 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001860 stream.write(mSamplersVS[i].active);
1861 stream.write(mSamplersVS[i].logicalTextureUnit);
1862 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001863 }
1864
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001865 stream.write(mUsedVertexSamplerRange);
1866 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001867 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001868 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001869
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001870 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001871 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001872 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001873 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001874
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001875 stream.write(uniform.type);
1876 stream.write(uniform.precision);
1877 stream.write(uniform.name);
1878 stream.write(uniform.arraySize);
1879 stream.write(uniform.blockIndex);
1880
1881 stream.write(uniform.blockInfo.offset);
1882 stream.write(uniform.blockInfo.arrayStride);
1883 stream.write(uniform.blockInfo.matrixStride);
1884 stream.write(uniform.blockInfo.isRowMajorMatrix);
1885
1886 stream.write(uniform.psRegisterIndex);
1887 stream.write(uniform.vsRegisterIndex);
1888 stream.write(uniform.registerCount);
1889 }
1890
1891 stream.write(mUniformBlocks.size());
1892 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1893 {
1894 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1895
1896 stream.write(uniformBlock.name);
1897 stream.write(uniformBlock.elementIndex);
1898 stream.write(uniformBlock.dataSize);
1899
1900 stream.write(uniformBlock.memberUniformIndexes.size());
1901 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1902 {
1903 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1904 }
1905
1906 stream.write(uniformBlock.psRegisterIndex);
1907 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001908 }
1909
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001910 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001911 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1912 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001913 stream.write(mUniformIndex[i].name);
1914 stream.write(mUniformIndex[i].element);
1915 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001916 }
1917
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001918 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001919 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001920
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001921 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001922 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001923
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001924 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1925 stream.write(geometryShaderSize);
1926
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001927 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001928
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001929 GLsizei streamLength = stream.length();
1930 const void *streamData = stream.data();
1931
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001932 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001933 if (totalLength > bufSize)
1934 {
1935 if (length)
1936 {
1937 *length = 0;
1938 }
1939
1940 return false;
1941 }
1942
1943 if (binary)
1944 {
1945 char *ptr = (char*) binary;
1946
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001947 memcpy(ptr, streamData, streamLength);
1948 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001949
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001950 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001951 ptr += sizeof(GUID);
1952
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001953 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001954 ptr += pixelShaderSize;
1955
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001956 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001957 ptr += vertexShaderSize;
1958
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001959 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1960 {
1961 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1962 ptr += geometryShaderSize;
1963 }
1964
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001965 ASSERT(ptr - totalLength == binary);
1966 }
1967
1968 if (length)
1969 {
1970 *length = totalLength;
1971 }
1972
1973 return true;
1974}
1975
1976GLint ProgramBinary::getLength()
1977{
1978 GLint length;
1979 if (save(NULL, INT_MAX, &length))
1980 {
1981 return length;
1982 }
1983 else
1984 {
1985 return 0;
1986 }
1987}
1988
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001989bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001990{
1991 if (!fragmentShader || !fragmentShader->isCompiled())
1992 {
1993 return false;
1994 }
1995
1996 if (!vertexShader || !vertexShader->isCompiled())
1997 {
1998 return false;
1999 }
2000
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00002001 mShaderVersion = vertexShader->getShaderVersion();
2002
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002003 std::string pixelHLSL = fragmentShader->getHLSL();
2004 std::string vertexHLSL = vertexShader->getHLSL();
2005
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002006 // Map the varyings to the register file
2007 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
2008 int registers = packVaryings(infoLog, packing, fragmentShader);
2009
2010 if (registers < 0)
2011 {
2012 return false;
2013 }
2014
2015 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002016 {
2017 return false;
2018 }
2019
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002020 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002021
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002022 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2023 {
2024 success = false;
2025 }
2026
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002027 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002028 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002029 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002030 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002031
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002032 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2033 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2034 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002035 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2036 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2037 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 +00002038 }
2039
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002040 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2041 {
2042 success = false;
2043 }
2044
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002045 if (success)
2046 {
2047 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
2048 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
2049
2050 if (usesGeometryShader())
2051 {
2052 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2053 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2054 }
2055
2056 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
2057 {
2058 infoLog.append("Failed to create D3D shaders.");
2059 success = false;
2060
2061 delete mVertexExecutable;
2062 mVertexExecutable = NULL;
2063 delete mPixelExecutable;
2064 mPixelExecutable = NULL;
2065 delete mGeometryExecutable;
2066 mGeometryExecutable = NULL;
2067 }
2068 }
2069
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002070 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071}
2072
2073// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002074bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002075{
2076 unsigned int usedLocations = 0;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002077 const std::vector<sh::Attribute> &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002078
2079 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002080 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002081 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002082 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002083 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084
Jamie Madilleba4eff2013-06-20 11:55:51 -04002085 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002086 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002087 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002088
2089 if (rows + location > MAX_VERTEX_ATTRIBS)
2090 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002091 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 +00002092
2093 return false;
2094 }
2095
Jamie Madilleba4eff2013-06-20 11:55:51 -04002096 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002098 const int rowLocation = location + row;
2099 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2100
2101 // In GLSL 3.00, attribute aliasing produces a link error
2102 // In GLSL 1.00, attribute aliasing is allowed
2103 if (mShaderVersion >= 300)
2104 {
2105 if (!linkedAttribute.name.empty())
2106 {
2107 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2108 return false;
2109 }
2110 }
2111
2112 linkedAttribute = attribute;
2113 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002114 }
2115 }
2116 }
2117
2118 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002119 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002120 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002121 const sh::Attribute &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002122 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002123
Jamie Madilleba4eff2013-06-20 11:55:51 -04002124 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002125 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002126 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002127 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2128
2129 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2130 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002131 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002132
2133 return false; // Fail to link
2134 }
2135
Jamie Madilldefb6742013-06-20 11:55:51 -04002136 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002137 }
2138 }
2139
2140 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2141 {
2142 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002143 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002144
2145 for (int r = 0; r < rows; r++)
2146 {
2147 mSemanticIndex[attributeIndex++] = index++;
2148 }
2149 }
2150
2151 return true;
2152}
2153
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002154bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002155{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002156 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002157 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002158 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002159 return false;
2160 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002161 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002162 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002163 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002164 return false;
2165 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002166 if (vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002167 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002168 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04002169 return false;
2170 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002171
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002172 return true;
2173}
2174
2175template <class ShaderVarType>
2176bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
2177{
2178 if (vertexVar.fields.size() != fragmentVar.fields.size())
2179 {
2180 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
2181 return false;
2182 }
2183 const unsigned int numMembers = vertexVar.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002184 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2185 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002186 const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
2187 const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002188
2189 if (vertexMember.name != fragmentMember.name)
2190 {
2191 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002192 memberIndex, varName.c_str(), vertexVar.name.c_str(), fragmentVar.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002193 return false;
2194 }
2195
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002196 const std::string memberName = varName + "." + vertexVar.name;
2197 if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002198 {
2199 return false;
2200 }
2201 }
2202
2203 return true;
2204}
2205
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002206bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2207{
2208 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform))
2209 {
2210 return false;
2211 }
2212
2213 if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
2214 {
2215 return false;
2216 }
2217
2218 return true;
2219}
2220
2221bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
2222{
2223 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform))
2224 {
2225 return false;
2226 }
2227
2228 if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2229 {
2230 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2231 return false;
2232 }
2233
2234 if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
2235 {
2236 return false;
2237 }
2238
2239 return true;
2240}
2241
2242bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002243{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002244 // Check that uniforms defined in the vertex and fragment shaders are identical
2245 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2246 UniformMap linkedUniforms;
2247
2248 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2249 {
2250 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2251 linkedUniforms[vertexUniform.name] = &vertexUniform;
2252 }
2253
2254 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2255 {
2256 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2257 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2258 if (entry != linkedUniforms.end())
2259 {
2260 const sh::Uniform &vertexUniform = *entry->second;
2261 const std::string &uniformName = "uniform " + vertexUniform.name;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002262 if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002263 {
2264 return false;
2265 }
2266 }
2267 }
2268
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002269 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002270 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002271 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002272 {
2273 return false;
2274 }
2275 }
2276
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002277 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002278 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002279 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002280 {
2281 return false;
2282 }
2283 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002284
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002285 return true;
2286}
2287
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002288int totalRegisterCount(const sh::Uniform &uniform)
2289{
2290 int registerCount = 0;
2291
2292 if (!uniform.fields.empty())
2293 {
2294 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2295 {
2296 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2297 }
2298 }
2299 else
2300 {
2301 registerCount = 1;
2302 }
2303
2304 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2305}
2306
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002307TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
2308{
2309 switch(samplerType)
2310 {
2311 case GL_SAMPLER_2D:
2312 case GL_INT_SAMPLER_2D:
2313 case GL_UNSIGNED_INT_SAMPLER_2D:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002314 case GL_SAMPLER_2D_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002315 return TEXTURE_2D;
2316 case GL_SAMPLER_3D:
2317 case GL_INT_SAMPLER_3D:
2318 case GL_UNSIGNED_INT_SAMPLER_3D:
2319 return TEXTURE_3D;
2320 case GL_SAMPLER_CUBE:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002321 case GL_SAMPLER_CUBE_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002322 return TEXTURE_CUBE;
2323 case GL_INT_SAMPLER_CUBE:
2324 case GL_UNSIGNED_INT_SAMPLER_CUBE:
2325 //UNIMPLEMENTED();
2326 infoLog.append("Integer cube texture sampling is currently not supported by ANGLE and returns a black color.");
2327 return TEXTURE_CUBE;
2328 case GL_SAMPLER_2D_ARRAY:
2329 case GL_INT_SAMPLER_2D_ARRAY:
2330 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
Nicolas Capenscb127d32013-07-15 17:26:18 -04002331 case GL_SAMPLER_2D_ARRAY_SHADOW:
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002332 return TEXTURE_2D_ARRAY;
2333 default: UNREACHABLE();
2334 }
2335
2336 return TEXTURE_2D;
2337}
2338
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002339bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002340{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002341 if (!constant.fields.empty())
2342 {
2343 if (constant.arraySize > 0)
2344 {
2345 unsigned int elementRegisterIndex = constant.registerIndex;
2346
2347 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2348 {
2349 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2350 {
2351 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002352 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002353 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002354 if (!defineUniform(shader, fieldUniform, infoLog))
2355 {
2356 return false;
2357 }
2358 elementRegisterIndex += totalRegisterCount(field);
2359 }
2360 }
2361 }
2362 else
2363 {
2364 unsigned int fieldRegisterIndex = constant.registerIndex;
2365
2366 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2367 {
2368 const sh::Uniform &field = constant.fields[fieldIndex];
2369 const std::string &uniformName = constant.name + "." + field.name;
2370
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002371 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002372 fieldUniform.fields = field.fields;
2373
2374 if (!defineUniform(shader, fieldUniform, infoLog))
2375 {
2376 return false;
2377 }
2378 fieldRegisterIndex += totalRegisterCount(field);
2379 }
2380 }
2381
2382 return true;
2383 }
2384
Nicolas Capense6050882013-07-08 10:43:10 -04002385 if (IsSampler(constant.type))
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002386 {
2387 unsigned int samplerIndex = constant.registerIndex;
2388
2389 do
2390 {
2391 if (shader == GL_VERTEX_SHADER)
2392 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002393 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002394 {
2395 mSamplersVS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002396 mSamplersVS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002397 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2398 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2399 }
2400 else
2401 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002402 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002403 return false;
2404 }
2405 }
2406 else if (shader == GL_FRAGMENT_SHADER)
2407 {
2408 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2409 {
2410 mSamplersPS[samplerIndex].active = true;
Nicolas Capens43e8ba82013-07-09 10:35:15 -04002411 mSamplersPS[samplerIndex].textureType = getTextureType(constant.type, infoLog);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002412 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2413 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2414 }
2415 else
2416 {
2417 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2418 return false;
2419 }
2420 }
2421 else UNREACHABLE();
2422
2423 samplerIndex++;
2424 }
2425 while (samplerIndex < constant.registerIndex + constant.arraySize);
2426 }
2427
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002428 Uniform *uniform = NULL;
2429 GLint location = getUniformLocation(constant.name);
2430
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002431 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002432 {
2433 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002434 }
2435 else
2436 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002437 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002438 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002439
2440 if (!uniform)
2441 {
2442 return false;
2443 }
2444
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002445 if (shader == GL_FRAGMENT_SHADER)
2446 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002447 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002448 }
2449 else if (shader == GL_VERTEX_SHADER)
2450 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002451 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002452 }
2453 else UNREACHABLE();
2454
2455 if (location >= 0)
2456 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002457 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002458 }
2459
2460 mUniforms.push_back(uniform);
2461 unsigned int uniformIndex = mUniforms.size() - 1;
2462
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002463 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002464 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002465 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002466 }
2467
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002468 if (shader == GL_VERTEX_SHADER)
2469 {
2470 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2471 {
2472 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2473 return false;
2474 }
2475 }
2476 else if (shader == GL_FRAGMENT_SHADER)
2477 {
2478 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2479 {
2480 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2481 return false;
2482 }
2483 }
2484 else UNREACHABLE();
2485
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002486 return true;
2487}
2488
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002489bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2490{
2491 const char* blockName = vertexInterfaceBlock.name.c_str();
2492
2493 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002494 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002495 {
2496 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2497 return false;
2498 }
2499
2500 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2501 {
2502 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2503 return false;
2504 }
2505
Jamie Madill9060a4e2013-08-12 16:22:57 -07002506 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2507 {
2508 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2509 return false;
2510 }
2511
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002512 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002513 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2514 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002515 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2516 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002517
2518 if (vertexMember.name != fragmentMember.name)
2519 {
2520 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2521 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2522 return false;
2523 }
2524
2525 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002526 if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002527 {
2528 return false;
2529 }
2530 }
2531
2532 return true;
2533}
2534
2535bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2536{
2537 // Check that interface blocks defined in the vertex and fragment shaders are identical
2538 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2539 UniformBlockMap linkedUniformBlocks;
2540
2541 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2542 {
2543 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2544 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2545 }
2546
2547 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2548 {
2549 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2550 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2551 if (entry != linkedUniformBlocks.end())
2552 {
2553 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2554 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2555 {
2556 return false;
2557 }
2558 }
2559 }
2560
2561 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2562 {
2563 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2564 {
2565 return false;
2566 }
2567 }
2568
2569 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2570 {
2571 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2572 {
2573 return false;
2574 }
2575 }
2576
2577 return true;
2578}
2579
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002580void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002581{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002582 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002583 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002584 const sh::InterfaceBlockField &field = fields[uniformIndex];
2585 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002586
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002587 if (!field.fields.empty())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002588 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002589 if (field.arraySize > 0)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002590 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002591 for (unsigned int arrayElement = 0; arrayElement < field.arraySize; arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002592 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002593 const std::string uniformElementName = fieldName + arrayString(arrayElement);
2594 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002595 }
2596 }
2597 else
2598 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002599 defineUniformBlockMembers(field.fields, fieldName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002600 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002601 }
2602 else
2603 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002604 Uniform *newUniform = new Uniform(field.type, field.precision, fieldName, field.arraySize,
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002605 blockIndex, **blockInfoItr);
2606
2607 // add to uniform list, but not index, since uniform block uniforms have no location
2608 blockUniformIndexes->push_back(mUniforms.size());
2609 mUniforms.push_back(newUniform);
2610 (*blockInfoItr)++;
2611 }
2612 }
2613}
2614
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002615bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2616{
2617 // create uniform block entries if they do not exist
2618 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2619 {
2620 std::vector<unsigned int> blockUniformIndexes;
2621 const unsigned int blockIndex = mUniformBlocks.size();
2622
2623 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002624 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002625 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002626
2627 // create all the uniform blocks
2628 if (interfaceBlock.arraySize > 0)
2629 {
2630 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2631 {
2632 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2633 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2634 mUniformBlocks.push_back(newUniformBlock);
2635 }
2636 }
2637 else
2638 {
2639 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2640 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2641 mUniformBlocks.push_back(newUniformBlock);
2642 }
2643 }
2644
2645 // Assign registers to the uniform blocks
2646 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2647 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2648 ASSERT(blockIndex != GL_INVALID_INDEX);
2649 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2650
2651 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2652 {
2653 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2654 ASSERT(uniformBlock->name == interfaceBlock.name);
2655
2656 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2657 {
2658 return false;
2659 }
2660 }
2661
2662 return true;
2663}
2664
2665bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2666{
2667 if (shader == GL_VERTEX_SHADER)
2668 {
2669 uniformBlock->vsRegisterIndex = registerIndex;
2670 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2671
2672 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2673 {
2674 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2675 return false;
2676 }
2677 }
2678 else if (shader == GL_FRAGMENT_SHADER)
2679 {
2680 uniformBlock->psRegisterIndex = registerIndex;
2681 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2682
2683 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2684 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002685 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002686 return false;
2687 }
2688 }
2689 else UNREACHABLE();
2690
2691 return true;
2692}
2693
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002694std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2695{
2696 // for now we only handle point sprite emulation
2697 ASSERT(usesPointSpriteEmulation());
2698 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2699}
2700
2701std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2702{
2703 ASSERT(registers >= 0);
2704 ASSERT(vertexShader->mUsesPointSize);
2705 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2706
2707 std::string geomHLSL;
2708
2709 std::string varyingSemantic = "TEXCOORD";
2710
2711 std::string fragCoordSemantic;
2712 std::string pointCoordSemantic;
2713
2714 int reservedRegisterIndex = registers;
2715
2716 if (fragmentShader->mUsesFragCoord)
2717 {
2718 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2719 }
2720
2721 if (fragmentShader->mUsesPointCoord)
2722 {
2723 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2724 }
2725
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002726 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2727 "\n"
2728 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002729 "{\n";
2730
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002731 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002732
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002733 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002734
2735 if (fragmentShader->mUsesFragCoord)
2736 {
2737 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2738 }
2739
2740 geomHLSL += " float gl_PointSize : PSIZE;\n"
2741 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002742 "};\n"
2743 "\n"
2744 "struct GS_OUTPUT\n"
2745 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002746
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002747 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002748
2749 if (fragmentShader->mUsesFragCoord)
2750 {
2751 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2752 }
2753
2754 if (fragmentShader->mUsesPointCoord)
2755 {
2756 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2757 }
2758
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002759 geomHLSL += " float gl_PointSize : PSIZE;\n"
2760 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002761 "};\n"
2762 "\n"
2763 "static float2 pointSpriteCorners[] = \n"
2764 "{\n"
2765 " float2( 0.5f, -0.5f),\n"
2766 " float2( 0.5f, 0.5f),\n"
2767 " float2(-0.5f, -0.5f),\n"
2768 " float2(-0.5f, 0.5f)\n"
2769 "};\n"
2770 "\n"
2771 "static float2 pointSpriteTexcoords[] = \n"
2772 "{\n"
2773 " float2(1.0f, 1.0f),\n"
2774 " float2(1.0f, 0.0f),\n"
2775 " float2(0.0f, 1.0f),\n"
2776 " float2(0.0f, 0.0f)\n"
2777 "};\n"
2778 "\n"
2779 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2780 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2781 "\n"
2782 "[maxvertexcount(4)]\n"
2783 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2784 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002785 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2786 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002787
2788 for (int r = 0; r < registers; r++)
2789 {
2790 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2791 }
2792
2793 if (fragmentShader->mUsesFragCoord)
2794 {
2795 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2796 }
2797
2798 geomHLSL += " \n"
2799 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2800 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002801 " 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 +00002802
2803 for (int corner = 0; corner < 4; corner++)
2804 {
2805 geomHLSL += " \n"
2806 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2807
2808 if (fragmentShader->mUsesPointCoord)
2809 {
2810 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2811 }
2812
2813 geomHLSL += " outStream.Append(output);\n";
2814 }
2815
2816 geomHLSL += " \n"
2817 " outStream.RestartStrip();\n"
2818 "}\n";
2819
2820 return geomHLSL;
2821}
2822
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002823// This method needs to match OutputHLSL::decorate
2824std::string ProgramBinary::decorateAttribute(const std::string &name)
2825{
2826 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2827 {
2828 return "_" + name;
2829 }
2830
2831 return name;
2832}
2833
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002834bool ProgramBinary::isValidated() const
2835{
2836 return mValidated;
2837}
2838
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002839void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002840{
2841 // Skip over inactive attributes
2842 unsigned int activeAttribute = 0;
2843 unsigned int attribute;
2844 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2845 {
2846 if (mLinkedAttribute[attribute].name.empty())
2847 {
2848 continue;
2849 }
2850
2851 if (activeAttribute == index)
2852 {
2853 break;
2854 }
2855
2856 activeAttribute++;
2857 }
2858
2859 if (bufsize > 0)
2860 {
2861 const char *string = mLinkedAttribute[attribute].name.c_str();
2862
2863 strncpy(name, string, bufsize);
2864 name[bufsize - 1] = '\0';
2865
2866 if (length)
2867 {
2868 *length = strlen(name);
2869 }
2870 }
2871
2872 *size = 1; // Always a single 'type' instance
2873
2874 *type = mLinkedAttribute[attribute].type;
2875}
2876
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002877GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002878{
2879 int count = 0;
2880
2881 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2882 {
2883 if (!mLinkedAttribute[attributeIndex].name.empty())
2884 {
2885 count++;
2886 }
2887 }
2888
2889 return count;
2890}
2891
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002892GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002893{
2894 int maxLength = 0;
2895
2896 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2897 {
2898 if (!mLinkedAttribute[attributeIndex].name.empty())
2899 {
2900 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2901 }
2902 }
2903
2904 return maxLength;
2905}
2906
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002907void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002908{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002909 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002910
2911 if (bufsize > 0)
2912 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002913 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002914
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002915 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002916 {
2917 string += "[0]";
2918 }
2919
2920 strncpy(name, string.c_str(), bufsize);
2921 name[bufsize - 1] = '\0';
2922
2923 if (length)
2924 {
2925 *length = strlen(name);
2926 }
2927 }
2928
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002929 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002930
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002931 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002932}
2933
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002934GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002935{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002936 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002937}
2938
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002939GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002940{
2941 int maxLength = 0;
2942
2943 unsigned int numUniforms = mUniforms.size();
2944 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2945 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002946 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002947 {
2948 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2949 if (mUniforms[uniformIndex]->isArray())
2950 {
2951 length += 3; // Counting in "[0]".
2952 }
2953 maxLength = std::max(length, maxLength);
2954 }
2955 }
2956
2957 return maxLength;
2958}
2959
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002960GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2961{
2962 const gl::Uniform& uniform = *mUniforms[index];
2963
2964 switch (pname)
2965 {
2966 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2967 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002968 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 +00002969 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002970
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002971 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2972 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2973 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2974 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002975
2976 default:
2977 UNREACHABLE();
2978 break;
2979 }
2980 return 0;
2981}
2982
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002983void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2984{
2985 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2986
2987 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2988
2989 if (bufSize > 0)
2990 {
2991 std::string string = uniformBlock.name;
2992
2993 if (uniformBlock.isArrayElement())
2994 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002995 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002996 }
2997
2998 strncpy(uniformBlockName, string.c_str(), bufSize);
2999 uniformBlockName[bufSize - 1] = '\0';
3000
3001 if (length)
3002 {
3003 *length = strlen(uniformBlockName);
3004 }
3005 }
3006}
3007
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003008void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
3009{
3010 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
3011
3012 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3013
3014 switch (pname)
3015 {
3016 case GL_UNIFORM_BLOCK_DATA_SIZE:
3017 *params = static_cast<GLint>(uniformBlock.dataSize);
3018 break;
3019 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00003020 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00003021 break;
3022 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
3023 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
3024 break;
3025 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
3026 {
3027 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
3028 {
3029 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
3030 }
3031 }
3032 break;
3033 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
3034 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
3035 break;
3036 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
3037 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
3038 break;
3039 default: UNREACHABLE();
3040 }
3041}
3042
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00003043GLuint ProgramBinary::getActiveUniformBlockCount() const
3044{
3045 return mUniformBlocks.size();
3046}
3047
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00003048GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
3049{
3050 unsigned int maxLength = 0;
3051
3052 unsigned int numUniformBlocks = mUniformBlocks.size();
3053 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
3054 {
3055 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
3056 if (!uniformBlock.name.empty())
3057 {
3058 const unsigned int length = uniformBlock.name.length() + 1;
3059
3060 // Counting in "[0]".
3061 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
3062
3063 maxLength = std::max(length + arrayLength, maxLength);
3064 }
3065 }
3066
3067 return maxLength;
3068}
3069
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003070void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003071{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003072 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003073 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003074 {
3075 mValidated = false;
3076 }
3077 else
3078 {
3079 mValidated = true;
3080 }
3081}
3082
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003083bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003084{
3085 // if any two active samplers in a program are of different types, but refer to the same
3086 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3087 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3088
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00003089 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003090 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003091
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003092 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003093 {
3094 textureUnitType[i] = TEXTURE_UNKNOWN;
3095 }
3096
3097 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3098 {
3099 if (mSamplersPS[i].active)
3100 {
3101 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3102
3103 if (unit >= maxCombinedTextureImageUnits)
3104 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003105 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003106 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003107 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003108 }
3109
3110 return false;
3111 }
3112
3113 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3114 {
3115 if (mSamplersPS[i].textureType != textureUnitType[unit])
3116 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003117 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003118 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003119 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003120 }
3121
3122 return false;
3123 }
3124 }
3125 else
3126 {
3127 textureUnitType[unit] = mSamplersPS[i].textureType;
3128 }
3129 }
3130 }
3131
3132 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3133 {
3134 if (mSamplersVS[i].active)
3135 {
3136 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3137
3138 if (unit >= maxCombinedTextureImageUnits)
3139 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003140 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003141 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003142 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003143 }
3144
3145 return false;
3146 }
3147
3148 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3149 {
3150 if (mSamplersVS[i].textureType != textureUnitType[unit])
3151 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003152 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003153 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003154 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003155 }
3156
3157 return false;
3158 }
3159 }
3160 else
3161 {
3162 textureUnitType[unit] = mSamplersVS[i].textureType;
3163 }
3164 }
3165 }
3166
3167 return true;
3168}
3169
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003170ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3171{
3172}
3173
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003174struct AttributeSorter
3175{
3176 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3177 : originalIndices(semanticIndices)
3178 {
3179 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3180 {
3181 indices[i] = i;
3182 }
3183
3184 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3185 }
3186
3187 bool operator()(int a, int b)
3188 {
3189 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3190 }
3191
3192 int indices[MAX_VERTEX_ATTRIBS];
3193 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3194};
3195
3196void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3197{
3198 AttributeSorter sorter(mSemanticIndex);
3199
3200 int oldIndices[MAX_VERTEX_ATTRIBS];
3201 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3202
3203 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3204 {
3205 oldIndices[i] = mSemanticIndex[i];
3206 oldTranslatedAttributes[i] = attributes[i];
3207 }
3208
3209 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3210 {
3211 int oldIndex = sorter.indices[i];
3212 sortedSemanticIndices[i] = oldIndices[oldIndex];
3213 attributes[i] = oldTranslatedAttributes[oldIndex];
3214 }
3215}
3216
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003217}