blob: 14e6c94ca4acb35f6e70894cc22675ebe6a297a8 [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"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "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"
24
daniel@transgaming.com88853c52012-12-20 20:56:40 +000025#undef near
26#undef far
27
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000028namespace gl
29{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030std::string str(int i)
31{
32 char buffer[20];
33 snprintf(buffer, sizeof(buffer), "%d", i);
34 return buffer;
35}
36
daniel@transgaming.comdb019952012-12-20 21:13:32 +000037UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
38 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000039{
40}
41
daniel@transgaming.come87ca002012-07-24 18:30:43 +000042unsigned int ProgramBinary::mCurrentSerial = 1;
43
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000044ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000045{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046 mPixelExecutable = NULL;
47 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000048 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000049
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000050 mValidated = false;
51
52 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
53 {
54 mSemanticIndex[index] = -1;
55 }
56
57 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
58 {
59 mSamplersPS[index].active = false;
60 }
61
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000062 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000063 {
64 mSamplersVS[index].active = false;
65 }
66
67 mUsedVertexSamplerRange = 0;
68 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000069 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000070}
71
72ProgramBinary::~ProgramBinary()
73{
daniel@transgaming.com95892412012-11-28 20:59:09 +000074 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000075 mPixelExecutable = NULL;
76
daniel@transgaming.com95892412012-11-28 20:59:09 +000077 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000078 mVertexExecutable = NULL;
79
80 delete mGeometryExecutable;
81 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000082
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083 while (!mUniforms.empty())
84 {
85 delete mUniforms.back();
86 mUniforms.pop_back();
87 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000088}
89
daniel@transgaming.come87ca002012-07-24 18:30:43 +000090unsigned int ProgramBinary::getSerial() const
91{
92 return mSerial;
93}
94
95unsigned int ProgramBinary::issueSerial()
96{
97 return mCurrentSerial++;
98}
99
daniel@transgaming.com95892412012-11-28 20:59:09 +0000100rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101{
102 return mPixelExecutable;
103}
104
daniel@transgaming.com95892412012-11-28 20:59:09 +0000105rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106{
107 return mVertexExecutable;
108}
109
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000110rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
111{
112 return mGeometryExecutable;
113}
114
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115GLuint ProgramBinary::getAttributeLocation(const char *name)
116{
117 if (name)
118 {
119 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
120 {
121 if (mLinkedAttribute[index].name == std::string(name))
122 {
123 return index;
124 }
125 }
126 }
127
128 return -1;
129}
130
131int ProgramBinary::getSemanticIndex(int attributeIndex)
132{
133 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
134
135 return mSemanticIndex[attributeIndex];
136}
137
138// Returns one more than the highest sampler index used.
139GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
140{
141 switch (type)
142 {
143 case SAMPLER_PIXEL:
144 return mUsedPixelSamplerRange;
145 case SAMPLER_VERTEX:
146 return mUsedVertexSamplerRange;
147 default:
148 UNREACHABLE();
149 return 0;
150 }
151}
152
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000153bool ProgramBinary::usesPointSize() const
154{
155 return mUsesPointSize;
156}
157
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000158bool ProgramBinary::usesPointSpriteEmulation() const
159{
160 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
161}
162
163bool ProgramBinary::usesGeometryShader() const
164{
165 return usesPointSpriteEmulation();
166}
167
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000168// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
169// index (0-15 for the pixel shader and 0-3 for the vertex shader).
170GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
171{
172 GLint logicalTextureUnit = -1;
173
174 switch (type)
175 {
176 case SAMPLER_PIXEL:
177 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
178
179 if (mSamplersPS[samplerIndex].active)
180 {
181 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
182 }
183 break;
184 case SAMPLER_VERTEX:
185 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
186
187 if (mSamplersVS[samplerIndex].active)
188 {
189 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
190 }
191 break;
192 default: UNREACHABLE();
193 }
194
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000195 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000196 {
197 return logicalTextureUnit;
198 }
199
200 return -1;
201}
202
203// Returns the texture type for a given Direct3D 9 sampler type and
204// index (0-15 for the pixel shader and 0-3 for the vertex shader).
205TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
206{
207 switch (type)
208 {
209 case SAMPLER_PIXEL:
210 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
211 ASSERT(mSamplersPS[samplerIndex].active);
212 return mSamplersPS[samplerIndex].textureType;
213 case SAMPLER_VERTEX:
214 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
215 ASSERT(mSamplersVS[samplerIndex].active);
216 return mSamplersVS[samplerIndex].textureType;
217 default: UNREACHABLE();
218 }
219
220 return TEXTURE_2D;
221}
222
223GLint ProgramBinary::getUniformLocation(std::string name)
224{
225 unsigned int subscript = 0;
226
227 // Strip any trailing array operator and retrieve the subscript
228 size_t open = name.find_last_of('[');
229 size_t close = name.find_last_of(']');
230 if (open != std::string::npos && close == name.length() - 1)
231 {
232 subscript = atoi(name.substr(open + 1).c_str());
233 name.erase(open);
234 }
235
236 unsigned int numUniforms = mUniformIndex.size();
237 for (unsigned int location = 0; location < numUniforms; location++)
238 {
239 if (mUniformIndex[location].name == name &&
240 mUniformIndex[location].element == subscript)
241 {
242 return location;
243 }
244 }
245
246 return -1;
247}
248
249bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
250{
251 if (location < 0 || location >= (int)mUniformIndex.size())
252 {
253 return false;
254 }
255
256 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
257 targetUniform->dirty = true;
258
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000259 int elementCount = targetUniform->elementCount();
260
261 if (elementCount == 1 && count > 1)
262 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
263
264 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
265
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000266 if (targetUniform->type == GL_FLOAT)
267 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000268 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
269
270 for (int i = 0; i < count; i++)
271 {
272 target[0] = v[0];
273 target[1] = 0;
274 target[2] = 0;
275 target[3] = 0;
276 target += 4;
277 v += 1;
278 }
279 }
280 else if (targetUniform->type == GL_BOOL)
281 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000282 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000283
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000284 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000285 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000286 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
287 boolParams[1] = GL_FALSE;
288 boolParams[2] = GL_FALSE;
289 boolParams[3] = GL_FALSE;
290 boolParams += 4;
291 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000292 }
293 }
294 else
295 {
296 return false;
297 }
298
299 return true;
300}
301
302bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
303{
304 if (location < 0 || location >= (int)mUniformIndex.size())
305 {
306 return false;
307 }
308
309 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
310 targetUniform->dirty = true;
311
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000312 int elementCount = targetUniform->elementCount();
313
314 if (elementCount == 1 && count > 1)
315 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
316
317 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
318
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000319 if (targetUniform->type == GL_FLOAT_VEC2)
320 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000321 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
322
323 for (int i = 0; i < count; i++)
324 {
325 target[0] = v[0];
326 target[1] = v[1];
327 target[2] = 0;
328 target[3] = 0;
329 target += 4;
330 v += 2;
331 }
332 }
333 else if (targetUniform->type == GL_BOOL_VEC2)
334 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000335 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000336
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000337 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000338 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000339 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
340 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
341 boolParams[2] = GL_FALSE;
342 boolParams[3] = GL_FALSE;
343 boolParams += 4;
344 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000345 }
346 }
347 else
348 {
349 return false;
350 }
351
352 return true;
353}
354
355bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
356{
357 if (location < 0 || location >= (int)mUniformIndex.size())
358 {
359 return false;
360 }
361
362 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
363 targetUniform->dirty = true;
364
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000365 int elementCount = targetUniform->elementCount();
366
367 if (elementCount == 1 && count > 1)
368 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
369
370 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
371
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372 if (targetUniform->type == GL_FLOAT_VEC3)
373 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000374 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
375
376 for (int i = 0; i < count; i++)
377 {
378 target[0] = v[0];
379 target[1] = v[1];
380 target[2] = v[2];
381 target[3] = 0;
382 target += 4;
383 v += 3;
384 }
385 }
386 else if (targetUniform->type == GL_BOOL_VEC3)
387 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000388 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000389
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000390 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000391 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000392 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
393 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
394 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
395 boolParams[3] = GL_FALSE;
396 boolParams += 4;
397 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398 }
399 }
400 else
401 {
402 return false;
403 }
404
405 return true;
406}
407
408bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
409{
410 if (location < 0 || location >= (int)mUniformIndex.size())
411 {
412 return false;
413 }
414
415 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
416 targetUniform->dirty = true;
417
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000418 int elementCount = targetUniform->elementCount();
419
420 if (elementCount == 1 && count > 1)
421 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
422
423 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
424
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000425 if (targetUniform->type == GL_FLOAT_VEC4)
426 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000427 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000428
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000429 for (int i = 0; i < count; i++)
430 {
431 target[0] = v[0];
432 target[1] = v[1];
433 target[2] = v[2];
434 target[3] = v[3];
435 target += 4;
436 v += 4;
437 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438 }
439 else if (targetUniform->type == GL_BOOL_VEC4)
440 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000441 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000442
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000443 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000444 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000445 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
446 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
447 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
448 boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
449 boolParams += 4;
450 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000451 }
452 }
453 else
454 {
455 return false;
456 }
457
458 return true;
459}
460
461template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
462void transposeMatrix(T *target, const GLfloat *value)
463{
464 int copyWidth = std::min(targetWidth, srcWidth);
465 int copyHeight = std::min(targetHeight, srcHeight);
466
467 for (int x = 0; x < copyWidth; x++)
468 {
469 for (int y = 0; y < copyHeight; y++)
470 {
471 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
472 }
473 }
474 // clear unfilled right side
475 for (int y = 0; y < copyHeight; y++)
476 {
477 for (int x = srcWidth; x < targetWidth; x++)
478 {
479 target[y * targetWidth + x] = (T)0;
480 }
481 }
482 // clear unfilled bottom.
483 for (int y = srcHeight; y < targetHeight; y++)
484 {
485 for (int x = 0; x < targetWidth; x++)
486 {
487 target[y * targetWidth + x] = (T)0;
488 }
489 }
490}
491
492bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
493{
494 if (location < 0 || location >= (int)mUniformIndex.size())
495 {
496 return false;
497 }
498
499 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
500 targetUniform->dirty = true;
501
502 if (targetUniform->type != GL_FLOAT_MAT2)
503 {
504 return false;
505 }
506
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000507 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000508
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000509 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000510 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
511
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000512 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000513 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000514
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000515 for (int i = 0; i < count; i++)
516 {
517 transposeMatrix<GLfloat,4,2,2,2>(target, value);
518 target += 8;
519 value += 4;
520 }
521
522 return true;
523}
524
525bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
526{
527 if (location < 0 || location >= (int)mUniformIndex.size())
528 {
529 return false;
530 }
531
532 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
533 targetUniform->dirty = true;
534
535 if (targetUniform->type != GL_FLOAT_MAT3)
536 {
537 return false;
538 }
539
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000540 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000541
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000542 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000543 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
544
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000545 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000546 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000547
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000548 for (int i = 0; i < count; i++)
549 {
550 transposeMatrix<GLfloat,4,3,3,3>(target, value);
551 target += 12;
552 value += 9;
553 }
554
555 return true;
556}
557
558
559bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
560{
561 if (location < 0 || location >= (int)mUniformIndex.size())
562 {
563 return false;
564 }
565
566 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
567 targetUniform->dirty = true;
568
569 if (targetUniform->type != GL_FLOAT_MAT4)
570 {
571 return false;
572 }
573
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000574 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000575
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000576 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000577 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
578
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000579 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000580 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000581
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000582 for (int i = 0; i < count; i++)
583 {
584 transposeMatrix<GLfloat,4,4,4,4>(target, value);
585 target += 16;
586 value += 16;
587 }
588
589 return true;
590}
591
592bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
593{
594 if (location < 0 || location >= (int)mUniformIndex.size())
595 {
596 return false;
597 }
598
599 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
600 targetUniform->dirty = true;
601
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000602 int elementCount = targetUniform->elementCount();
603
604 if (elementCount == 1 && count > 1)
605 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
606
607 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
608
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000609 if (targetUniform->type == GL_INT ||
610 targetUniform->type == GL_SAMPLER_2D ||
611 targetUniform->type == GL_SAMPLER_CUBE)
612 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000613 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000615 for (int i = 0; i < count; i++)
616 {
617 target[0] = v[0];
618 target[1] = 0;
619 target[2] = 0;
620 target[3] = 0;
621 target += 4;
622 v += 1;
623 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624 }
625 else if (targetUniform->type == GL_BOOL)
626 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000627 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000629 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000630 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000631 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
632 boolParams[1] = GL_FALSE;
633 boolParams[2] = GL_FALSE;
634 boolParams[3] = GL_FALSE;
635 boolParams += 4;
636 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000637 }
638 }
639 else
640 {
641 return false;
642 }
643
644 return true;
645}
646
647bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
648{
649 if (location < 0 || location >= (int)mUniformIndex.size())
650 {
651 return false;
652 }
653
654 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
655 targetUniform->dirty = true;
656
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000657 int elementCount = targetUniform->elementCount();
658
659 if (elementCount == 1 && count > 1)
660 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
661
662 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
663
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000664 if (targetUniform->type == GL_INT_VEC2)
665 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000666 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000668 for (int i = 0; i < count; i++)
669 {
670 target[0] = v[0];
671 target[1] = v[1];
672 target[2] = 0;
673 target[3] = 0;
674 target += 4;
675 v += 2;
676 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000677 }
678 else if (targetUniform->type == GL_BOOL_VEC2)
679 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000680 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000681
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000682 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000683 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000684 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
685 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
686 boolParams[2] = GL_FALSE;
687 boolParams[3] = GL_FALSE;
688 boolParams += 4;
689 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000690 }
691 }
692 else
693 {
694 return false;
695 }
696
697 return true;
698}
699
700bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
701{
702 if (location < 0 || location >= (int)mUniformIndex.size())
703 {
704 return false;
705 }
706
707 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
708 targetUniform->dirty = true;
709
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000710 int elementCount = targetUniform->elementCount();
711
712 if (elementCount == 1 && count > 1)
713 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
714
715 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
716
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000717 if (targetUniform->type == GL_INT_VEC3)
718 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000719 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000721 for (int i = 0; i < count; i++)
722 {
723 target[0] = v[0];
724 target[1] = v[1];
725 target[2] = v[2];
726 target[3] = 0;
727 target += 4;
728 v += 3;
729 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000730 }
731 else if (targetUniform->type == GL_BOOL_VEC3)
732 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000733 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000734
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000735 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000736 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000737 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
738 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
739 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
740 boolParams[3] = GL_FALSE;
741 boolParams += 4;
742 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000743 }
744 }
745 else
746 {
747 return false;
748 }
749
750 return true;
751}
752
753bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
754{
755 if (location < 0 || location >= (int)mUniformIndex.size())
756 {
757 return false;
758 }
759
760 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
761 targetUniform->dirty = true;
762
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000763 int elementCount = targetUniform->elementCount();
764
765 if (elementCount == 1 && count > 1)
766 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
767
768 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
769
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000770 if (targetUniform->type == GL_INT_VEC4)
771 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000772 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000774 for (int i = 0; i < count; i++)
775 {
776 target[0] = v[0];
777 target[1] = v[1];
778 target[2] = v[2];
779 target[3] = v[3];
780 target += 4;
781 v += 4;
782 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000783 }
784 else if (targetUniform->type == GL_BOOL_VEC4)
785 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000786 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000787
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000788 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000790 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
791 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
792 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
793 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
794 boolParams += 4;
795 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000796 }
797 }
798 else
799 {
800 return false;
801 }
802
803 return true;
804}
805
806bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
807{
808 if (location < 0 || location >= (int)mUniformIndex.size())
809 {
810 return false;
811 }
812
813 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
814
815 // sized queries -- ensure the provided buffer is large enough
816 if (bufSize)
817 {
818 int requiredBytes = UniformExternalSize(targetUniform->type);
819 if (*bufSize < requiredBytes)
820 {
821 return false;
822 }
823 }
824
825 switch (targetUniform->type)
826 {
827 case GL_FLOAT_MAT2:
828 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
829 break;
830 case GL_FLOAT_MAT3:
831 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
832 break;
833 case GL_FLOAT_MAT4:
834 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
835 break;
836 default:
837 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000838 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000839
840 switch (UniformComponentType(targetUniform->type))
841 {
842 case GL_BOOL:
843 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000844 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000845
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000846 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000847 {
848 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
849 }
850 }
851 break;
852 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000853 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
854 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000855 break;
856 case GL_INT:
857 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000858 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000859
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000860 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000861 {
862 params[i] = (float)intParams[i];
863 }
864 }
865 break;
866 default: UNREACHABLE();
867 }
868 }
869 }
870
871 return true;
872}
873
874bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
875{
876 if (location < 0 || location >= (int)mUniformIndex.size())
877 {
878 return false;
879 }
880
881 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
882
883 // sized queries -- ensure the provided buffer is large enough
884 if (bufSize)
885 {
886 int requiredBytes = UniformExternalSize(targetUniform->type);
887 if (*bufSize < requiredBytes)
888 {
889 return false;
890 }
891 }
892
893 switch (targetUniform->type)
894 {
895 case GL_FLOAT_MAT2:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000896 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000897 break;
898 case GL_FLOAT_MAT3:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000899 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000900 break;
901 case GL_FLOAT_MAT4:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000902 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000903 break;
904 default:
905 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000906 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000907
908 switch (UniformComponentType(targetUniform->type))
909 {
910 case GL_BOOL:
911 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000912 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000913
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000914 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000915 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000916 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000917 }
918 }
919 break;
920 case GL_FLOAT:
921 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000922 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000923
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000924 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000925 {
926 params[i] = (GLint)floatParams[i];
927 }
928 }
929 break;
930 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000931 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
932 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000933 break;
934 default: UNREACHABLE();
935 }
936 }
937 }
938
939 return true;
940}
941
942void ProgramBinary::dirtyAllUniforms()
943{
944 unsigned int numUniforms = mUniforms.size();
945 for (unsigned int index = 0; index < numUniforms; index++)
946 {
947 mUniforms[index]->dirty = true;
948 }
949}
950
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000951// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000952void ProgramBinary::applyUniforms()
953{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000954 // Retrieve sampler uniform values
955 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
956 {
957 Uniform *targetUniform = *ub;
958
959 if (targetUniform->dirty)
960 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000961 if (targetUniform->type == GL_SAMPLER_2D ||
962 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000963 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000964 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000965 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000966
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000967 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000968 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000969 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000970
971 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000972 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000973 unsigned int samplerIndex = firstIndex + i;
974
975 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000976 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000977 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000978 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000979 }
980 }
981 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000982
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000983 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000984 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000985 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000986
987 for (int i = 0; i < count; i++)
988 {
989 unsigned int samplerIndex = firstIndex + i;
990
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000991 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000992 {
993 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000994 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000995 }
996 }
997 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000998 }
999 }
1000 }
1001
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +00001002 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001003}
1004
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001005// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1006// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001007int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001008{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001009 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001010
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001011 fragmentShader->resetVaryingsRegisterAssignment();
1012
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001013 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1014 {
1015 int n = VariableRowCount(varying->type) * varying->size;
1016 int m = VariableColumnCount(varying->type);
1017 bool success = false;
1018
1019 if (m == 2 || m == 3 || m == 4)
1020 {
1021 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1022 {
1023 bool available = true;
1024
1025 for (int y = 0; y < n && available; y++)
1026 {
1027 for (int x = 0; x < m && available; x++)
1028 {
1029 if (packing[r + y][x])
1030 {
1031 available = false;
1032 }
1033 }
1034 }
1035
1036 if (available)
1037 {
1038 varying->reg = r;
1039 varying->col = 0;
1040
1041 for (int y = 0; y < n; y++)
1042 {
1043 for (int x = 0; x < m; x++)
1044 {
1045 packing[r + y][x] = &*varying;
1046 }
1047 }
1048
1049 success = true;
1050 }
1051 }
1052
1053 if (!success && m == 2)
1054 {
1055 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1056 {
1057 bool available = true;
1058
1059 for (int y = 0; y < n && available; y++)
1060 {
1061 for (int x = 2; x < 4 && available; x++)
1062 {
1063 if (packing[r + y][x])
1064 {
1065 available = false;
1066 }
1067 }
1068 }
1069
1070 if (available)
1071 {
1072 varying->reg = r;
1073 varying->col = 2;
1074
1075 for (int y = 0; y < n; y++)
1076 {
1077 for (int x = 2; x < 4; x++)
1078 {
1079 packing[r + y][x] = &*varying;
1080 }
1081 }
1082
1083 success = true;
1084 }
1085 }
1086 }
1087 }
1088 else if (m == 1)
1089 {
1090 int space[4] = {0};
1091
1092 for (int y = 0; y < maxVaryingVectors; y++)
1093 {
1094 for (int x = 0; x < 4; x++)
1095 {
1096 space[x] += packing[y][x] ? 0 : 1;
1097 }
1098 }
1099
1100 int column = 0;
1101
1102 for (int x = 0; x < 4; x++)
1103 {
1104 if (space[x] >= n && space[x] < space[column])
1105 {
1106 column = x;
1107 }
1108 }
1109
1110 if (space[column] >= n)
1111 {
1112 for (int r = 0; r < maxVaryingVectors; r++)
1113 {
1114 if (!packing[r][column])
1115 {
1116 varying->reg = r;
1117
1118 for (int y = r; y < r + n; y++)
1119 {
1120 packing[y][column] = &*varying;
1121 }
1122
1123 break;
1124 }
1125 }
1126
1127 varying->col = column;
1128
1129 success = true;
1130 }
1131 }
1132 else UNREACHABLE();
1133
1134 if (!success)
1135 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001136 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001137
1138 return -1;
1139 }
1140 }
1141
1142 // Return the number of used registers
1143 int registers = 0;
1144
1145 for (int r = 0; r < maxVaryingVectors; r++)
1146 {
1147 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1148 {
1149 registers++;
1150 }
1151 }
1152
1153 return registers;
1154}
1155
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001156bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1157 std::string& pixelHLSL, std::string& vertexHLSL,
1158 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001159{
1160 if (pixelHLSL.empty() || vertexHLSL.empty())
1161 {
1162 return false;
1163 }
1164
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001165 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1166 bool usesFragColor = fragmentShader->mUsesFragColor;
1167 bool usesFragData = fragmentShader->mUsesFragData;
1168 if (usesMRT && usesFragColor && usesFragData)
1169 {
1170 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1171 return false;
1172 }
1173
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001174 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001175 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001176 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001177
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001178 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1179
1180 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001181 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001182 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001183
1184 return false;
1185 }
1186
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001187 vertexShader->resetVaryingsRegisterAssignment();
1188
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001189 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1190 {
1191 bool matched = false;
1192
1193 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1194 {
1195 if (output->name == input->name)
1196 {
1197 if (output->type != input->type || output->size != input->size)
1198 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001199 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 +00001200
1201 return false;
1202 }
1203
1204 output->reg = input->reg;
1205 output->col = input->col;
1206
1207 matched = true;
1208 break;
1209 }
1210 }
1211
1212 if (!matched)
1213 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001214 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001215
1216 return false;
1217 }
1218 }
1219
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001220 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001221 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001222 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001223 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1224
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001225 const unsigned int renderTargetCount = usesMRT ? mRenderer->getMaxRenderTargets() : 1;
1226
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001227 // special varyings that use reserved registers
1228 int reservedRegisterIndex = registers;
1229 std::string fragCoordSemantic;
1230 std::string pointCoordSemantic;
1231
1232 if (fragmentShader->mUsesFragCoord)
1233 {
1234 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1235 }
1236
1237 if (fragmentShader->mUsesPointCoord)
1238 {
1239 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1240 // In DX11 we compute this in the GS.
1241 if (shaderModel == 3)
1242 {
1243 pointCoordSemantic = "TEXCOORD0";
1244 }
1245 else if (shaderModel >= 4)
1246 {
1247 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1248 }
1249 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001250
1251 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001252 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001253
1254 int semanticIndex = 0;
1255 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1256 {
1257 switch (attribute->type)
1258 {
1259 case GL_FLOAT: vertexHLSL += " float "; break;
1260 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1261 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1262 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1263 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1264 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1265 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1266 default: UNREACHABLE();
1267 }
1268
1269 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1270
1271 semanticIndex += VariableRowCount(attribute->type);
1272 }
1273
1274 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001275 "\n"
1276 "struct VS_OUTPUT\n"
1277 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001279 if (shaderModel < 4)
1280 {
1281 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1282 }
1283
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001284 for (int r = 0; r < registers; r++)
1285 {
1286 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1287
1288 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1289 }
1290
1291 if (fragmentShader->mUsesFragCoord)
1292 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001293 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001294 }
1295
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001296 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001297 {
1298 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1299 }
1300
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001301 if (shaderModel >= 4)
1302 {
1303 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1304 }
1305
1306 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001307 "\n"
1308 "VS_OUTPUT main(VS_INPUT input)\n"
1309 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001310
1311 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1312 {
1313 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1314
1315 if (VariableRowCount(attribute->type) > 1) // Matrix
1316 {
1317 vertexHLSL += "transpose";
1318 }
1319
1320 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1321 }
1322
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001323 if (shaderModel >= 4)
1324 {
1325 vertexHLSL += "\n"
1326 " gl_main();\n"
1327 "\n"
1328 " VS_OUTPUT output;\n"
1329 " output.gl_Position.x = gl_Position.x;\n"
1330 " output.gl_Position.y = -gl_Position.y;\n"
1331 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1332 " output.gl_Position.w = gl_Position.w;\n";
1333 }
1334 else
1335 {
1336 vertexHLSL += "\n"
1337 " gl_main();\n"
1338 "\n"
1339 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001340 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1341 " 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 +00001342 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1343 " output.gl_Position.w = gl_Position.w;\n";
1344 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001345
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001346 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001347 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001348 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349 }
1350
1351 if (fragmentShader->mUsesFragCoord)
1352 {
1353 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1354 }
1355
1356 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1357 {
1358 if (varying->reg >= 0)
1359 {
1360 for (int i = 0; i < varying->size; i++)
1361 {
1362 int rows = VariableRowCount(varying->type);
1363
1364 for (int j = 0; j < rows; j++)
1365 {
1366 int r = varying->reg + i * rows + j;
1367 vertexHLSL += " output.v" + str(r);
1368
1369 bool sharedRegister = false; // Register used by multiple varyings
1370
1371 for (int x = 0; x < 4; x++)
1372 {
1373 if (packing[r][x] && packing[r][x] != packing[r][0])
1374 {
1375 sharedRegister = true;
1376 break;
1377 }
1378 }
1379
1380 if(sharedRegister)
1381 {
1382 vertexHLSL += ".";
1383
1384 for (int x = 0; x < 4; x++)
1385 {
1386 if (packing[r][x] == &*varying)
1387 {
1388 switch(x)
1389 {
1390 case 0: vertexHLSL += "x"; break;
1391 case 1: vertexHLSL += "y"; break;
1392 case 2: vertexHLSL += "z"; break;
1393 case 3: vertexHLSL += "w"; break;
1394 }
1395 }
1396 }
1397 }
1398
1399 vertexHLSL += " = " + varying->name;
1400
1401 if (varying->array)
1402 {
1403 vertexHLSL += "[" + str(i) + "]";
1404 }
1405
1406 if (rows > 1)
1407 {
1408 vertexHLSL += "[" + str(j) + "]";
1409 }
1410
1411 vertexHLSL += ";\n";
1412 }
1413 }
1414 }
1415 }
1416
1417 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001418 " return output;\n"
1419 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001420
1421 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001422 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001423
1424 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1425 {
1426 if (varying->reg >= 0)
1427 {
1428 for (int i = 0; i < varying->size; i++)
1429 {
1430 int rows = VariableRowCount(varying->type);
1431 for (int j = 0; j < rows; j++)
1432 {
1433 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001434 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001435 }
1436 }
1437 }
1438 else UNREACHABLE();
1439 }
1440
1441 if (fragmentShader->mUsesFragCoord)
1442 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001443 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001444 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001445
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001446 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1447 {
1448 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1449 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001450
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001451 // Must consume the PSIZE element if the geometry shader is not active
1452 // We won't know if we use a GS until we draw
1453 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1454 {
1455 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1456 }
1457
1458 if (fragmentShader->mUsesFragCoord)
1459 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001460 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001461 {
1462 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1463 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001464 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001465 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001466 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1467 }
1468 }
1469
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001470 pixelHLSL += "};\n"
1471 "\n"
1472 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001473 "{\n";
1474
1475 for (unsigned int i = 0; i < renderTargetCount; i++)
1476 {
1477 pixelHLSL += " float4 gl_Color" + str(i) + " : " + targetSemantic + str(i) + ";\n";
1478 }
1479
1480 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001481 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001482
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001483 if (fragmentShader->mUsesFrontFacing)
1484 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001485 if (shaderModel >= 4)
1486 {
1487 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1488 "{\n";
1489 }
1490 else
1491 {
1492 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1493 "{\n";
1494 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001495 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001496 else
1497 {
1498 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1499 "{\n";
1500 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001501
1502 if (fragmentShader->mUsesFragCoord)
1503 {
1504 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1505
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001506 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001507 {
1508 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1509 " gl_FragCoord.y = input.dx_VPos.y;\n";
1510 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001511 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001512 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001513 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001514 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001515 }
1516 else
1517 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001518 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1519 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1520 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001521 }
1522
daniel@transgaming.com12985182012-12-20 20:56:31 +00001523 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001524 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001525 }
1526
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001527 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001528 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001529 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1530 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001531 }
1532
1533 if (fragmentShader->mUsesFrontFacing)
1534 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001535 if (shaderModel <= 3)
1536 {
1537 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1538 }
1539 else
1540 {
1541 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1542 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001543 }
1544
1545 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1546 {
1547 if (varying->reg >= 0)
1548 {
1549 for (int i = 0; i < varying->size; i++)
1550 {
1551 int rows = VariableRowCount(varying->type);
1552 for (int j = 0; j < rows; j++)
1553 {
1554 std::string n = str(varying->reg + i * rows + j);
1555 pixelHLSL += " " + varying->name;
1556
1557 if (varying->array)
1558 {
1559 pixelHLSL += "[" + str(i) + "]";
1560 }
1561
1562 if (rows > 1)
1563 {
1564 pixelHLSL += "[" + str(j) + "]";
1565 }
1566
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001567 switch (VariableColumnCount(varying->type))
1568 {
1569 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1570 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1571 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1572 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1573 default: UNREACHABLE();
1574 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001575 }
1576 }
1577 }
1578 else UNREACHABLE();
1579 }
1580
1581 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001582 " gl_main();\n"
1583 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001584 " PS_OUTPUT output;\n";
1585
1586 for (unsigned int i = 0; i < renderTargetCount; i++)
1587 {
1588 unsigned int sourceColor = fragmentShader->mUsesFragData ? i : 0;
1589
1590 pixelHLSL += " output.gl_Color" + str(i) + " = gl_Color[" + str(sourceColor) + "];\n";
1591 }
1592
1593 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001594 " return output;\n"
1595 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001596
1597 return true;
1598}
1599
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1601{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001602 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001603
1604 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001605 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001606 if (format != GL_PROGRAM_BINARY_ANGLE)
1607 {
1608 infoLog.append("Invalid program binary format.");
1609 return false;
1610 }
1611
1612 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001613 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001614 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001615 {
1616 infoLog.append("Invalid program binary version.");
1617 return false;
1618 }
1619
1620 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1621 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.read(&name);
1625 mLinkedAttribute[i].name = name;
1626 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 }
1628
1629 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1630 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.read(&mSamplersPS[i].active);
1632 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633
1634 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636 mSamplersPS[i].textureType = (TextureType) textureType;
1637 }
1638
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001639 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001641 stream.read(&mSamplersVS[i].active);
1642 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643
1644 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001645 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 mSamplersVS[i].textureType = (TextureType) textureType;
1647 }
1648
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001649 stream.read(&mUsedVertexSamplerRange);
1650 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001651 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001652
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001653 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001654 stream.read(&size);
1655 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656 {
1657 infoLog.append("Invalid program binary.");
1658 return false;
1659 }
1660
1661 mUniforms.resize(size);
1662 for (unsigned int i = 0; i < size; ++i)
1663 {
1664 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001665 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001666 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667 unsigned int arraySize;
1668
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001670 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001671 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001672 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001674 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001676 stream.read(&mUniforms[i]->psRegisterIndex);
1677 stream.read(&mUniforms[i]->vsRegisterIndex);
1678 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 }
1680
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&size);
1682 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683 {
1684 infoLog.append("Invalid program binary.");
1685 return false;
1686 }
1687
1688 mUniformIndex.resize(size);
1689 for (unsigned int i = 0; i < size; ++i)
1690 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001691 stream.read(&mUniformIndex[i].name);
1692 stream.read(&mUniformIndex[i].element);
1693 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001694 }
1695
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001697 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001698
1699 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001700 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001701
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001702 unsigned int geometryShaderSize;
1703 stream.read(&geometryShaderSize);
1704
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001705 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001706
daniel@transgaming.com36038542012-11-28 20:59:26 +00001707 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708 ptr += sizeof(GUID);
1709
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001710 GUID identifier = mRenderer->getAdapterIdentifier();
1711 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712 {
1713 infoLog.append("Invalid program binary.");
1714 return false;
1715 }
1716
1717 const char *pixelShaderFunction = ptr;
1718 ptr += pixelShaderSize;
1719
1720 const char *vertexShaderFunction = ptr;
1721 ptr += vertexShaderSize;
1722
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001723 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1724 ptr += geometryShaderSize;
1725
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001726 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001727 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001728 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 {
1730 infoLog.append("Could not create pixel shader.");
1731 return false;
1732 }
1733
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001734 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001735 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001736 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001737 {
1738 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001739 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740 mPixelExecutable = NULL;
1741 return false;
1742 }
1743
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001744 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1745 {
1746 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1747 geometryShaderSize, rx::SHADER_GEOMETRY);
1748 if (!mGeometryExecutable)
1749 {
1750 infoLog.append("Could not create geometry shader.");
1751 delete mPixelExecutable;
1752 mPixelExecutable = NULL;
1753 delete mVertexExecutable;
1754 mVertexExecutable = NULL;
1755 return false;
1756 }
1757 }
1758 else
1759 {
1760 mGeometryExecutable = NULL;
1761 }
1762
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763 return true;
1764}
1765
1766bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1767{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001768 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001770 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001771 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772
1773 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1774 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001775 stream.write(mLinkedAttribute[i].type);
1776 stream.write(mLinkedAttribute[i].name);
1777 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778 }
1779
1780 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1781 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.write(mSamplersPS[i].active);
1783 stream.write(mSamplersPS[i].logicalTextureUnit);
1784 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001785 }
1786
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001787 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001789 stream.write(mSamplersVS[i].active);
1790 stream.write(mSamplersVS[i].logicalTextureUnit);
1791 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001792 }
1793
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001794 stream.write(mUsedVertexSamplerRange);
1795 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001796 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001797
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001799 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1800 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001801 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001802 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001803 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001804 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001806 stream.write(mUniforms[i]->psRegisterIndex);
1807 stream.write(mUniforms[i]->vsRegisterIndex);
1808 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001809 }
1810
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001811 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1813 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001814 stream.write(mUniformIndex[i].name);
1815 stream.write(mUniformIndex[i].element);
1816 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817 }
1818
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001819 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001820 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001821
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001822 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001823 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001825 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1826 stream.write(geometryShaderSize);
1827
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001828 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001830 GLsizei streamLength = stream.length();
1831 const void *streamData = stream.data();
1832
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001833 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834 if (totalLength > bufSize)
1835 {
1836 if (length)
1837 {
1838 *length = 0;
1839 }
1840
1841 return false;
1842 }
1843
1844 if (binary)
1845 {
1846 char *ptr = (char*) binary;
1847
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001848 memcpy(ptr, streamData, streamLength);
1849 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001850
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001851 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001852 ptr += sizeof(GUID);
1853
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001854 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001855 ptr += pixelShaderSize;
1856
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001857 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001858 ptr += vertexShaderSize;
1859
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001860 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1861 {
1862 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1863 ptr += geometryShaderSize;
1864 }
1865
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001866 ASSERT(ptr - totalLength == binary);
1867 }
1868
1869 if (length)
1870 {
1871 *length = totalLength;
1872 }
1873
1874 return true;
1875}
1876
1877GLint ProgramBinary::getLength()
1878{
1879 GLint length;
1880 if (save(NULL, INT_MAX, &length))
1881 {
1882 return length;
1883 }
1884 else
1885 {
1886 return 0;
1887 }
1888}
1889
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001890bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001891{
1892 if (!fragmentShader || !fragmentShader->isCompiled())
1893 {
1894 return false;
1895 }
1896
1897 if (!vertexShader || !vertexShader->isCompiled())
1898 {
1899 return false;
1900 }
1901
1902 std::string pixelHLSL = fragmentShader->getHLSL();
1903 std::string vertexHLSL = vertexShader->getHLSL();
1904
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001905 // Map the varyings to the register file
1906 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1907 int registers = packVaryings(infoLog, packing, fragmentShader);
1908
1909 if (registers < 0)
1910 {
1911 return false;
1912 }
1913
1914 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001915 {
1916 return false;
1917 }
1918
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001919 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001920 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1921 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001922
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001923 if (usesGeometryShader())
1924 {
1925 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1926 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1927 }
1928
1929 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001930 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001931 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001932 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001933
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001934 delete mVertexExecutable;
1935 mVertexExecutable = NULL;
1936 delete mPixelExecutable;
1937 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001938 delete mGeometryExecutable;
1939 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001940 }
1941
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001942 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1943 {
1944 success = false;
1945 }
1946
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001947 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001948 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001949 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001950 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001951
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001952 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001953}
1954
1955// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001956bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001957{
1958 unsigned int usedLocations = 0;
1959
1960 // Link attributes that have a binding location
1961 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1962 {
1963 int location = attributeBindings.getAttributeBinding(attribute->name);
1964
1965 if (location != -1) // Set by glBindAttribLocation
1966 {
1967 if (!mLinkedAttribute[location].name.empty())
1968 {
1969 // Multiple active attributes bound to the same location; not an error
1970 }
1971
1972 mLinkedAttribute[location] = *attribute;
1973
1974 int rows = VariableRowCount(attribute->type);
1975
1976 if (rows + location > MAX_VERTEX_ATTRIBS)
1977 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001978 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 +00001979
1980 return false;
1981 }
1982
1983 for (int i = 0; i < rows; i++)
1984 {
1985 usedLocations |= 1 << (location + i);
1986 }
1987 }
1988 }
1989
1990 // Link attributes that don't have a binding location
1991 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1992 {
1993 int location = attributeBindings.getAttributeBinding(attribute->name);
1994
1995 if (location == -1) // Not set by glBindAttribLocation
1996 {
1997 int rows = VariableRowCount(attribute->type);
1998 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1999
2000 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2001 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002002 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002003
2004 return false; // Fail to link
2005 }
2006
2007 mLinkedAttribute[availableIndex] = *attribute;
2008 }
2009 }
2010
2011 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2012 {
2013 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2014 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2015
2016 for (int r = 0; r < rows; r++)
2017 {
2018 mSemanticIndex[attributeIndex++] = index++;
2019 }
2020 }
2021
2022 return true;
2023}
2024
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002025bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002026{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002027 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002028 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002029 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002030 {
2031 return false;
2032 }
2033 }
2034
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002035 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002036 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002037 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002038 {
2039 return false;
2040 }
2041 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002042
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002043 return true;
2044}
2045
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002046bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002047{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002048 if (constant.type == GL_SAMPLER_2D ||
2049 constant.type == GL_SAMPLER_CUBE)
2050 {
2051 unsigned int samplerIndex = constant.registerIndex;
2052
2053 do
2054 {
2055 if (shader == GL_VERTEX_SHADER)
2056 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002057 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002058 {
2059 mSamplersVS[samplerIndex].active = true;
2060 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2061 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2062 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2063 }
2064 else
2065 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002066 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002067 return false;
2068 }
2069 }
2070 else if (shader == GL_FRAGMENT_SHADER)
2071 {
2072 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2073 {
2074 mSamplersPS[samplerIndex].active = true;
2075 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2076 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2077 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2078 }
2079 else
2080 {
2081 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2082 return false;
2083 }
2084 }
2085 else UNREACHABLE();
2086
2087 samplerIndex++;
2088 }
2089 while (samplerIndex < constant.registerIndex + constant.arraySize);
2090 }
2091
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002092 Uniform *uniform = NULL;
2093 GLint location = getUniformLocation(constant.name);
2094
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002095 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002096 {
2097 uniform = mUniforms[mUniformIndex[location].index];
2098
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002099 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002100 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002101 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
2102 return false;
2103 }
2104
2105 if (uniform->precision != constant.precision)
2106 {
2107 infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002108 return false;
2109 }
2110 }
2111 else
2112 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002113 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002114 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002115
2116 if (!uniform)
2117 {
2118 return false;
2119 }
2120
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002121 if (shader == GL_FRAGMENT_SHADER)
2122 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002123 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002124 }
2125 else if (shader == GL_VERTEX_SHADER)
2126 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002127 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002128 }
2129 else UNREACHABLE();
2130
2131 if (location >= 0)
2132 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002133 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002134 }
2135
2136 mUniforms.push_back(uniform);
2137 unsigned int uniformIndex = mUniforms.size() - 1;
2138
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002139 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002140 {
2141 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2142 }
2143
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002144 if (shader == GL_VERTEX_SHADER)
2145 {
2146 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2147 {
2148 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2149 return false;
2150 }
2151 }
2152 else if (shader == GL_FRAGMENT_SHADER)
2153 {
2154 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2155 {
2156 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2157 return false;
2158 }
2159 }
2160 else UNREACHABLE();
2161
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002162 return true;
2163}
2164
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002165std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2166{
2167 // for now we only handle point sprite emulation
2168 ASSERT(usesPointSpriteEmulation());
2169 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2170}
2171
2172std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2173{
2174 ASSERT(registers >= 0);
2175 ASSERT(vertexShader->mUsesPointSize);
2176 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2177
2178 std::string geomHLSL;
2179
2180 std::string varyingSemantic = "TEXCOORD";
2181
2182 std::string fragCoordSemantic;
2183 std::string pointCoordSemantic;
2184
2185 int reservedRegisterIndex = registers;
2186
2187 if (fragmentShader->mUsesFragCoord)
2188 {
2189 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2190 }
2191
2192 if (fragmentShader->mUsesPointCoord)
2193 {
2194 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2195 }
2196
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002197 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2198 "\n"
2199 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002200 "{\n";
2201
2202 for (int r = 0; r < registers; r++)
2203 {
2204 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2205
2206 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2207 }
2208
2209 if (fragmentShader->mUsesFragCoord)
2210 {
2211 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2212 }
2213
2214 geomHLSL += " float gl_PointSize : PSIZE;\n"
2215 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002216 "};\n"
2217 "\n"
2218 "struct GS_OUTPUT\n"
2219 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002220
2221 for (int r = 0; r < registers; r++)
2222 {
2223 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2224
2225 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2226 }
2227
2228 if (fragmentShader->mUsesFragCoord)
2229 {
2230 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2231 }
2232
2233 if (fragmentShader->mUsesPointCoord)
2234 {
2235 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2236 }
2237
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002238 geomHLSL += " float gl_PointSize : PSIZE;\n"
2239 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002240 "};\n"
2241 "\n"
2242 "static float2 pointSpriteCorners[] = \n"
2243 "{\n"
2244 " float2( 0.5f, -0.5f),\n"
2245 " float2( 0.5f, 0.5f),\n"
2246 " float2(-0.5f, -0.5f),\n"
2247 " float2(-0.5f, 0.5f)\n"
2248 "};\n"
2249 "\n"
2250 "static float2 pointSpriteTexcoords[] = \n"
2251 "{\n"
2252 " float2(1.0f, 1.0f),\n"
2253 " float2(1.0f, 0.0f),\n"
2254 " float2(0.0f, 1.0f),\n"
2255 " float2(0.0f, 0.0f)\n"
2256 "};\n"
2257 "\n"
2258 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2259 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2260 "\n"
2261 "[maxvertexcount(4)]\n"
2262 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2263 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002264 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2265 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002266
2267 for (int r = 0; r < registers; r++)
2268 {
2269 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2270 }
2271
2272 if (fragmentShader->mUsesFragCoord)
2273 {
2274 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2275 }
2276
2277 geomHLSL += " \n"
2278 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2279 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002280 " 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 +00002281
2282 for (int corner = 0; corner < 4; corner++)
2283 {
2284 geomHLSL += " \n"
2285 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2286
2287 if (fragmentShader->mUsesPointCoord)
2288 {
2289 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2290 }
2291
2292 geomHLSL += " outStream.Append(output);\n";
2293 }
2294
2295 geomHLSL += " \n"
2296 " outStream.RestartStrip();\n"
2297 "}\n";
2298
2299 return geomHLSL;
2300}
2301
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002302// This method needs to match OutputHLSL::decorate
2303std::string ProgramBinary::decorateAttribute(const std::string &name)
2304{
2305 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2306 {
2307 return "_" + name;
2308 }
2309
2310 return name;
2311}
2312
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002313bool ProgramBinary::isValidated() const
2314{
2315 return mValidated;
2316}
2317
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002318void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002319{
2320 // Skip over inactive attributes
2321 unsigned int activeAttribute = 0;
2322 unsigned int attribute;
2323 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2324 {
2325 if (mLinkedAttribute[attribute].name.empty())
2326 {
2327 continue;
2328 }
2329
2330 if (activeAttribute == index)
2331 {
2332 break;
2333 }
2334
2335 activeAttribute++;
2336 }
2337
2338 if (bufsize > 0)
2339 {
2340 const char *string = mLinkedAttribute[attribute].name.c_str();
2341
2342 strncpy(name, string, bufsize);
2343 name[bufsize - 1] = '\0';
2344
2345 if (length)
2346 {
2347 *length = strlen(name);
2348 }
2349 }
2350
2351 *size = 1; // Always a single 'type' instance
2352
2353 *type = mLinkedAttribute[attribute].type;
2354}
2355
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002356GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002357{
2358 int count = 0;
2359
2360 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2361 {
2362 if (!mLinkedAttribute[attributeIndex].name.empty())
2363 {
2364 count++;
2365 }
2366 }
2367
2368 return count;
2369}
2370
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002371GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002372{
2373 int maxLength = 0;
2374
2375 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2376 {
2377 if (!mLinkedAttribute[attributeIndex].name.empty())
2378 {
2379 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2380 }
2381 }
2382
2383 return maxLength;
2384}
2385
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002386void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002387{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002388 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002389
2390 if (bufsize > 0)
2391 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002392 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002393
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002394 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002395 {
2396 string += "[0]";
2397 }
2398
2399 strncpy(name, string.c_str(), bufsize);
2400 name[bufsize - 1] = '\0';
2401
2402 if (length)
2403 {
2404 *length = strlen(name);
2405 }
2406 }
2407
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002408 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002409
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002410 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002411}
2412
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002413GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002414{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002415 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002416}
2417
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002418GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002419{
2420 int maxLength = 0;
2421
2422 unsigned int numUniforms = mUniforms.size();
2423 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2424 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002425 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002426 {
2427 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2428 if (mUniforms[uniformIndex]->isArray())
2429 {
2430 length += 3; // Counting in "[0]".
2431 }
2432 maxLength = std::max(length, maxLength);
2433 }
2434 }
2435
2436 return maxLength;
2437}
2438
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002439void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002440{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002441 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002442 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002443 {
2444 mValidated = false;
2445 }
2446 else
2447 {
2448 mValidated = true;
2449 }
2450}
2451
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002452bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002453{
2454 // if any two active samplers in a program are of different types, but refer to the same
2455 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2456 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2457
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002458 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002459 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002460
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002461 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002462 {
2463 textureUnitType[i] = TEXTURE_UNKNOWN;
2464 }
2465
2466 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2467 {
2468 if (mSamplersPS[i].active)
2469 {
2470 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2471
2472 if (unit >= maxCombinedTextureImageUnits)
2473 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002474 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002475 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002476 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002477 }
2478
2479 return false;
2480 }
2481
2482 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2483 {
2484 if (mSamplersPS[i].textureType != textureUnitType[unit])
2485 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002486 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002487 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002488 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002489 }
2490
2491 return false;
2492 }
2493 }
2494 else
2495 {
2496 textureUnitType[unit] = mSamplersPS[i].textureType;
2497 }
2498 }
2499 }
2500
2501 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2502 {
2503 if (mSamplersVS[i].active)
2504 {
2505 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2506
2507 if (unit >= maxCombinedTextureImageUnits)
2508 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002509 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002510 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002511 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002512 }
2513
2514 return false;
2515 }
2516
2517 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2518 {
2519 if (mSamplersVS[i].textureType != textureUnitType[unit])
2520 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002521 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002522 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002523 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002524 }
2525
2526 return false;
2527 }
2528 }
2529 else
2530 {
2531 textureUnitType[unit] = mSamplersVS[i].textureType;
2532 }
2533 }
2534 }
2535
2536 return true;
2537}
2538
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002539ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2540{
2541}
2542
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002543struct AttributeSorter
2544{
2545 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2546 : originalIndices(semanticIndices)
2547 {
2548 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2549 {
2550 indices[i] = i;
2551 }
2552
2553 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2554 }
2555
2556 bool operator()(int a, int b)
2557 {
2558 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2559 }
2560
2561 int indices[MAX_VERTEX_ATTRIBS];
2562 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2563};
2564
2565void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2566{
2567 AttributeSorter sorter(mSemanticIndex);
2568
2569 int oldIndices[MAX_VERTEX_ATTRIBS];
2570 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2571
2572 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2573 {
2574 oldIndices[i] = mSemanticIndex[i];
2575 oldTranslatedAttributes[i] = attributes[i];
2576 }
2577
2578 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2579 {
2580 int oldIndex = sorter.indices[i];
2581 sortedSemanticIndices[i] = oldIndices[oldIndex];
2582 attributes[i] = oldTranslatedAttributes[oldIndex];
2583 }
2584}
2585
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002586}