blob: 034dfec07b88e9ab277ff91b358b644ce2c3563c [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
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001268 if (shaderModel < 4)
1269 {
1270 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1271 }
1272
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001273 for (int r = 0; r < registers; r++)
1274 {
1275 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1276
1277 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1278 }
1279
1280 if (fragmentShader->mUsesFragCoord)
1281 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001282 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001283 }
1284
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001285 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001286 {
1287 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1288 }
1289
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001290 if (shaderModel >= 4)
1291 {
1292 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1293 }
1294
1295 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001296 "\n"
1297 "VS_OUTPUT main(VS_INPUT input)\n"
1298 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001299
1300 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1301 {
1302 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1303
1304 if (VariableRowCount(attribute->type) > 1) // Matrix
1305 {
1306 vertexHLSL += "transpose";
1307 }
1308
1309 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1310 }
1311
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001312 if (shaderModel >= 4)
1313 {
1314 vertexHLSL += "\n"
1315 " gl_main();\n"
1316 "\n"
1317 " VS_OUTPUT output;\n"
1318 " output.gl_Position.x = gl_Position.x;\n"
1319 " output.gl_Position.y = -gl_Position.y;\n"
1320 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1321 " output.gl_Position.w = gl_Position.w;\n";
1322 }
1323 else
1324 {
1325 vertexHLSL += "\n"
1326 " gl_main();\n"
1327 "\n"
1328 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001329 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1330 " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001331 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1332 " output.gl_Position.w = gl_Position.w;\n";
1333 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001334
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001335 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001336 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001337 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001338 }
1339
1340 if (fragmentShader->mUsesFragCoord)
1341 {
1342 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1343 }
1344
1345 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1346 {
1347 if (varying->reg >= 0)
1348 {
1349 for (int i = 0; i < varying->size; i++)
1350 {
1351 int rows = VariableRowCount(varying->type);
1352
1353 for (int j = 0; j < rows; j++)
1354 {
1355 int r = varying->reg + i * rows + j;
1356 vertexHLSL += " output.v" + str(r);
1357
1358 bool sharedRegister = false; // Register used by multiple varyings
1359
1360 for (int x = 0; x < 4; x++)
1361 {
1362 if (packing[r][x] && packing[r][x] != packing[r][0])
1363 {
1364 sharedRegister = true;
1365 break;
1366 }
1367 }
1368
1369 if(sharedRegister)
1370 {
1371 vertexHLSL += ".";
1372
1373 for (int x = 0; x < 4; x++)
1374 {
1375 if (packing[r][x] == &*varying)
1376 {
1377 switch(x)
1378 {
1379 case 0: vertexHLSL += "x"; break;
1380 case 1: vertexHLSL += "y"; break;
1381 case 2: vertexHLSL += "z"; break;
1382 case 3: vertexHLSL += "w"; break;
1383 }
1384 }
1385 }
1386 }
1387
1388 vertexHLSL += " = " + varying->name;
1389
1390 if (varying->array)
1391 {
1392 vertexHLSL += "[" + str(i) + "]";
1393 }
1394
1395 if (rows > 1)
1396 {
1397 vertexHLSL += "[" + str(j) + "]";
1398 }
1399
1400 vertexHLSL += ";\n";
1401 }
1402 }
1403 }
1404 }
1405
1406 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001407 " return output;\n"
1408 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001409
1410 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001411 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001412
1413 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1414 {
1415 if (varying->reg >= 0)
1416 {
1417 for (int i = 0; i < varying->size; i++)
1418 {
1419 int rows = VariableRowCount(varying->type);
1420 for (int j = 0; j < rows; j++)
1421 {
1422 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001423 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001424 }
1425 }
1426 }
1427 else UNREACHABLE();
1428 }
1429
1430 if (fragmentShader->mUsesFragCoord)
1431 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001432 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001433 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001434
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001435 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1436 {
1437 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1438 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001439
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001440 // Must consume the PSIZE element if the geometry shader is not active
1441 // We won't know if we use a GS until we draw
1442 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1443 {
1444 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1445 }
1446
1447 if (fragmentShader->mUsesFragCoord)
1448 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001449 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001450 {
1451 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1452 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001453 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001454 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001455 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1456 }
1457 }
1458
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001459 pixelHLSL += "};\n"
1460 "\n"
1461 "struct PS_OUTPUT\n"
1462 "{\n"
1463 " float4 gl_Color[1] : " + targetSemantic + ";\n"
1464 "};\n"
1465 "\n";
1466
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 if (fragmentShader->mUsesFrontFacing)
1468 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001469 if (shaderModel >= 4)
1470 {
1471 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1472 "{\n";
1473 }
1474 else
1475 {
1476 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1477 "{\n";
1478 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001479 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001480 else
1481 {
1482 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1483 "{\n";
1484 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001485
1486 if (fragmentShader->mUsesFragCoord)
1487 {
1488 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1489
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001490 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001491 {
1492 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1493 " gl_FragCoord.y = input.dx_VPos.y;\n";
1494 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001495 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001496 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001497 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001498 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001499 }
1500 else
1501 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001502 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1503 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1504 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001505 }
1506
daniel@transgaming.com12985182012-12-20 20:56:31 +00001507 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001508 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001509 }
1510
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001511 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001512 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001513 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1514 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001515 }
1516
1517 if (fragmentShader->mUsesFrontFacing)
1518 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001519 if (shaderModel <= 3)
1520 {
1521 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1522 }
1523 else
1524 {
1525 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1526 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001527 }
1528
1529 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1530 {
1531 if (varying->reg >= 0)
1532 {
1533 for (int i = 0; i < varying->size; i++)
1534 {
1535 int rows = VariableRowCount(varying->type);
1536 for (int j = 0; j < rows; j++)
1537 {
1538 std::string n = str(varying->reg + i * rows + j);
1539 pixelHLSL += " " + varying->name;
1540
1541 if (varying->array)
1542 {
1543 pixelHLSL += "[" + str(i) + "]";
1544 }
1545
1546 if (rows > 1)
1547 {
1548 pixelHLSL += "[" + str(j) + "]";
1549 }
1550
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001551 switch (VariableColumnCount(varying->type))
1552 {
1553 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1554 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1555 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1556 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1557 default: UNREACHABLE();
1558 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001559 }
1560 }
1561 }
1562 else UNREACHABLE();
1563 }
1564
1565 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001566 " gl_main();\n"
1567 "\n"
1568 " PS_OUTPUT output;\n"
1569 " output.gl_Color[0] = gl_Color[0];\n"
1570 "\n"
1571 " return output;\n"
1572 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001573
1574 return true;
1575}
1576
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001577bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1578{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001579 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001580
1581 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001582 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001583 if (format != GL_PROGRAM_BINARY_ANGLE)
1584 {
1585 infoLog.append("Invalid program binary format.");
1586 return false;
1587 }
1588
1589 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001590 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001591 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592 {
1593 infoLog.append("Invalid program binary version.");
1594 return false;
1595 }
1596
1597 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1598 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001601 stream.read(&name);
1602 mLinkedAttribute[i].name = name;
1603 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001604 }
1605
1606 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1607 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001608 stream.read(&mSamplersPS[i].active);
1609 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001610
1611 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001612 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001613 mSamplersPS[i].textureType = (TextureType) textureType;
1614 }
1615
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001616 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001617 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001618 stream.read(&mSamplersVS[i].active);
1619 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001620
1621 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623 mSamplersVS[i].textureType = (TextureType) textureType;
1624 }
1625
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001626 stream.read(&mUsedVertexSamplerRange);
1627 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001628 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001630 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.read(&size);
1632 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633 {
1634 infoLog.append("Invalid program binary.");
1635 return false;
1636 }
1637
1638 mUniforms.resize(size);
1639 for (unsigned int i = 0; i < size; ++i)
1640 {
1641 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001642 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001643 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001644 unsigned int arraySize;
1645
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001646 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001647 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001648 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001649 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001650
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001651 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001652
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001653 stream.read(&mUniforms[i]->psRegisterIndex);
1654 stream.read(&mUniforms[i]->vsRegisterIndex);
1655 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656 }
1657
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001658 stream.read(&size);
1659 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 {
1661 infoLog.append("Invalid program binary.");
1662 return false;
1663 }
1664
1665 mUniformIndex.resize(size);
1666 for (unsigned int i = 0; i < size; ++i)
1667 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001668 stream.read(&mUniformIndex[i].name);
1669 stream.read(&mUniformIndex[i].element);
1670 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 }
1672
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001673 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001674 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675
1676 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001677 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001678
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001679 unsigned int geometryShaderSize;
1680 stream.read(&geometryShaderSize);
1681
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001682 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683
daniel@transgaming.com36038542012-11-28 20:59:26 +00001684 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001685 ptr += sizeof(GUID);
1686
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001687 GUID identifier = mRenderer->getAdapterIdentifier();
1688 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001689 {
1690 infoLog.append("Invalid program binary.");
1691 return false;
1692 }
1693
1694 const char *pixelShaderFunction = ptr;
1695 ptr += pixelShaderSize;
1696
1697 const char *vertexShaderFunction = ptr;
1698 ptr += vertexShaderSize;
1699
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001700 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1701 ptr += geometryShaderSize;
1702
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001703 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001704 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001705 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001706 {
1707 infoLog.append("Could not create pixel shader.");
1708 return false;
1709 }
1710
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001711 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001712 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001713 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001714 {
1715 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001716 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001717 mPixelExecutable = NULL;
1718 return false;
1719 }
1720
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001721 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1722 {
1723 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1724 geometryShaderSize, rx::SHADER_GEOMETRY);
1725 if (!mGeometryExecutable)
1726 {
1727 infoLog.append("Could not create geometry shader.");
1728 delete mPixelExecutable;
1729 mPixelExecutable = NULL;
1730 delete mVertexExecutable;
1731 mVertexExecutable = NULL;
1732 return false;
1733 }
1734 }
1735 else
1736 {
1737 mGeometryExecutable = NULL;
1738 }
1739
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740 return true;
1741}
1742
1743bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1744{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001745 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001747 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001748 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001749
1750 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1751 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001752 stream.write(mLinkedAttribute[i].type);
1753 stream.write(mLinkedAttribute[i].name);
1754 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001755 }
1756
1757 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1758 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001759 stream.write(mSamplersPS[i].active);
1760 stream.write(mSamplersPS[i].logicalTextureUnit);
1761 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 }
1763
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001764 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.write(mSamplersVS[i].active);
1767 stream.write(mSamplersVS[i].logicalTextureUnit);
1768 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001769 }
1770
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001771 stream.write(mUsedVertexSamplerRange);
1772 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001773 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001775 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1777 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001778 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001779 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001780 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001782
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001783 stream.write(mUniforms[i]->psRegisterIndex);
1784 stream.write(mUniforms[i]->vsRegisterIndex);
1785 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786 }
1787
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001788 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001789 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1790 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.write(mUniformIndex[i].name);
1792 stream.write(mUniformIndex[i].element);
1793 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794 }
1795
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001796 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001797 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001798
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001799 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001800 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001802 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1803 stream.write(geometryShaderSize);
1804
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001805 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001806
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001807 GLsizei streamLength = stream.length();
1808 const void *streamData = stream.data();
1809
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001810 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001811 if (totalLength > bufSize)
1812 {
1813 if (length)
1814 {
1815 *length = 0;
1816 }
1817
1818 return false;
1819 }
1820
1821 if (binary)
1822 {
1823 char *ptr = (char*) binary;
1824
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 memcpy(ptr, streamData, streamLength);
1826 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001827
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001828 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 ptr += sizeof(GUID);
1830
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001831 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001832 ptr += pixelShaderSize;
1833
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001834 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001835 ptr += vertexShaderSize;
1836
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001837 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1838 {
1839 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1840 ptr += geometryShaderSize;
1841 }
1842
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001843 ASSERT(ptr - totalLength == binary);
1844 }
1845
1846 if (length)
1847 {
1848 *length = totalLength;
1849 }
1850
1851 return true;
1852}
1853
1854GLint ProgramBinary::getLength()
1855{
1856 GLint length;
1857 if (save(NULL, INT_MAX, &length))
1858 {
1859 return length;
1860 }
1861 else
1862 {
1863 return 0;
1864 }
1865}
1866
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001867bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001868{
1869 if (!fragmentShader || !fragmentShader->isCompiled())
1870 {
1871 return false;
1872 }
1873
1874 if (!vertexShader || !vertexShader->isCompiled())
1875 {
1876 return false;
1877 }
1878
1879 std::string pixelHLSL = fragmentShader->getHLSL();
1880 std::string vertexHLSL = vertexShader->getHLSL();
1881
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001882 // Map the varyings to the register file
1883 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1884 int registers = packVaryings(infoLog, packing, fragmentShader);
1885
1886 if (registers < 0)
1887 {
1888 return false;
1889 }
1890
1891 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001892 {
1893 return false;
1894 }
1895
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001896 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001897 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1898 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001899
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001900 if (usesGeometryShader())
1901 {
1902 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1903 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1904 }
1905
1906 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001907 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001908 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001909 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001910
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001911 delete mVertexExecutable;
1912 mVertexExecutable = NULL;
1913 delete mPixelExecutable;
1914 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001915 delete mGeometryExecutable;
1916 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001917 }
1918
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001919 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1920 {
1921 success = false;
1922 }
1923
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001924 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001925 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001926 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001927 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001928
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001929 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001930}
1931
1932// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001933bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001934{
1935 unsigned int usedLocations = 0;
1936
1937 // Link attributes that have a binding location
1938 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1939 {
1940 int location = attributeBindings.getAttributeBinding(attribute->name);
1941
1942 if (location != -1) // Set by glBindAttribLocation
1943 {
1944 if (!mLinkedAttribute[location].name.empty())
1945 {
1946 // Multiple active attributes bound to the same location; not an error
1947 }
1948
1949 mLinkedAttribute[location] = *attribute;
1950
1951 int rows = VariableRowCount(attribute->type);
1952
1953 if (rows + location > MAX_VERTEX_ATTRIBS)
1954 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001955 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 +00001956
1957 return false;
1958 }
1959
1960 for (int i = 0; i < rows; i++)
1961 {
1962 usedLocations |= 1 << (location + i);
1963 }
1964 }
1965 }
1966
1967 // Link attributes that don't have a binding location
1968 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1969 {
1970 int location = attributeBindings.getAttributeBinding(attribute->name);
1971
1972 if (location == -1) // Not set by glBindAttribLocation
1973 {
1974 int rows = VariableRowCount(attribute->type);
1975 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1976
1977 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1978 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001979 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001980
1981 return false; // Fail to link
1982 }
1983
1984 mLinkedAttribute[availableIndex] = *attribute;
1985 }
1986 }
1987
1988 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1989 {
1990 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1991 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1992
1993 for (int r = 0; r < rows; r++)
1994 {
1995 mSemanticIndex[attributeIndex++] = index++;
1996 }
1997 }
1998
1999 return true;
2000}
2001
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002002bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002003{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002004 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002005 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002006 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002007 {
2008 return false;
2009 }
2010 }
2011
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002012 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002013 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002014 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002015 {
2016 return false;
2017 }
2018 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002019
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002020 return true;
2021}
2022
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002023bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002024{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002025 if (constant.type == GL_SAMPLER_2D ||
2026 constant.type == GL_SAMPLER_CUBE)
2027 {
2028 unsigned int samplerIndex = constant.registerIndex;
2029
2030 do
2031 {
2032 if (shader == GL_VERTEX_SHADER)
2033 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002034 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002035 {
2036 mSamplersVS[samplerIndex].active = true;
2037 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2038 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2039 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2040 }
2041 else
2042 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002043 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002044 return false;
2045 }
2046 }
2047 else if (shader == GL_FRAGMENT_SHADER)
2048 {
2049 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2050 {
2051 mSamplersPS[samplerIndex].active = true;
2052 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2053 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2054 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2055 }
2056 else
2057 {
2058 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2059 return false;
2060 }
2061 }
2062 else UNREACHABLE();
2063
2064 samplerIndex++;
2065 }
2066 while (samplerIndex < constant.registerIndex + constant.arraySize);
2067 }
2068
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002069 Uniform *uniform = NULL;
2070 GLint location = getUniformLocation(constant.name);
2071
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002072 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002073 {
2074 uniform = mUniforms[mUniformIndex[location].index];
2075
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002076 if (uniform->type != constant.type)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002077 {
shannon.woods@transgaming.coma09c70f2013-02-28 23:18:56 +00002078 infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
2079 return false;
2080 }
2081
2082 if (uniform->precision != constant.precision)
2083 {
2084 infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002085 return false;
2086 }
2087 }
2088 else
2089 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002090 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002091 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002092
2093 if (!uniform)
2094 {
2095 return false;
2096 }
2097
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002098 if (shader == GL_FRAGMENT_SHADER)
2099 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002100 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002101 }
2102 else if (shader == GL_VERTEX_SHADER)
2103 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002104 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002105 }
2106 else UNREACHABLE();
2107
2108 if (location >= 0)
2109 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002110 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002111 }
2112
2113 mUniforms.push_back(uniform);
2114 unsigned int uniformIndex = mUniforms.size() - 1;
2115
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002116 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002117 {
2118 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2119 }
2120
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002121 if (shader == GL_VERTEX_SHADER)
2122 {
2123 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2124 {
2125 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2126 return false;
2127 }
2128 }
2129 else if (shader == GL_FRAGMENT_SHADER)
2130 {
2131 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2132 {
2133 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2134 return false;
2135 }
2136 }
2137 else UNREACHABLE();
2138
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002139 return true;
2140}
2141
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002142std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2143{
2144 // for now we only handle point sprite emulation
2145 ASSERT(usesPointSpriteEmulation());
2146 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2147}
2148
2149std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2150{
2151 ASSERT(registers >= 0);
2152 ASSERT(vertexShader->mUsesPointSize);
2153 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2154
2155 std::string geomHLSL;
2156
2157 std::string varyingSemantic = "TEXCOORD";
2158
2159 std::string fragCoordSemantic;
2160 std::string pointCoordSemantic;
2161
2162 int reservedRegisterIndex = registers;
2163
2164 if (fragmentShader->mUsesFragCoord)
2165 {
2166 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2167 }
2168
2169 if (fragmentShader->mUsesPointCoord)
2170 {
2171 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2172 }
2173
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002174 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2175 "\n"
2176 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002177 "{\n";
2178
2179 for (int r = 0; r < registers; r++)
2180 {
2181 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2182
2183 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2184 }
2185
2186 if (fragmentShader->mUsesFragCoord)
2187 {
2188 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2189 }
2190
2191 geomHLSL += " float gl_PointSize : PSIZE;\n"
2192 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002193 "};\n"
2194 "\n"
2195 "struct GS_OUTPUT\n"
2196 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002197
2198 for (int r = 0; r < registers; r++)
2199 {
2200 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2201
2202 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2203 }
2204
2205 if (fragmentShader->mUsesFragCoord)
2206 {
2207 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2208 }
2209
2210 if (fragmentShader->mUsesPointCoord)
2211 {
2212 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2213 }
2214
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002215 geomHLSL += " float gl_PointSize : PSIZE;\n"
2216 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002217 "};\n"
2218 "\n"
2219 "static float2 pointSpriteCorners[] = \n"
2220 "{\n"
2221 " float2( 0.5f, -0.5f),\n"
2222 " float2( 0.5f, 0.5f),\n"
2223 " float2(-0.5f, -0.5f),\n"
2224 " float2(-0.5f, 0.5f)\n"
2225 "};\n"
2226 "\n"
2227 "static float2 pointSpriteTexcoords[] = \n"
2228 "{\n"
2229 " float2(1.0f, 1.0f),\n"
2230 " float2(1.0f, 0.0f),\n"
2231 " float2(0.0f, 1.0f),\n"
2232 " float2(0.0f, 0.0f)\n"
2233 "};\n"
2234 "\n"
2235 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2236 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2237 "\n"
2238 "[maxvertexcount(4)]\n"
2239 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2240 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002241 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2242 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002243
2244 for (int r = 0; r < registers; r++)
2245 {
2246 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2247 }
2248
2249 if (fragmentShader->mUsesFragCoord)
2250 {
2251 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2252 }
2253
2254 geomHLSL += " \n"
2255 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2256 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002257 " 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 +00002258
2259 for (int corner = 0; corner < 4; corner++)
2260 {
2261 geomHLSL += " \n"
2262 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2263
2264 if (fragmentShader->mUsesPointCoord)
2265 {
2266 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2267 }
2268
2269 geomHLSL += " outStream.Append(output);\n";
2270 }
2271
2272 geomHLSL += " \n"
2273 " outStream.RestartStrip();\n"
2274 "}\n";
2275
2276 return geomHLSL;
2277}
2278
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002279// This method needs to match OutputHLSL::decorate
2280std::string ProgramBinary::decorateAttribute(const std::string &name)
2281{
2282 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2283 {
2284 return "_" + name;
2285 }
2286
2287 return name;
2288}
2289
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002290bool ProgramBinary::isValidated() const
2291{
2292 return mValidated;
2293}
2294
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002295void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002296{
2297 // Skip over inactive attributes
2298 unsigned int activeAttribute = 0;
2299 unsigned int attribute;
2300 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2301 {
2302 if (mLinkedAttribute[attribute].name.empty())
2303 {
2304 continue;
2305 }
2306
2307 if (activeAttribute == index)
2308 {
2309 break;
2310 }
2311
2312 activeAttribute++;
2313 }
2314
2315 if (bufsize > 0)
2316 {
2317 const char *string = mLinkedAttribute[attribute].name.c_str();
2318
2319 strncpy(name, string, bufsize);
2320 name[bufsize - 1] = '\0';
2321
2322 if (length)
2323 {
2324 *length = strlen(name);
2325 }
2326 }
2327
2328 *size = 1; // Always a single 'type' instance
2329
2330 *type = mLinkedAttribute[attribute].type;
2331}
2332
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002333GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002334{
2335 int count = 0;
2336
2337 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2338 {
2339 if (!mLinkedAttribute[attributeIndex].name.empty())
2340 {
2341 count++;
2342 }
2343 }
2344
2345 return count;
2346}
2347
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002348GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002349{
2350 int maxLength = 0;
2351
2352 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2353 {
2354 if (!mLinkedAttribute[attributeIndex].name.empty())
2355 {
2356 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2357 }
2358 }
2359
2360 return maxLength;
2361}
2362
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002363void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002364{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002365 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002366
2367 if (bufsize > 0)
2368 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002369 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002370
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002371 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002372 {
2373 string += "[0]";
2374 }
2375
2376 strncpy(name, string.c_str(), bufsize);
2377 name[bufsize - 1] = '\0';
2378
2379 if (length)
2380 {
2381 *length = strlen(name);
2382 }
2383 }
2384
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002385 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002386
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002387 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388}
2389
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002390GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002391{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002392 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002393}
2394
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002395GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002396{
2397 int maxLength = 0;
2398
2399 unsigned int numUniforms = mUniforms.size();
2400 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2401 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002402 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002403 {
2404 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2405 if (mUniforms[uniformIndex]->isArray())
2406 {
2407 length += 3; // Counting in "[0]".
2408 }
2409 maxLength = std::max(length, maxLength);
2410 }
2411 }
2412
2413 return maxLength;
2414}
2415
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002416void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002417{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002418 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002419 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002420 {
2421 mValidated = false;
2422 }
2423 else
2424 {
2425 mValidated = true;
2426 }
2427}
2428
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002429bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002430{
2431 // if any two active samplers in a program are of different types, but refer to the same
2432 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2433 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2434
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002435 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002436 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002437
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002438 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002439 {
2440 textureUnitType[i] = TEXTURE_UNKNOWN;
2441 }
2442
2443 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2444 {
2445 if (mSamplersPS[i].active)
2446 {
2447 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2448
2449 if (unit >= maxCombinedTextureImageUnits)
2450 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002451 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002452 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002453 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002454 }
2455
2456 return false;
2457 }
2458
2459 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2460 {
2461 if (mSamplersPS[i].textureType != textureUnitType[unit])
2462 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002463 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002464 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002465 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002466 }
2467
2468 return false;
2469 }
2470 }
2471 else
2472 {
2473 textureUnitType[unit] = mSamplersPS[i].textureType;
2474 }
2475 }
2476 }
2477
2478 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2479 {
2480 if (mSamplersVS[i].active)
2481 {
2482 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2483
2484 if (unit >= maxCombinedTextureImageUnits)
2485 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002486 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002487 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002488 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002489 }
2490
2491 return false;
2492 }
2493
2494 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2495 {
2496 if (mSamplersVS[i].textureType != textureUnitType[unit])
2497 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002498 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002499 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002500 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002501 }
2502
2503 return false;
2504 }
2505 }
2506 else
2507 {
2508 textureUnitType[unit] = mSamplersVS[i].textureType;
2509 }
2510 }
2511 }
2512
2513 return true;
2514}
2515
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002516ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2517{
2518}
2519
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002520struct AttributeSorter
2521{
2522 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2523 : originalIndices(semanticIndices)
2524 {
2525 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2526 {
2527 indices[i] = i;
2528 }
2529
2530 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2531 }
2532
2533 bool operator()(int a, int b)
2534 {
2535 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2536 }
2537
2538 int indices[MAX_VERTEX_ATTRIBS];
2539 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2540};
2541
2542void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2543{
2544 AttributeSorter sorter(mSemanticIndex);
2545
2546 int oldIndices[MAX_VERTEX_ATTRIBS];
2547 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2548
2549 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2550 {
2551 oldIndices[i] = mSemanticIndex[i];
2552 oldTranslatedAttributes[i] = attributes[i];
2553 }
2554
2555 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2556 {
2557 int oldIndex = sorter.indices[i];
2558 sortedSemanticIndices[i] = oldIndices[oldIndex];
2559 attributes[i] = oldTranslatedAttributes[oldIndex];
2560 }
2561}
2562
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002563}