blob: 5bfd01a5ed5c8c0bc97274df785d5bb0438c6b73 [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
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001165 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001166 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001167 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001168
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001169 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1170
1171 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001172 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001173 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001174
1175 return false;
1176 }
1177
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001178 vertexShader->resetVaryingsRegisterAssignment();
1179
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001180 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1181 {
1182 bool matched = false;
1183
1184 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1185 {
1186 if (output->name == input->name)
1187 {
1188 if (output->type != input->type || output->size != input->size)
1189 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001190 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 +00001191
1192 return false;
1193 }
1194
1195 output->reg = input->reg;
1196 output->col = input->col;
1197
1198 matched = true;
1199 break;
1200 }
1201 }
1202
1203 if (!matched)
1204 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001205 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001206
1207 return false;
1208 }
1209 }
1210
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001211 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001212 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001213 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001214 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1215
1216 // special varyings that use reserved registers
1217 int reservedRegisterIndex = registers;
1218 std::string fragCoordSemantic;
1219 std::string pointCoordSemantic;
1220
1221 if (fragmentShader->mUsesFragCoord)
1222 {
1223 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1224 }
1225
1226 if (fragmentShader->mUsesPointCoord)
1227 {
1228 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1229 // In DX11 we compute this in the GS.
1230 if (shaderModel == 3)
1231 {
1232 pointCoordSemantic = "TEXCOORD0";
1233 }
1234 else if (shaderModel >= 4)
1235 {
1236 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1237 }
1238 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239
1240 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001241 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 int semanticIndex = 0;
1244 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1245 {
1246 switch (attribute->type)
1247 {
1248 case GL_FLOAT: vertexHLSL += " float "; break;
1249 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1250 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1251 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1252 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1253 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1254 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1255 default: UNREACHABLE();
1256 }
1257
1258 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1259
1260 semanticIndex += VariableRowCount(attribute->type);
1261 }
1262
1263 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001264 "\n"
1265 "struct VS_OUTPUT\n"
1266 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001267
1268 for (int r = 0; r < registers; r++)
1269 {
1270 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1271
1272 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1273 }
1274
1275 if (fragmentShader->mUsesFragCoord)
1276 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001277 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278 }
1279
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001280 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281 {
1282 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1283 }
1284
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001285 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"
1286 "};\n"
1287 "\n"
1288 "VS_OUTPUT main(VS_INPUT input)\n"
1289 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001290
1291 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1292 {
1293 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1294
1295 if (VariableRowCount(attribute->type) > 1) // Matrix
1296 {
1297 vertexHLSL += "transpose";
1298 }
1299
1300 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1301 }
1302
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001303 if (shaderModel >= 4)
1304 {
1305 vertexHLSL += "\n"
1306 " gl_main();\n"
1307 "\n"
1308 " VS_OUTPUT output;\n"
1309 " output.gl_Position.x = gl_Position.x;\n"
1310 " output.gl_Position.y = -gl_Position.y;\n"
1311 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1312 " output.gl_Position.w = gl_Position.w;\n";
1313 }
1314 else
1315 {
1316 vertexHLSL += "\n"
1317 " gl_main();\n"
1318 "\n"
1319 " VS_OUTPUT output;\n"
1320 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1321 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
1322 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1323 " output.gl_Position.w = gl_Position.w;\n";
1324 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001325
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001326 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001327 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001328 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001329 }
1330
1331 if (fragmentShader->mUsesFragCoord)
1332 {
1333 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1334 }
1335
1336 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1337 {
1338 if (varying->reg >= 0)
1339 {
1340 for (int i = 0; i < varying->size; i++)
1341 {
1342 int rows = VariableRowCount(varying->type);
1343
1344 for (int j = 0; j < rows; j++)
1345 {
1346 int r = varying->reg + i * rows + j;
1347 vertexHLSL += " output.v" + str(r);
1348
1349 bool sharedRegister = false; // Register used by multiple varyings
1350
1351 for (int x = 0; x < 4; x++)
1352 {
1353 if (packing[r][x] && packing[r][x] != packing[r][0])
1354 {
1355 sharedRegister = true;
1356 break;
1357 }
1358 }
1359
1360 if(sharedRegister)
1361 {
1362 vertexHLSL += ".";
1363
1364 for (int x = 0; x < 4; x++)
1365 {
1366 if (packing[r][x] == &*varying)
1367 {
1368 switch(x)
1369 {
1370 case 0: vertexHLSL += "x"; break;
1371 case 1: vertexHLSL += "y"; break;
1372 case 2: vertexHLSL += "z"; break;
1373 case 3: vertexHLSL += "w"; break;
1374 }
1375 }
1376 }
1377 }
1378
1379 vertexHLSL += " = " + varying->name;
1380
1381 if (varying->array)
1382 {
1383 vertexHLSL += "[" + str(i) + "]";
1384 }
1385
1386 if (rows > 1)
1387 {
1388 vertexHLSL += "[" + str(j) + "]";
1389 }
1390
1391 vertexHLSL += ";\n";
1392 }
1393 }
1394 }
1395 }
1396
1397 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001398 " return output;\n"
1399 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001400
1401 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001402 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001403
1404 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1405 {
1406 if (varying->reg >= 0)
1407 {
1408 for (int i = 0; i < varying->size; i++)
1409 {
1410 int rows = VariableRowCount(varying->type);
1411 for (int j = 0; j < rows; j++)
1412 {
1413 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001414 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001415 }
1416 }
1417 }
1418 else UNREACHABLE();
1419 }
1420
1421 if (fragmentShader->mUsesFragCoord)
1422 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001423 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001424
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001425 // Must consume the PSIZE element if the geometry shader is not active
1426 // We won't know if we use a GS until we draw
1427 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1428 {
1429 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1430 }
1431
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001432 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001433 {
1434 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1435 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001436 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001437 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001438 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1439 }
1440 }
1441
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001442 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001443 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001444 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001445 }
1446
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001447 pixelHLSL += "};\n"
1448 "\n"
1449 "struct PS_OUTPUT\n"
1450 "{\n"
1451 " float4 gl_Color[1] : " + targetSemantic + ";\n"
1452 "};\n"
1453 "\n";
1454
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001455 if (fragmentShader->mUsesFrontFacing)
1456 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001457 if (shaderModel >= 4)
1458 {
1459 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1460 "{\n";
1461 }
1462 else
1463 {
1464 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1465 "{\n";
1466 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001468 else
1469 {
1470 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1471 "{\n";
1472 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001473
1474 if (fragmentShader->mUsesFragCoord)
1475 {
1476 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1477
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001478 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001479 {
1480 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1481 " gl_FragCoord.y = input.dx_VPos.y;\n";
1482 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001483 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001484 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001485 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001486 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001487 }
1488 else
1489 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001490 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1491 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1492 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001493 }
1494
daniel@transgaming.com12985182012-12-20 20:56:31 +00001495 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001496 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001497 }
1498
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001499 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001500 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001501 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1502 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001503 }
1504
1505 if (fragmentShader->mUsesFrontFacing)
1506 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001507 if (shaderModel <= 3)
1508 {
1509 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1510 }
1511 else
1512 {
1513 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1514 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001515 }
1516
1517 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1518 {
1519 if (varying->reg >= 0)
1520 {
1521 for (int i = 0; i < varying->size; i++)
1522 {
1523 int rows = VariableRowCount(varying->type);
1524 for (int j = 0; j < rows; j++)
1525 {
1526 std::string n = str(varying->reg + i * rows + j);
1527 pixelHLSL += " " + varying->name;
1528
1529 if (varying->array)
1530 {
1531 pixelHLSL += "[" + str(i) + "]";
1532 }
1533
1534 if (rows > 1)
1535 {
1536 pixelHLSL += "[" + str(j) + "]";
1537 }
1538
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001539 switch (VariableColumnCount(varying->type))
1540 {
1541 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1542 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1543 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1544 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1545 default: UNREACHABLE();
1546 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001547 }
1548 }
1549 }
1550 else UNREACHABLE();
1551 }
1552
1553 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001554 " gl_main();\n"
1555 "\n"
1556 " PS_OUTPUT output;\n"
1557 " output.gl_Color[0] = gl_Color[0];\n"
1558 "\n"
1559 " return output;\n"
1560 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001561
1562 return true;
1563}
1564
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1566{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001567 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001568
1569 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001570 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571 if (format != GL_PROGRAM_BINARY_ANGLE)
1572 {
1573 infoLog.append("Invalid program binary format.");
1574 return false;
1575 }
1576
1577 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001578 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001579 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001580 {
1581 infoLog.append("Invalid program binary version.");
1582 return false;
1583 }
1584
1585 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1586 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001587 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001588 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001589 stream.read(&name);
1590 mLinkedAttribute[i].name = name;
1591 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592 }
1593
1594 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1595 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001596 stream.read(&mSamplersPS[i].active);
1597 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001598
1599 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001600 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601 mSamplersPS[i].textureType = (TextureType) textureType;
1602 }
1603
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001604 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001606 stream.read(&mSamplersVS[i].active);
1607 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001608
1609 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001610 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001611 mSamplersVS[i].textureType = (TextureType) textureType;
1612 }
1613
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001614 stream.read(&mUsedVertexSamplerRange);
1615 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001616 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617
1618 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001619 stream.read(&size);
1620 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001621 {
1622 infoLog.append("Invalid program binary.");
1623 return false;
1624 }
1625
1626 mUniforms.resize(size);
1627 for (unsigned int i = 0; i < size; ++i)
1628 {
1629 GLenum type;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001630 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631 unsigned int arraySize;
1632
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001633 stream.read(&type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001634 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001637 mUniforms[i] = new Uniform(type, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001639 stream.read(&mUniforms[i]->psRegisterIndex);
1640 stream.read(&mUniforms[i]->vsRegisterIndex);
1641 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001642 }
1643
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001644 stream.read(&size);
1645 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 {
1647 infoLog.append("Invalid program binary.");
1648 return false;
1649 }
1650
1651 mUniformIndex.resize(size);
1652 for (unsigned int i = 0; i < size; ++i)
1653 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001654 stream.read(&mUniformIndex[i].name);
1655 stream.read(&mUniformIndex[i].element);
1656 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001657 }
1658
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001659 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001660 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661
1662 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001665 unsigned int geometryShaderSize;
1666 stream.read(&geometryShaderSize);
1667
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001668 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669
daniel@transgaming.com36038542012-11-28 20:59:26 +00001670 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 ptr += sizeof(GUID);
1672
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001673 GUID identifier = mRenderer->getAdapterIdentifier();
1674 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 {
1676 infoLog.append("Invalid program binary.");
1677 return false;
1678 }
1679
1680 const char *pixelShaderFunction = ptr;
1681 ptr += pixelShaderSize;
1682
1683 const char *vertexShaderFunction = ptr;
1684 ptr += vertexShaderSize;
1685
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001686 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1687 ptr += geometryShaderSize;
1688
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001689 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001690 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001691 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001692 {
1693 infoLog.append("Could not create pixel shader.");
1694 return false;
1695 }
1696
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001697 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001698 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001699 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001700 {
1701 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001702 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001703 mPixelExecutable = NULL;
1704 return false;
1705 }
1706
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001707 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1708 {
1709 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1710 geometryShaderSize, rx::SHADER_GEOMETRY);
1711 if (!mGeometryExecutable)
1712 {
1713 infoLog.append("Could not create geometry shader.");
1714 delete mPixelExecutable;
1715 mPixelExecutable = NULL;
1716 delete mVertexExecutable;
1717 mVertexExecutable = NULL;
1718 return false;
1719 }
1720 }
1721 else
1722 {
1723 mGeometryExecutable = NULL;
1724 }
1725
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001726 return true;
1727}
1728
1729bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1730{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001731 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001732
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001733 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001734 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735
1736 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1737 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001738 stream.write(mLinkedAttribute[i].type);
1739 stream.write(mLinkedAttribute[i].name);
1740 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741 }
1742
1743 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1744 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001745 stream.write(mSamplersPS[i].active);
1746 stream.write(mSamplersPS[i].logicalTextureUnit);
1747 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001748 }
1749
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001750 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001752 stream.write(mSamplersVS[i].active);
1753 stream.write(mSamplersVS[i].logicalTextureUnit);
1754 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001755 }
1756
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001757 stream.write(mUsedVertexSamplerRange);
1758 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001759 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001761 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1763 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001764 stream.write(mUniforms[i]->type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001765 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001768 stream.write(mUniforms[i]->psRegisterIndex);
1769 stream.write(mUniforms[i]->vsRegisterIndex);
1770 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001771 }
1772
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001773 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1775 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.write(mUniformIndex[i].name);
1777 stream.write(mUniformIndex[i].element);
1778 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779 }
1780
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001781 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001784 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001787 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1788 stream.write(geometryShaderSize);
1789
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001790 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001792 GLsizei streamLength = stream.length();
1793 const void *streamData = stream.data();
1794
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001795 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796 if (totalLength > bufSize)
1797 {
1798 if (length)
1799 {
1800 *length = 0;
1801 }
1802
1803 return false;
1804 }
1805
1806 if (binary)
1807 {
1808 char *ptr = (char*) binary;
1809
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001810 memcpy(ptr, streamData, streamLength);
1811 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001813 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 ptr += sizeof(GUID);
1815
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001816 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817 ptr += pixelShaderSize;
1818
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001819 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820 ptr += vertexShaderSize;
1821
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001822 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1823 {
1824 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1825 ptr += geometryShaderSize;
1826 }
1827
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001828 ASSERT(ptr - totalLength == binary);
1829 }
1830
1831 if (length)
1832 {
1833 *length = totalLength;
1834 }
1835
1836 return true;
1837}
1838
1839GLint ProgramBinary::getLength()
1840{
1841 GLint length;
1842 if (save(NULL, INT_MAX, &length))
1843 {
1844 return length;
1845 }
1846 else
1847 {
1848 return 0;
1849 }
1850}
1851
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001852bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001853{
1854 if (!fragmentShader || !fragmentShader->isCompiled())
1855 {
1856 return false;
1857 }
1858
1859 if (!vertexShader || !vertexShader->isCompiled())
1860 {
1861 return false;
1862 }
1863
1864 std::string pixelHLSL = fragmentShader->getHLSL();
1865 std::string vertexHLSL = vertexShader->getHLSL();
1866
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001867 // Map the varyings to the register file
1868 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1869 int registers = packVaryings(infoLog, packing, fragmentShader);
1870
1871 if (registers < 0)
1872 {
1873 return false;
1874 }
1875
1876 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001877 {
1878 return false;
1879 }
1880
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001881 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001882 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1883 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001884
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001885 if (usesGeometryShader())
1886 {
1887 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1888 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1889 }
1890
1891 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001892 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001893 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001894 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001895
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001896 delete mVertexExecutable;
1897 mVertexExecutable = NULL;
1898 delete mPixelExecutable;
1899 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001900 delete mGeometryExecutable;
1901 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001902 }
1903
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001904 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1905 {
1906 success = false;
1907 }
1908
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001909 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001910 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001911 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001912 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001913
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001914 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001915}
1916
1917// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001918bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001919{
1920 unsigned int usedLocations = 0;
1921
1922 // Link attributes that have a binding location
1923 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1924 {
1925 int location = attributeBindings.getAttributeBinding(attribute->name);
1926
1927 if (location != -1) // Set by glBindAttribLocation
1928 {
1929 if (!mLinkedAttribute[location].name.empty())
1930 {
1931 // Multiple active attributes bound to the same location; not an error
1932 }
1933
1934 mLinkedAttribute[location] = *attribute;
1935
1936 int rows = VariableRowCount(attribute->type);
1937
1938 if (rows + location > MAX_VERTEX_ATTRIBS)
1939 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001940 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 +00001941
1942 return false;
1943 }
1944
1945 for (int i = 0; i < rows; i++)
1946 {
1947 usedLocations |= 1 << (location + i);
1948 }
1949 }
1950 }
1951
1952 // Link attributes that don't have a binding location
1953 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1954 {
1955 int location = attributeBindings.getAttributeBinding(attribute->name);
1956
1957 if (location == -1) // Not set by glBindAttribLocation
1958 {
1959 int rows = VariableRowCount(attribute->type);
1960 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1961
1962 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1963 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001964 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001965
1966 return false; // Fail to link
1967 }
1968
1969 mLinkedAttribute[availableIndex] = *attribute;
1970 }
1971 }
1972
1973 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1974 {
1975 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1976 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1977
1978 for (int r = 0; r < rows; r++)
1979 {
1980 mSemanticIndex[attributeIndex++] = index++;
1981 }
1982 }
1983
1984 return true;
1985}
1986
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001987bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001988{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001989 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001990 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001991 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001992 {
1993 return false;
1994 }
1995 }
1996
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001997 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001998 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001999 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002000 {
2001 return false;
2002 }
2003 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002004
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002005 return true;
2006}
2007
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002008bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002009{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002010 if (constant.type == GL_SAMPLER_2D ||
2011 constant.type == GL_SAMPLER_CUBE)
2012 {
2013 unsigned int samplerIndex = constant.registerIndex;
2014
2015 do
2016 {
2017 if (shader == GL_VERTEX_SHADER)
2018 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002019 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002020 {
2021 mSamplersVS[samplerIndex].active = true;
2022 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2023 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2024 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2025 }
2026 else
2027 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002028 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002029 return false;
2030 }
2031 }
2032 else if (shader == GL_FRAGMENT_SHADER)
2033 {
2034 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2035 {
2036 mSamplersPS[samplerIndex].active = true;
2037 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2038 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2039 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2040 }
2041 else
2042 {
2043 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2044 return false;
2045 }
2046 }
2047 else UNREACHABLE();
2048
2049 samplerIndex++;
2050 }
2051 while (samplerIndex < constant.registerIndex + constant.arraySize);
2052 }
2053
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002054 Uniform *uniform = NULL;
2055 GLint location = getUniformLocation(constant.name);
2056
2057 if (location >= 0) // Previously defined, types must match
2058 {
2059 uniform = mUniforms[mUniformIndex[location].index];
2060
2061 if (uniform->type != constant.type)
2062 {
2063 return false;
2064 }
2065 }
2066 else
2067 {
2068 uniform = new Uniform(constant.type, constant.name, constant.arraySize);
2069 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002070
2071 if (!uniform)
2072 {
2073 return false;
2074 }
2075
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002076 if (shader == GL_FRAGMENT_SHADER)
2077 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002078 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002079 }
2080 else if (shader == GL_VERTEX_SHADER)
2081 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002082 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002083 }
2084 else UNREACHABLE();
2085
2086 if (location >= 0)
2087 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002088 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002089 }
2090
2091 mUniforms.push_back(uniform);
2092 unsigned int uniformIndex = mUniforms.size() - 1;
2093
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002094 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002095 {
2096 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2097 }
2098
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002099 if (shader == GL_VERTEX_SHADER)
2100 {
2101 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2102 {
2103 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2104 return false;
2105 }
2106 }
2107 else if (shader == GL_FRAGMENT_SHADER)
2108 {
2109 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2110 {
2111 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2112 return false;
2113 }
2114 }
2115 else UNREACHABLE();
2116
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002117 return true;
2118}
2119
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002120std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2121{
2122 // for now we only handle point sprite emulation
2123 ASSERT(usesPointSpriteEmulation());
2124 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2125}
2126
2127std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2128{
2129 ASSERT(registers >= 0);
2130 ASSERT(vertexShader->mUsesPointSize);
2131 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2132
2133 std::string geomHLSL;
2134
2135 std::string varyingSemantic = "TEXCOORD";
2136
2137 std::string fragCoordSemantic;
2138 std::string pointCoordSemantic;
2139
2140 int reservedRegisterIndex = registers;
2141
2142 if (fragmentShader->mUsesFragCoord)
2143 {
2144 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2145 }
2146
2147 if (fragmentShader->mUsesPointCoord)
2148 {
2149 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2150 }
2151
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002152 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2153 "\n"
2154 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002155 "{\n";
2156
2157 for (int r = 0; r < registers; r++)
2158 {
2159 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2160
2161 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2162 }
2163
2164 if (fragmentShader->mUsesFragCoord)
2165 {
2166 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2167 }
2168
2169 geomHLSL += " float gl_PointSize : PSIZE;\n"
2170 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002171 "};\n"
2172 "\n"
2173 "struct GS_OUTPUT\n"
2174 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002175
2176 for (int r = 0; r < registers; r++)
2177 {
2178 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2179
2180 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2181 }
2182
2183 if (fragmentShader->mUsesFragCoord)
2184 {
2185 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2186 }
2187
2188 if (fragmentShader->mUsesPointCoord)
2189 {
2190 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2191 }
2192
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002193 geomHLSL += " float gl_PointSize : PSIZE;\n"
2194 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002195 "};\n"
2196 "\n"
2197 "static float2 pointSpriteCorners[] = \n"
2198 "{\n"
2199 " float2( 0.5f, -0.5f),\n"
2200 " float2( 0.5f, 0.5f),\n"
2201 " float2(-0.5f, -0.5f),\n"
2202 " float2(-0.5f, 0.5f)\n"
2203 "};\n"
2204 "\n"
2205 "static float2 pointSpriteTexcoords[] = \n"
2206 "{\n"
2207 " float2(1.0f, 1.0f),\n"
2208 " float2(1.0f, 0.0f),\n"
2209 " float2(0.0f, 1.0f),\n"
2210 " float2(0.0f, 0.0f)\n"
2211 "};\n"
2212 "\n"
2213 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2214 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2215 "\n"
2216 "[maxvertexcount(4)]\n"
2217 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2218 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002219 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2220 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002221
2222 for (int r = 0; r < registers; r++)
2223 {
2224 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2225 }
2226
2227 if (fragmentShader->mUsesFragCoord)
2228 {
2229 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2230 }
2231
2232 geomHLSL += " \n"
2233 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2234 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002235 " 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 +00002236
2237 for (int corner = 0; corner < 4; corner++)
2238 {
2239 geomHLSL += " \n"
2240 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2241
2242 if (fragmentShader->mUsesPointCoord)
2243 {
2244 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2245 }
2246
2247 geomHLSL += " outStream.Append(output);\n";
2248 }
2249
2250 geomHLSL += " \n"
2251 " outStream.RestartStrip();\n"
2252 "}\n";
2253
2254 return geomHLSL;
2255}
2256
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002257// This method needs to match OutputHLSL::decorate
2258std::string ProgramBinary::decorateAttribute(const std::string &name)
2259{
2260 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2261 {
2262 return "_" + name;
2263 }
2264
2265 return name;
2266}
2267
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002268bool ProgramBinary::isValidated() const
2269{
2270 return mValidated;
2271}
2272
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002273void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274{
2275 // Skip over inactive attributes
2276 unsigned int activeAttribute = 0;
2277 unsigned int attribute;
2278 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2279 {
2280 if (mLinkedAttribute[attribute].name.empty())
2281 {
2282 continue;
2283 }
2284
2285 if (activeAttribute == index)
2286 {
2287 break;
2288 }
2289
2290 activeAttribute++;
2291 }
2292
2293 if (bufsize > 0)
2294 {
2295 const char *string = mLinkedAttribute[attribute].name.c_str();
2296
2297 strncpy(name, string, bufsize);
2298 name[bufsize - 1] = '\0';
2299
2300 if (length)
2301 {
2302 *length = strlen(name);
2303 }
2304 }
2305
2306 *size = 1; // Always a single 'type' instance
2307
2308 *type = mLinkedAttribute[attribute].type;
2309}
2310
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002311GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002312{
2313 int count = 0;
2314
2315 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2316 {
2317 if (!mLinkedAttribute[attributeIndex].name.empty())
2318 {
2319 count++;
2320 }
2321 }
2322
2323 return count;
2324}
2325
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002326GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002327{
2328 int maxLength = 0;
2329
2330 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2331 {
2332 if (!mLinkedAttribute[attributeIndex].name.empty())
2333 {
2334 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2335 }
2336 }
2337
2338 return maxLength;
2339}
2340
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002341void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002342{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002343 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002344
2345 if (bufsize > 0)
2346 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002347 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002348
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002349 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002350 {
2351 string += "[0]";
2352 }
2353
2354 strncpy(name, string.c_str(), bufsize);
2355 name[bufsize - 1] = '\0';
2356
2357 if (length)
2358 {
2359 *length = strlen(name);
2360 }
2361 }
2362
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002363 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002364
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002365 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002366}
2367
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002368GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002369{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002370 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002371}
2372
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002373GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002374{
2375 int maxLength = 0;
2376
2377 unsigned int numUniforms = mUniforms.size();
2378 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2379 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002380 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002381 {
2382 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2383 if (mUniforms[uniformIndex]->isArray())
2384 {
2385 length += 3; // Counting in "[0]".
2386 }
2387 maxLength = std::max(length, maxLength);
2388 }
2389 }
2390
2391 return maxLength;
2392}
2393
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002394void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002395{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002396 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002397 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002398 {
2399 mValidated = false;
2400 }
2401 else
2402 {
2403 mValidated = true;
2404 }
2405}
2406
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002407bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002408{
2409 // if any two active samplers in a program are of different types, but refer to the same
2410 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2411 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2412
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002413 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002414 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002415
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002416 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002417 {
2418 textureUnitType[i] = TEXTURE_UNKNOWN;
2419 }
2420
2421 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2422 {
2423 if (mSamplersPS[i].active)
2424 {
2425 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2426
2427 if (unit >= maxCombinedTextureImageUnits)
2428 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002429 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002430 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002431 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002432 }
2433
2434 return false;
2435 }
2436
2437 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2438 {
2439 if (mSamplersPS[i].textureType != textureUnitType[unit])
2440 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002441 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002442 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002443 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002444 }
2445
2446 return false;
2447 }
2448 }
2449 else
2450 {
2451 textureUnitType[unit] = mSamplersPS[i].textureType;
2452 }
2453 }
2454 }
2455
2456 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2457 {
2458 if (mSamplersVS[i].active)
2459 {
2460 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2461
2462 if (unit >= maxCombinedTextureImageUnits)
2463 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002464 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002465 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002466 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002467 }
2468
2469 return false;
2470 }
2471
2472 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2473 {
2474 if (mSamplersVS[i].textureType != textureUnitType[unit])
2475 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002476 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002477 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002478 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002479 }
2480
2481 return false;
2482 }
2483 }
2484 else
2485 {
2486 textureUnitType[unit] = mSamplersVS[i].textureType;
2487 }
2488 }
2489 }
2490
2491 return true;
2492}
2493
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002494ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2495{
2496}
2497
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002498struct AttributeSorter
2499{
2500 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2501 : originalIndices(semanticIndices)
2502 {
2503 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2504 {
2505 indices[i] = i;
2506 }
2507
2508 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2509 }
2510
2511 bool operator()(int a, int b)
2512 {
2513 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2514 }
2515
2516 int indices[MAX_VERTEX_ATTRIBS];
2517 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2518};
2519
2520void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2521{
2522 AttributeSorter sorter(mSemanticIndex);
2523
2524 int oldIndices[MAX_VERTEX_ATTRIBS];
2525 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2526
2527 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2528 {
2529 oldIndices[i] = mSemanticIndex[i];
2530 oldTranslatedAttributes[i] = attributes[i];
2531 }
2532
2533 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2534 {
2535 int oldIndex = sorter.indices[i];
2536 sortedSemanticIndices[i] = oldIndices[oldIndex];
2537 attributes[i] = oldTranslatedAttributes[oldIndex];
2538 }
2539}
2540
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002541}