blob: 6a837939a5b55dceff42619f2669ef268185e265 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
24
daniel@transgaming.com88853c52012-12-20 20:56:40 +000025#undef near
26#undef far
27
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000028namespace gl
29{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030std::string str(int i)
31{
32 char buffer[20];
33 snprintf(buffer, sizeof(buffer), "%d", i);
34 return buffer;
35}
36
daniel@transgaming.comdb019952012-12-20 21:13:32 +000037UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
38 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000039{
40}
41
daniel@transgaming.come87ca002012-07-24 18:30:43 +000042unsigned int ProgramBinary::mCurrentSerial = 1;
43
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000044ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000045{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000046 mPixelExecutable = NULL;
47 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000048 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000049
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000050 mValidated = false;
51
52 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
53 {
54 mSemanticIndex[index] = -1;
55 }
56
57 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
58 {
59 mSamplersPS[index].active = false;
60 }
61
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000062 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000063 {
64 mSamplersVS[index].active = false;
65 }
66
67 mUsedVertexSamplerRange = 0;
68 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000069 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000070}
71
72ProgramBinary::~ProgramBinary()
73{
daniel@transgaming.com95892412012-11-28 20:59:09 +000074 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000075 mPixelExecutable = NULL;
76
daniel@transgaming.com95892412012-11-28 20:59:09 +000077 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000078 mVertexExecutable = NULL;
79
80 delete mGeometryExecutable;
81 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000082
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000083 while (!mUniforms.empty())
84 {
85 delete mUniforms.back();
86 mUniforms.pop_back();
87 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000088}
89
daniel@transgaming.come87ca002012-07-24 18:30:43 +000090unsigned int ProgramBinary::getSerial() const
91{
92 return mSerial;
93}
94
95unsigned int ProgramBinary::issueSerial()
96{
97 return mCurrentSerial++;
98}
99
daniel@transgaming.com95892412012-11-28 20:59:09 +0000100rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000101{
102 return mPixelExecutable;
103}
104
daniel@transgaming.com95892412012-11-28 20:59:09 +0000105rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106{
107 return mVertexExecutable;
108}
109
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000110rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
111{
112 return mGeometryExecutable;
113}
114
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000115GLuint ProgramBinary::getAttributeLocation(const char *name)
116{
117 if (name)
118 {
119 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
120 {
121 if (mLinkedAttribute[index].name == std::string(name))
122 {
123 return index;
124 }
125 }
126 }
127
128 return -1;
129}
130
131int ProgramBinary::getSemanticIndex(int attributeIndex)
132{
133 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
134
135 return mSemanticIndex[attributeIndex];
136}
137
138// Returns one more than the highest sampler index used.
139GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
140{
141 switch (type)
142 {
143 case SAMPLER_PIXEL:
144 return mUsedPixelSamplerRange;
145 case SAMPLER_VERTEX:
146 return mUsedVertexSamplerRange;
147 default:
148 UNREACHABLE();
149 return 0;
150 }
151}
152
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000153bool ProgramBinary::usesPointSize() const
154{
155 return mUsesPointSize;
156}
157
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000158bool ProgramBinary::usesPointSpriteEmulation() const
159{
160 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
161}
162
163bool ProgramBinary::usesGeometryShader() const
164{
165 return usesPointSpriteEmulation();
166}
167
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000168// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
169// index (0-15 for the pixel shader and 0-3 for the vertex shader).
170GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
171{
172 GLint logicalTextureUnit = -1;
173
174 switch (type)
175 {
176 case SAMPLER_PIXEL:
177 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
178
179 if (mSamplersPS[samplerIndex].active)
180 {
181 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
182 }
183 break;
184 case SAMPLER_VERTEX:
185 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
186
187 if (mSamplersVS[samplerIndex].active)
188 {
189 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
190 }
191 break;
192 default: UNREACHABLE();
193 }
194
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000195 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000196 {
197 return logicalTextureUnit;
198 }
199
200 return -1;
201}
202
203// Returns the texture type for a given Direct3D 9 sampler type and
204// index (0-15 for the pixel shader and 0-3 for the vertex shader).
205TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
206{
207 switch (type)
208 {
209 case SAMPLER_PIXEL:
210 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
211 ASSERT(mSamplersPS[samplerIndex].active);
212 return mSamplersPS[samplerIndex].textureType;
213 case SAMPLER_VERTEX:
214 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
215 ASSERT(mSamplersVS[samplerIndex].active);
216 return mSamplersVS[samplerIndex].textureType;
217 default: UNREACHABLE();
218 }
219
220 return TEXTURE_2D;
221}
222
223GLint ProgramBinary::getUniformLocation(std::string name)
224{
225 unsigned int subscript = 0;
226
227 // Strip any trailing array operator and retrieve the subscript
228 size_t open = name.find_last_of('[');
229 size_t close = name.find_last_of(']');
230 if (open != std::string::npos && close == name.length() - 1)
231 {
232 subscript = atoi(name.substr(open + 1).c_str());
233 name.erase(open);
234 }
235
236 unsigned int numUniforms = mUniformIndex.size();
237 for (unsigned int location = 0; location < numUniforms; location++)
238 {
239 if (mUniformIndex[location].name == name &&
240 mUniformIndex[location].element == subscript)
241 {
242 return location;
243 }
244 }
245
246 return -1;
247}
248
249bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
250{
251 if (location < 0 || location >= (int)mUniformIndex.size())
252 {
253 return false;
254 }
255
256 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
257 targetUniform->dirty = true;
258
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000259 int elementCount = targetUniform->elementCount();
260
261 if (elementCount == 1 && count > 1)
262 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
263
264 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
265
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000266 if (targetUniform->type == GL_FLOAT)
267 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000268 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
269
270 for (int i = 0; i < count; i++)
271 {
272 target[0] = v[0];
273 target[1] = 0;
274 target[2] = 0;
275 target[3] = 0;
276 target += 4;
277 v += 1;
278 }
279 }
280 else if (targetUniform->type == GL_BOOL)
281 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000282 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000283
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000284 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000285 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000286 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
287 boolParams[1] = GL_FALSE;
288 boolParams[2] = GL_FALSE;
289 boolParams[3] = GL_FALSE;
290 boolParams += 4;
291 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000292 }
293 }
294 else
295 {
296 return false;
297 }
298
299 return true;
300}
301
302bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
303{
304 if (location < 0 || location >= (int)mUniformIndex.size())
305 {
306 return false;
307 }
308
309 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
310 targetUniform->dirty = true;
311
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000312 int elementCount = targetUniform->elementCount();
313
314 if (elementCount == 1 && count > 1)
315 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
316
317 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
318
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000319 if (targetUniform->type == GL_FLOAT_VEC2)
320 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000321 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
322
323 for (int i = 0; i < count; i++)
324 {
325 target[0] = v[0];
326 target[1] = v[1];
327 target[2] = 0;
328 target[3] = 0;
329 target += 4;
330 v += 2;
331 }
332 }
333 else if (targetUniform->type == GL_BOOL_VEC2)
334 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000335 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000336
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000337 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000338 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000339 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
340 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
341 boolParams[2] = GL_FALSE;
342 boolParams[3] = GL_FALSE;
343 boolParams += 4;
344 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000345 }
346 }
347 else
348 {
349 return false;
350 }
351
352 return true;
353}
354
355bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
356{
357 if (location < 0 || location >= (int)mUniformIndex.size())
358 {
359 return false;
360 }
361
362 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
363 targetUniform->dirty = true;
364
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000365 int elementCount = targetUniform->elementCount();
366
367 if (elementCount == 1 && count > 1)
368 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
369
370 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
371
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000372 if (targetUniform->type == GL_FLOAT_VEC3)
373 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000374 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
375
376 for (int i = 0; i < count; i++)
377 {
378 target[0] = v[0];
379 target[1] = v[1];
380 target[2] = v[2];
381 target[3] = 0;
382 target += 4;
383 v += 3;
384 }
385 }
386 else if (targetUniform->type == GL_BOOL_VEC3)
387 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000388 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000389
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000390 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000391 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000392 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
393 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
394 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
395 boolParams[3] = GL_FALSE;
396 boolParams += 4;
397 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398 }
399 }
400 else
401 {
402 return false;
403 }
404
405 return true;
406}
407
408bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
409{
410 if (location < 0 || location >= (int)mUniformIndex.size())
411 {
412 return false;
413 }
414
415 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
416 targetUniform->dirty = true;
417
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000418 int elementCount = targetUniform->elementCount();
419
420 if (elementCount == 1 && count > 1)
421 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
422
423 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
424
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000425 if (targetUniform->type == GL_FLOAT_VEC4)
426 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000427 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000428
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000429 for (int i = 0; i < count; i++)
430 {
431 target[0] = v[0];
432 target[1] = v[1];
433 target[2] = v[2];
434 target[3] = v[3];
435 target += 4;
436 v += 4;
437 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000438 }
439 else if (targetUniform->type == GL_BOOL_VEC4)
440 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000441 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000442
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000443 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000444 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000445 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
446 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
447 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
448 boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
449 boolParams += 4;
450 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000451 }
452 }
453 else
454 {
455 return false;
456 }
457
458 return true;
459}
460
461template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
462void transposeMatrix(T *target, const GLfloat *value)
463{
464 int copyWidth = std::min(targetWidth, srcWidth);
465 int copyHeight = std::min(targetHeight, srcHeight);
466
467 for (int x = 0; x < copyWidth; x++)
468 {
469 for (int y = 0; y < copyHeight; y++)
470 {
471 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
472 }
473 }
474 // clear unfilled right side
475 for (int y = 0; y < copyHeight; y++)
476 {
477 for (int x = srcWidth; x < targetWidth; x++)
478 {
479 target[y * targetWidth + x] = (T)0;
480 }
481 }
482 // clear unfilled bottom.
483 for (int y = srcHeight; y < targetHeight; y++)
484 {
485 for (int x = 0; x < targetWidth; x++)
486 {
487 target[y * targetWidth + x] = (T)0;
488 }
489 }
490}
491
492bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
493{
494 if (location < 0 || location >= (int)mUniformIndex.size())
495 {
496 return false;
497 }
498
499 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
500 targetUniform->dirty = true;
501
502 if (targetUniform->type != GL_FLOAT_MAT2)
503 {
504 return false;
505 }
506
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000507 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000508
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000509 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000510 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
511
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000512 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000513 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000514
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000515 for (int i = 0; i < count; i++)
516 {
517 transposeMatrix<GLfloat,4,2,2,2>(target, value);
518 target += 8;
519 value += 4;
520 }
521
522 return true;
523}
524
525bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
526{
527 if (location < 0 || location >= (int)mUniformIndex.size())
528 {
529 return false;
530 }
531
532 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
533 targetUniform->dirty = true;
534
535 if (targetUniform->type != GL_FLOAT_MAT3)
536 {
537 return false;
538 }
539
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000540 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000541
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000542 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000543 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
544
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000545 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000546 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000547
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000548 for (int i = 0; i < count; i++)
549 {
550 transposeMatrix<GLfloat,4,3,3,3>(target, value);
551 target += 12;
552 value += 9;
553 }
554
555 return true;
556}
557
558
559bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
560{
561 if (location < 0 || location >= (int)mUniformIndex.size())
562 {
563 return false;
564 }
565
566 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
567 targetUniform->dirty = true;
568
569 if (targetUniform->type != GL_FLOAT_MAT4)
570 {
571 return false;
572 }
573
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000574 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000575
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000576 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000577 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
578
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000579 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000580 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000581
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000582 for (int i = 0; i < count; i++)
583 {
584 transposeMatrix<GLfloat,4,4,4,4>(target, value);
585 target += 16;
586 value += 16;
587 }
588
589 return true;
590}
591
592bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
593{
594 if (location < 0 || location >= (int)mUniformIndex.size())
595 {
596 return false;
597 }
598
599 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
600 targetUniform->dirty = true;
601
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000602 int elementCount = targetUniform->elementCount();
603
604 if (elementCount == 1 && count > 1)
605 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
606
607 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
608
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000609 if (targetUniform->type == GL_INT ||
610 targetUniform->type == GL_SAMPLER_2D ||
611 targetUniform->type == GL_SAMPLER_CUBE)
612 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000613 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000615 for (int i = 0; i < count; i++)
616 {
617 target[0] = v[0];
618 target[1] = 0;
619 target[2] = 0;
620 target[3] = 0;
621 target += 4;
622 v += 1;
623 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624 }
625 else if (targetUniform->type == GL_BOOL)
626 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000627 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000629 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000630 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000631 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
632 boolParams[1] = GL_FALSE;
633 boolParams[2] = GL_FALSE;
634 boolParams[3] = GL_FALSE;
635 boolParams += 4;
636 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000637 }
638 }
639 else
640 {
641 return false;
642 }
643
644 return true;
645}
646
647bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
648{
649 if (location < 0 || location >= (int)mUniformIndex.size())
650 {
651 return false;
652 }
653
654 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
655 targetUniform->dirty = true;
656
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000657 int elementCount = targetUniform->elementCount();
658
659 if (elementCount == 1 && count > 1)
660 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
661
662 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
663
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000664 if (targetUniform->type == GL_INT_VEC2)
665 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000666 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000668 for (int i = 0; i < count; i++)
669 {
670 target[0] = v[0];
671 target[1] = v[1];
672 target[2] = 0;
673 target[3] = 0;
674 target += 4;
675 v += 2;
676 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000677 }
678 else if (targetUniform->type == GL_BOOL_VEC2)
679 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000680 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000681
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000682 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000683 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000684 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
685 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
686 boolParams[2] = GL_FALSE;
687 boolParams[3] = GL_FALSE;
688 boolParams += 4;
689 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000690 }
691 }
692 else
693 {
694 return false;
695 }
696
697 return true;
698}
699
700bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
701{
702 if (location < 0 || location >= (int)mUniformIndex.size())
703 {
704 return false;
705 }
706
707 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
708 targetUniform->dirty = true;
709
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000710 int elementCount = targetUniform->elementCount();
711
712 if (elementCount == 1 && count > 1)
713 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
714
715 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
716
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000717 if (targetUniform->type == GL_INT_VEC3)
718 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000719 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000721 for (int i = 0; i < count; i++)
722 {
723 target[0] = v[0];
724 target[1] = v[1];
725 target[2] = v[2];
726 target[3] = 0;
727 target += 4;
728 v += 3;
729 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000730 }
731 else if (targetUniform->type == GL_BOOL_VEC3)
732 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000733 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000734
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000735 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000736 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000737 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
738 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
739 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
740 boolParams[3] = GL_FALSE;
741 boolParams += 4;
742 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000743 }
744 }
745 else
746 {
747 return false;
748 }
749
750 return true;
751}
752
753bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
754{
755 if (location < 0 || location >= (int)mUniformIndex.size())
756 {
757 return false;
758 }
759
760 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
761 targetUniform->dirty = true;
762
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000763 int elementCount = targetUniform->elementCount();
764
765 if (elementCount == 1 && count > 1)
766 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
767
768 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
769
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000770 if (targetUniform->type == GL_INT_VEC4)
771 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000772 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000774 for (int i = 0; i < count; i++)
775 {
776 target[0] = v[0];
777 target[1] = v[1];
778 target[2] = v[2];
779 target[3] = v[3];
780 target += 4;
781 v += 4;
782 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000783 }
784 else if (targetUniform->type == GL_BOOL_VEC4)
785 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000786 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000787
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000788 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000789 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000790 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
791 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
792 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
793 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
794 boolParams += 4;
795 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000796 }
797 }
798 else
799 {
800 return false;
801 }
802
803 return true;
804}
805
806bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
807{
808 if (location < 0 || location >= (int)mUniformIndex.size())
809 {
810 return false;
811 }
812
813 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
814
815 // sized queries -- ensure the provided buffer is large enough
816 if (bufSize)
817 {
818 int requiredBytes = UniformExternalSize(targetUniform->type);
819 if (*bufSize < requiredBytes)
820 {
821 return false;
822 }
823 }
824
825 switch (targetUniform->type)
826 {
827 case GL_FLOAT_MAT2:
828 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
829 break;
830 case GL_FLOAT_MAT3:
831 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
832 break;
833 case GL_FLOAT_MAT4:
834 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
835 break;
836 default:
837 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000838 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000839
840 switch (UniformComponentType(targetUniform->type))
841 {
842 case GL_BOOL:
843 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000844 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000845
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000846 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000847 {
848 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
849 }
850 }
851 break;
852 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000853 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
854 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000855 break;
856 case GL_INT:
857 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000858 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000859
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000860 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000861 {
862 params[i] = (float)intParams[i];
863 }
864 }
865 break;
866 default: UNREACHABLE();
867 }
868 }
869 }
870
871 return true;
872}
873
874bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
875{
876 if (location < 0 || location >= (int)mUniformIndex.size())
877 {
878 return false;
879 }
880
881 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
882
883 // sized queries -- ensure the provided buffer is large enough
884 if (bufSize)
885 {
886 int requiredBytes = UniformExternalSize(targetUniform->type);
887 if (*bufSize < requiredBytes)
888 {
889 return false;
890 }
891 }
892
893 switch (targetUniform->type)
894 {
895 case GL_FLOAT_MAT2:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000896 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000897 break;
898 case GL_FLOAT_MAT3:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000899 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000900 break;
901 case GL_FLOAT_MAT4:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000902 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000903 break;
904 default:
905 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000906 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000907
908 switch (UniformComponentType(targetUniform->type))
909 {
910 case GL_BOOL:
911 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000912 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000913
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000914 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000915 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000916 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000917 }
918 }
919 break;
920 case GL_FLOAT:
921 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000922 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000923
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000924 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000925 {
926 params[i] = (GLint)floatParams[i];
927 }
928 }
929 break;
930 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000931 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
932 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000933 break;
934 default: UNREACHABLE();
935 }
936 }
937 }
938
939 return true;
940}
941
942void ProgramBinary::dirtyAllUniforms()
943{
944 unsigned int numUniforms = mUniforms.size();
945 for (unsigned int index = 0; index < numUniforms; index++)
946 {
947 mUniforms[index]->dirty = true;
948 }
949}
950
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000951// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000952void ProgramBinary::applyUniforms()
953{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000954 // Retrieve sampler uniform values
955 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
956 {
957 Uniform *targetUniform = *ub;
958
959 if (targetUniform->dirty)
960 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000961 if (targetUniform->type == GL_SAMPLER_2D ||
962 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000963 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000964 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000965 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000966
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000967 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000968 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000969 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000970
971 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000972 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000973 unsigned int samplerIndex = firstIndex + i;
974
975 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000976 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000977 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000978 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000979 }
980 }
981 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000982
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000983 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000984 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000985 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000986
987 for (int i = 0; i < count; i++)
988 {
989 unsigned int samplerIndex = firstIndex + i;
990
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000991 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000992 {
993 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000994 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000995 }
996 }
997 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000998 }
999 }
1000 }
1001
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +00001002 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001003}
1004
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001005// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1006// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001007int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001008{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001009 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001010
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001011 fragmentShader->resetVaryingsRegisterAssignment();
1012
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001013 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1014 {
1015 int n = VariableRowCount(varying->type) * varying->size;
1016 int m = VariableColumnCount(varying->type);
1017 bool success = false;
1018
1019 if (m == 2 || m == 3 || m == 4)
1020 {
1021 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1022 {
1023 bool available = true;
1024
1025 for (int y = 0; y < n && available; y++)
1026 {
1027 for (int x = 0; x < m && available; x++)
1028 {
1029 if (packing[r + y][x])
1030 {
1031 available = false;
1032 }
1033 }
1034 }
1035
1036 if (available)
1037 {
1038 varying->reg = r;
1039 varying->col = 0;
1040
1041 for (int y = 0; y < n; y++)
1042 {
1043 for (int x = 0; x < m; x++)
1044 {
1045 packing[r + y][x] = &*varying;
1046 }
1047 }
1048
1049 success = true;
1050 }
1051 }
1052
1053 if (!success && m == 2)
1054 {
1055 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1056 {
1057 bool available = true;
1058
1059 for (int y = 0; y < n && available; y++)
1060 {
1061 for (int x = 2; x < 4 && available; x++)
1062 {
1063 if (packing[r + y][x])
1064 {
1065 available = false;
1066 }
1067 }
1068 }
1069
1070 if (available)
1071 {
1072 varying->reg = r;
1073 varying->col = 2;
1074
1075 for (int y = 0; y < n; y++)
1076 {
1077 for (int x = 2; x < 4; x++)
1078 {
1079 packing[r + y][x] = &*varying;
1080 }
1081 }
1082
1083 success = true;
1084 }
1085 }
1086 }
1087 }
1088 else if (m == 1)
1089 {
1090 int space[4] = {0};
1091
1092 for (int y = 0; y < maxVaryingVectors; y++)
1093 {
1094 for (int x = 0; x < 4; x++)
1095 {
1096 space[x] += packing[y][x] ? 0 : 1;
1097 }
1098 }
1099
1100 int column = 0;
1101
1102 for (int x = 0; x < 4; x++)
1103 {
1104 if (space[x] >= n && space[x] < space[column])
1105 {
1106 column = x;
1107 }
1108 }
1109
1110 if (space[column] >= n)
1111 {
1112 for (int r = 0; r < maxVaryingVectors; r++)
1113 {
1114 if (!packing[r][column])
1115 {
1116 varying->reg = r;
1117
1118 for (int y = r; y < r + n; y++)
1119 {
1120 packing[y][column] = &*varying;
1121 }
1122
1123 break;
1124 }
1125 }
1126
1127 varying->col = column;
1128
1129 success = true;
1130 }
1131 }
1132 else UNREACHABLE();
1133
1134 if (!success)
1135 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001136 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001137
1138 return -1;
1139 }
1140 }
1141
1142 // Return the number of used registers
1143 int registers = 0;
1144
1145 for (int r = 0; r < maxVaryingVectors; r++)
1146 {
1147 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1148 {
1149 registers++;
1150 }
1151 }
1152
1153 return registers;
1154}
1155
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001156bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1157 std::string& pixelHLSL, std::string& vertexHLSL,
1158 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001159{
1160 if (pixelHLSL.empty() || vertexHLSL.empty())
1161 {
1162 return false;
1163 }
1164
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001165 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001166 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001167 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001168
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001169 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1170
1171 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001172 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001173 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001174
1175 return false;
1176 }
1177
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001178 vertexShader->resetVaryingsRegisterAssignment();
1179
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001180 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1181 {
1182 bool matched = false;
1183
1184 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1185 {
1186 if (output->name == input->name)
1187 {
1188 if (output->type != input->type || output->size != input->size)
1189 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001190 infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001191
1192 return false;
1193 }
1194
1195 output->reg = input->reg;
1196 output->col = input->col;
1197
1198 matched = true;
1199 break;
1200 }
1201 }
1202
1203 if (!matched)
1204 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001205 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001206
1207 return false;
1208 }
1209 }
1210
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001211 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001212 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001213 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001214 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1215
1216 // special varyings that use reserved registers
1217 int reservedRegisterIndex = registers;
1218 std::string fragCoordSemantic;
1219 std::string pointCoordSemantic;
1220
1221 if (fragmentShader->mUsesFragCoord)
1222 {
1223 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1224 }
1225
1226 if (fragmentShader->mUsesPointCoord)
1227 {
1228 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1229 // In DX11 we compute this in the GS.
1230 if (shaderModel == 3)
1231 {
1232 pointCoordSemantic = "TEXCOORD0";
1233 }
1234 else if (shaderModel >= 4)
1235 {
1236 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1237 }
1238 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239
1240 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001241 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 int semanticIndex = 0;
1244 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1245 {
1246 switch (attribute->type)
1247 {
1248 case GL_FLOAT: vertexHLSL += " float "; break;
1249 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1250 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1251 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1252 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1253 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1254 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1255 default: UNREACHABLE();
1256 }
1257
1258 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1259
1260 semanticIndex += VariableRowCount(attribute->type);
1261 }
1262
1263 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001264 "\n"
1265 "struct VS_OUTPUT\n"
1266 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001267
1268 for (int r = 0; r < registers; r++)
1269 {
1270 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1271
1272 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1273 }
1274
1275 if (fragmentShader->mUsesFragCoord)
1276 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001277 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278 }
1279
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001280 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281 {
1282 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1283 }
1284
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001285 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"
1286 "};\n"
1287 "\n"
1288 "VS_OUTPUT main(VS_INPUT input)\n"
1289 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001290
1291 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1292 {
1293 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1294
1295 if (VariableRowCount(attribute->type) > 1) // Matrix
1296 {
1297 vertexHLSL += "transpose";
1298 }
1299
1300 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1301 }
1302
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001303 if (shaderModel >= 4)
1304 {
1305 vertexHLSL += "\n"
1306 " gl_main();\n"
1307 "\n"
1308 " VS_OUTPUT output;\n"
1309 " output.gl_Position.x = gl_Position.x;\n"
1310 " output.gl_Position.y = -gl_Position.y;\n"
1311 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1312 " output.gl_Position.w = gl_Position.w;\n";
1313 }
1314 else
1315 {
1316 vertexHLSL += "\n"
1317 " gl_main();\n"
1318 "\n"
1319 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001320 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1321 " 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 +00001322 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1323 " output.gl_Position.w = gl_Position.w;\n";
1324 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001325
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001326 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001327 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001328 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001329 }
1330
1331 if (fragmentShader->mUsesFragCoord)
1332 {
1333 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1334 }
1335
1336 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1337 {
1338 if (varying->reg >= 0)
1339 {
1340 for (int i = 0; i < varying->size; i++)
1341 {
1342 int rows = VariableRowCount(varying->type);
1343
1344 for (int j = 0; j < rows; j++)
1345 {
1346 int r = varying->reg + i * rows + j;
1347 vertexHLSL += " output.v" + str(r);
1348
1349 bool sharedRegister = false; // Register used by multiple varyings
1350
1351 for (int x = 0; x < 4; x++)
1352 {
1353 if (packing[r][x] && packing[r][x] != packing[r][0])
1354 {
1355 sharedRegister = true;
1356 break;
1357 }
1358 }
1359
1360 if(sharedRegister)
1361 {
1362 vertexHLSL += ".";
1363
1364 for (int x = 0; x < 4; x++)
1365 {
1366 if (packing[r][x] == &*varying)
1367 {
1368 switch(x)
1369 {
1370 case 0: vertexHLSL += "x"; break;
1371 case 1: vertexHLSL += "y"; break;
1372 case 2: vertexHLSL += "z"; break;
1373 case 3: vertexHLSL += "w"; break;
1374 }
1375 }
1376 }
1377 }
1378
1379 vertexHLSL += " = " + varying->name;
1380
1381 if (varying->array)
1382 {
1383 vertexHLSL += "[" + str(i) + "]";
1384 }
1385
1386 if (rows > 1)
1387 {
1388 vertexHLSL += "[" + str(j) + "]";
1389 }
1390
1391 vertexHLSL += ";\n";
1392 }
1393 }
1394 }
1395 }
1396
1397 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001398 " return output;\n"
1399 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001400
1401 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001402 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001403
1404 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1405 {
1406 if (varying->reg >= 0)
1407 {
1408 for (int i = 0; i < varying->size; i++)
1409 {
1410 int rows = VariableRowCount(varying->type);
1411 for (int j = 0; j < rows; j++)
1412 {
1413 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001414 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001415 }
1416 }
1417 }
1418 else UNREACHABLE();
1419 }
1420
1421 if (fragmentShader->mUsesFragCoord)
1422 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001423 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001424 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001425
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001426 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1427 {
1428 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1429 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001430
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001431 // Must consume the PSIZE element if the geometry shader is not active
1432 // We won't know if we use a GS until we draw
1433 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1434 {
1435 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1436 }
1437
1438 if (fragmentShader->mUsesFragCoord)
1439 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001440 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001441 {
1442 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1443 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001444 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001445 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001446 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1447 }
1448 }
1449
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001450 pixelHLSL += "};\n"
1451 "\n"
1452 "struct PS_OUTPUT\n"
1453 "{\n"
1454 " float4 gl_Color[1] : " + targetSemantic + ";\n"
1455 "};\n"
1456 "\n";
1457
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458 if (fragmentShader->mUsesFrontFacing)
1459 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001460 if (shaderModel >= 4)
1461 {
1462 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1463 "{\n";
1464 }
1465 else
1466 {
1467 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1468 "{\n";
1469 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001470 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001471 else
1472 {
1473 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1474 "{\n";
1475 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001476
1477 if (fragmentShader->mUsesFragCoord)
1478 {
1479 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1480
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001481 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001482 {
1483 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1484 " gl_FragCoord.y = input.dx_VPos.y;\n";
1485 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001486 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001487 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001488 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001489 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001490 }
1491 else
1492 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001493 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1494 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1495 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001496 }
1497
daniel@transgaming.com12985182012-12-20 20:56:31 +00001498 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001499 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001500 }
1501
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001502 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001503 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001504 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1505 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001506 }
1507
1508 if (fragmentShader->mUsesFrontFacing)
1509 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001510 if (shaderModel <= 3)
1511 {
1512 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1513 }
1514 else
1515 {
1516 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1517 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001518 }
1519
1520 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1521 {
1522 if (varying->reg >= 0)
1523 {
1524 for (int i = 0; i < varying->size; i++)
1525 {
1526 int rows = VariableRowCount(varying->type);
1527 for (int j = 0; j < rows; j++)
1528 {
1529 std::string n = str(varying->reg + i * rows + j);
1530 pixelHLSL += " " + varying->name;
1531
1532 if (varying->array)
1533 {
1534 pixelHLSL += "[" + str(i) + "]";
1535 }
1536
1537 if (rows > 1)
1538 {
1539 pixelHLSL += "[" + str(j) + "]";
1540 }
1541
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001542 switch (VariableColumnCount(varying->type))
1543 {
1544 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1545 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1546 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1547 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1548 default: UNREACHABLE();
1549 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001550 }
1551 }
1552 }
1553 else UNREACHABLE();
1554 }
1555
1556 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001557 " gl_main();\n"
1558 "\n"
1559 " PS_OUTPUT output;\n"
1560 " output.gl_Color[0] = gl_Color[0];\n"
1561 "\n"
1562 " return output;\n"
1563 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001564
1565 return true;
1566}
1567
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001568bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1569{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001570 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571
1572 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001573 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001574 if (format != GL_PROGRAM_BINARY_ANGLE)
1575 {
1576 infoLog.append("Invalid program binary format.");
1577 return false;
1578 }
1579
1580 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001581 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001582 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001583 {
1584 infoLog.append("Invalid program binary version.");
1585 return false;
1586 }
1587
1588 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1589 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001590 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001591 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001592 stream.read(&name);
1593 mLinkedAttribute[i].name = name;
1594 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001595 }
1596
1597 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1598 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 stream.read(&mSamplersPS[i].active);
1600 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601
1602 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001603 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001604 mSamplersPS[i].textureType = (TextureType) textureType;
1605 }
1606
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001607 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001608 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001609 stream.read(&mSamplersVS[i].active);
1610 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001611
1612 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001613 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614 mSamplersVS[i].textureType = (TextureType) textureType;
1615 }
1616
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001617 stream.read(&mUsedVertexSamplerRange);
1618 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001619 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001620
1621 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&size);
1623 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001624 {
1625 infoLog.append("Invalid program binary.");
1626 return false;
1627 }
1628
1629 mUniforms.resize(size);
1630 for (unsigned int i = 0; i < size; ++i)
1631 {
1632 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001633 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001634 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001635 unsigned int arraySize;
1636
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001637 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001638 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001639 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001640 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001642 mUniforms[i] = new Uniform(type, precision, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001644 stream.read(&mUniforms[i]->psRegisterIndex);
1645 stream.read(&mUniforms[i]->vsRegisterIndex);
1646 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001647 }
1648
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001649 stream.read(&size);
1650 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651 {
1652 infoLog.append("Invalid program binary.");
1653 return false;
1654 }
1655
1656 mUniformIndex.resize(size);
1657 for (unsigned int i = 0; i < size; ++i)
1658 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001659 stream.read(&mUniformIndex[i].name);
1660 stream.read(&mUniformIndex[i].element);
1661 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 }
1663
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001665 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666
1667 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001668 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001670 unsigned int geometryShaderSize;
1671 stream.read(&geometryShaderSize);
1672
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
daniel@transgaming.com36038542012-11-28 20:59:26 +00001675 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001676 ptr += sizeof(GUID);
1677
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001678 GUID identifier = mRenderer->getAdapterIdentifier();
1679 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001680 {
1681 infoLog.append("Invalid program binary.");
1682 return false;
1683 }
1684
1685 const char *pixelShaderFunction = ptr;
1686 ptr += pixelShaderSize;
1687
1688 const char *vertexShaderFunction = ptr;
1689 ptr += vertexShaderSize;
1690
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001691 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1692 ptr += geometryShaderSize;
1693
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001694 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001695 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001696 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697 {
1698 infoLog.append("Could not create pixel shader.");
1699 return false;
1700 }
1701
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001702 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001703 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001704 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705 {
1706 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001707 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708 mPixelExecutable = NULL;
1709 return false;
1710 }
1711
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001712 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1713 {
1714 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1715 geometryShaderSize, rx::SHADER_GEOMETRY);
1716 if (!mGeometryExecutable)
1717 {
1718 infoLog.append("Could not create geometry shader.");
1719 delete mPixelExecutable;
1720 mPixelExecutable = NULL;
1721 delete mVertexExecutable;
1722 mVertexExecutable = NULL;
1723 return false;
1724 }
1725 }
1726 else
1727 {
1728 mGeometryExecutable = NULL;
1729 }
1730
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001731 return true;
1732}
1733
1734bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1735{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001736 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001737
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001738 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001739 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
1741 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1742 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 stream.write(mLinkedAttribute[i].type);
1744 stream.write(mLinkedAttribute[i].name);
1745 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746 }
1747
1748 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1749 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001750 stream.write(mSamplersPS[i].active);
1751 stream.write(mSamplersPS[i].logicalTextureUnit);
1752 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001753 }
1754
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001755 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001756 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001757 stream.write(mSamplersVS[i].active);
1758 stream.write(mSamplersVS[i].logicalTextureUnit);
1759 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760 }
1761
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001762 stream.write(mUsedVertexSamplerRange);
1763 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001764 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1768 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001769 stream.write(mUniforms[i]->type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001770 stream.write(mUniforms[i]->precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001771 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001772 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001773
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001774 stream.write(mUniforms[i]->psRegisterIndex);
1775 stream.write(mUniforms[i]->vsRegisterIndex);
1776 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777 }
1778
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001779 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1781 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.write(mUniformIndex[i].name);
1783 stream.write(mUniformIndex[i].element);
1784 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001785 }
1786
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001787 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001788 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001789
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001790 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001792
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001793 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1794 stream.write(geometryShaderSize);
1795
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001796 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001797
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 GLsizei streamLength = stream.length();
1799 const void *streamData = stream.data();
1800
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001801 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001802 if (totalLength > bufSize)
1803 {
1804 if (length)
1805 {
1806 *length = 0;
1807 }
1808
1809 return false;
1810 }
1811
1812 if (binary)
1813 {
1814 char *ptr = (char*) binary;
1815
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 memcpy(ptr, streamData, streamLength);
1817 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001818
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001819 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820 ptr += sizeof(GUID);
1821
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001822 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823 ptr += pixelShaderSize;
1824
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001825 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001826 ptr += vertexShaderSize;
1827
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001828 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1829 {
1830 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1831 ptr += geometryShaderSize;
1832 }
1833
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834 ASSERT(ptr - totalLength == binary);
1835 }
1836
1837 if (length)
1838 {
1839 *length = totalLength;
1840 }
1841
1842 return true;
1843}
1844
1845GLint ProgramBinary::getLength()
1846{
1847 GLint length;
1848 if (save(NULL, INT_MAX, &length))
1849 {
1850 return length;
1851 }
1852 else
1853 {
1854 return 0;
1855 }
1856}
1857
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001858bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001859{
1860 if (!fragmentShader || !fragmentShader->isCompiled())
1861 {
1862 return false;
1863 }
1864
1865 if (!vertexShader || !vertexShader->isCompiled())
1866 {
1867 return false;
1868 }
1869
1870 std::string pixelHLSL = fragmentShader->getHLSL();
1871 std::string vertexHLSL = vertexShader->getHLSL();
1872
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001873 // Map the varyings to the register file
1874 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1875 int registers = packVaryings(infoLog, packing, fragmentShader);
1876
1877 if (registers < 0)
1878 {
1879 return false;
1880 }
1881
1882 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001883 {
1884 return false;
1885 }
1886
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001887 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001888 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1889 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001890
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001891 if (usesGeometryShader())
1892 {
1893 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1894 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1895 }
1896
1897 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001898 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001899 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001900 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001901
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001902 delete mVertexExecutable;
1903 mVertexExecutable = NULL;
1904 delete mPixelExecutable;
1905 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001906 delete mGeometryExecutable;
1907 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001908 }
1909
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001910 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1911 {
1912 success = false;
1913 }
1914
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001915 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001916 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001917 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001918 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001919
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001920 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001921}
1922
1923// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001924bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001925{
1926 unsigned int usedLocations = 0;
1927
1928 // Link attributes that have a binding location
1929 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1930 {
1931 int location = attributeBindings.getAttributeBinding(attribute->name);
1932
1933 if (location != -1) // Set by glBindAttribLocation
1934 {
1935 if (!mLinkedAttribute[location].name.empty())
1936 {
1937 // Multiple active attributes bound to the same location; not an error
1938 }
1939
1940 mLinkedAttribute[location] = *attribute;
1941
1942 int rows = VariableRowCount(attribute->type);
1943
1944 if (rows + location > MAX_VERTEX_ATTRIBS)
1945 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001946 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 +00001947
1948 return false;
1949 }
1950
1951 for (int i = 0; i < rows; i++)
1952 {
1953 usedLocations |= 1 << (location + i);
1954 }
1955 }
1956 }
1957
1958 // Link attributes that don't have a binding location
1959 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1960 {
1961 int location = attributeBindings.getAttributeBinding(attribute->name);
1962
1963 if (location == -1) // Not set by glBindAttribLocation
1964 {
1965 int rows = VariableRowCount(attribute->type);
1966 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1967
1968 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1969 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001970 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001971
1972 return false; // Fail to link
1973 }
1974
1975 mLinkedAttribute[availableIndex] = *attribute;
1976 }
1977 }
1978
1979 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1980 {
1981 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1982 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1983
1984 for (int r = 0; r < rows; r++)
1985 {
1986 mSemanticIndex[attributeIndex++] = index++;
1987 }
1988 }
1989
1990 return true;
1991}
1992
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001993bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001994{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001995 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001996 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001997 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001998 {
1999 return false;
2000 }
2001 }
2002
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002003 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002004 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002005 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002006 {
2007 return false;
2008 }
2009 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002010
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002011 return true;
2012}
2013
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002014bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002015{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002016 if (constant.type == GL_SAMPLER_2D ||
2017 constant.type == GL_SAMPLER_CUBE)
2018 {
2019 unsigned int samplerIndex = constant.registerIndex;
2020
2021 do
2022 {
2023 if (shader == GL_VERTEX_SHADER)
2024 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002025 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002026 {
2027 mSamplersVS[samplerIndex].active = true;
2028 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2029 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2030 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2031 }
2032 else
2033 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002034 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002035 return false;
2036 }
2037 }
2038 else if (shader == GL_FRAGMENT_SHADER)
2039 {
2040 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2041 {
2042 mSamplersPS[samplerIndex].active = true;
2043 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2044 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2045 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2046 }
2047 else
2048 {
2049 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2050 return false;
2051 }
2052 }
2053 else UNREACHABLE();
2054
2055 samplerIndex++;
2056 }
2057 while (samplerIndex < constant.registerIndex + constant.arraySize);
2058 }
2059
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002060 Uniform *uniform = NULL;
2061 GLint location = getUniformLocation(constant.name);
2062
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002063 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002064 {
2065 uniform = mUniforms[mUniformIndex[location].index];
2066
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002067 if (uniform->type != constant.type || uniform->precision != constant.precision)
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002068 {
2069 return false;
2070 }
2071 }
2072 else
2073 {
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002074 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002075 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002076
2077 if (!uniform)
2078 {
2079 return false;
2080 }
2081
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002082 if (shader == GL_FRAGMENT_SHADER)
2083 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002084 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002085 }
2086 else if (shader == GL_VERTEX_SHADER)
2087 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002088 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002089 }
2090 else UNREACHABLE();
2091
2092 if (location >= 0)
2093 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002094 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002095 }
2096
2097 mUniforms.push_back(uniform);
2098 unsigned int uniformIndex = mUniforms.size() - 1;
2099
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002100 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002101 {
2102 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2103 }
2104
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002105 if (shader == GL_VERTEX_SHADER)
2106 {
2107 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2108 {
2109 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2110 return false;
2111 }
2112 }
2113 else if (shader == GL_FRAGMENT_SHADER)
2114 {
2115 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2116 {
2117 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2118 return false;
2119 }
2120 }
2121 else UNREACHABLE();
2122
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002123 return true;
2124}
2125
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002126std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2127{
2128 // for now we only handle point sprite emulation
2129 ASSERT(usesPointSpriteEmulation());
2130 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2131}
2132
2133std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2134{
2135 ASSERT(registers >= 0);
2136 ASSERT(vertexShader->mUsesPointSize);
2137 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2138
2139 std::string geomHLSL;
2140
2141 std::string varyingSemantic = "TEXCOORD";
2142
2143 std::string fragCoordSemantic;
2144 std::string pointCoordSemantic;
2145
2146 int reservedRegisterIndex = registers;
2147
2148 if (fragmentShader->mUsesFragCoord)
2149 {
2150 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2151 }
2152
2153 if (fragmentShader->mUsesPointCoord)
2154 {
2155 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2156 }
2157
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002158 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2159 "\n"
2160 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002161 "{\n";
2162
2163 for (int r = 0; r < registers; r++)
2164 {
2165 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2166
2167 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2168 }
2169
2170 if (fragmentShader->mUsesFragCoord)
2171 {
2172 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2173 }
2174
2175 geomHLSL += " float gl_PointSize : PSIZE;\n"
2176 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002177 "};\n"
2178 "\n"
2179 "struct GS_OUTPUT\n"
2180 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002181
2182 for (int r = 0; r < registers; r++)
2183 {
2184 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2185
2186 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2187 }
2188
2189 if (fragmentShader->mUsesFragCoord)
2190 {
2191 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2192 }
2193
2194 if (fragmentShader->mUsesPointCoord)
2195 {
2196 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2197 }
2198
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002199 geomHLSL += " float gl_PointSize : PSIZE;\n"
2200 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002201 "};\n"
2202 "\n"
2203 "static float2 pointSpriteCorners[] = \n"
2204 "{\n"
2205 " float2( 0.5f, -0.5f),\n"
2206 " float2( 0.5f, 0.5f),\n"
2207 " float2(-0.5f, -0.5f),\n"
2208 " float2(-0.5f, 0.5f)\n"
2209 "};\n"
2210 "\n"
2211 "static float2 pointSpriteTexcoords[] = \n"
2212 "{\n"
2213 " float2(1.0f, 1.0f),\n"
2214 " float2(1.0f, 0.0f),\n"
2215 " float2(0.0f, 1.0f),\n"
2216 " float2(0.0f, 0.0f)\n"
2217 "};\n"
2218 "\n"
2219 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2220 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2221 "\n"
2222 "[maxvertexcount(4)]\n"
2223 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2224 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002225 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2226 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002227
2228 for (int r = 0; r < registers; r++)
2229 {
2230 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2231 }
2232
2233 if (fragmentShader->mUsesFragCoord)
2234 {
2235 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2236 }
2237
2238 geomHLSL += " \n"
2239 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2240 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002241 " 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 +00002242
2243 for (int corner = 0; corner < 4; corner++)
2244 {
2245 geomHLSL += " \n"
2246 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2247
2248 if (fragmentShader->mUsesPointCoord)
2249 {
2250 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2251 }
2252
2253 geomHLSL += " outStream.Append(output);\n";
2254 }
2255
2256 geomHLSL += " \n"
2257 " outStream.RestartStrip();\n"
2258 "}\n";
2259
2260 return geomHLSL;
2261}
2262
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002263// This method needs to match OutputHLSL::decorate
2264std::string ProgramBinary::decorateAttribute(const std::string &name)
2265{
2266 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2267 {
2268 return "_" + name;
2269 }
2270
2271 return name;
2272}
2273
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274bool ProgramBinary::isValidated() const
2275{
2276 return mValidated;
2277}
2278
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002279void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002280{
2281 // Skip over inactive attributes
2282 unsigned int activeAttribute = 0;
2283 unsigned int attribute;
2284 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2285 {
2286 if (mLinkedAttribute[attribute].name.empty())
2287 {
2288 continue;
2289 }
2290
2291 if (activeAttribute == index)
2292 {
2293 break;
2294 }
2295
2296 activeAttribute++;
2297 }
2298
2299 if (bufsize > 0)
2300 {
2301 const char *string = mLinkedAttribute[attribute].name.c_str();
2302
2303 strncpy(name, string, bufsize);
2304 name[bufsize - 1] = '\0';
2305
2306 if (length)
2307 {
2308 *length = strlen(name);
2309 }
2310 }
2311
2312 *size = 1; // Always a single 'type' instance
2313
2314 *type = mLinkedAttribute[attribute].type;
2315}
2316
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002317GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002318{
2319 int count = 0;
2320
2321 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2322 {
2323 if (!mLinkedAttribute[attributeIndex].name.empty())
2324 {
2325 count++;
2326 }
2327 }
2328
2329 return count;
2330}
2331
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002332GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002333{
2334 int maxLength = 0;
2335
2336 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2337 {
2338 if (!mLinkedAttribute[attributeIndex].name.empty())
2339 {
2340 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2341 }
2342 }
2343
2344 return maxLength;
2345}
2346
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002347void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002348{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002349 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002350
2351 if (bufsize > 0)
2352 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002353 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002354
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002355 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002356 {
2357 string += "[0]";
2358 }
2359
2360 strncpy(name, string.c_str(), bufsize);
2361 name[bufsize - 1] = '\0';
2362
2363 if (length)
2364 {
2365 *length = strlen(name);
2366 }
2367 }
2368
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002369 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002370
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002371 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002372}
2373
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002374GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002375{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002376 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002377}
2378
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002379GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002380{
2381 int maxLength = 0;
2382
2383 unsigned int numUniforms = mUniforms.size();
2384 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2385 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002386 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002387 {
2388 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2389 if (mUniforms[uniformIndex]->isArray())
2390 {
2391 length += 3; // Counting in "[0]".
2392 }
2393 maxLength = std::max(length, maxLength);
2394 }
2395 }
2396
2397 return maxLength;
2398}
2399
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002400void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002401{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002402 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002403 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002404 {
2405 mValidated = false;
2406 }
2407 else
2408 {
2409 mValidated = true;
2410 }
2411}
2412
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002413bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002414{
2415 // if any two active samplers in a program are of different types, but refer to the same
2416 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2417 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2418
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002419 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002420 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002421
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002422 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002423 {
2424 textureUnitType[i] = TEXTURE_UNKNOWN;
2425 }
2426
2427 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2428 {
2429 if (mSamplersPS[i].active)
2430 {
2431 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2432
2433 if (unit >= maxCombinedTextureImageUnits)
2434 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002435 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002436 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002437 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002438 }
2439
2440 return false;
2441 }
2442
2443 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2444 {
2445 if (mSamplersPS[i].textureType != textureUnitType[unit])
2446 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002447 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002448 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002449 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002450 }
2451
2452 return false;
2453 }
2454 }
2455 else
2456 {
2457 textureUnitType[unit] = mSamplersPS[i].textureType;
2458 }
2459 }
2460 }
2461
2462 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2463 {
2464 if (mSamplersVS[i].active)
2465 {
2466 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2467
2468 if (unit >= maxCombinedTextureImageUnits)
2469 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002470 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002471 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002472 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002473 }
2474
2475 return false;
2476 }
2477
2478 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2479 {
2480 if (mSamplersVS[i].textureType != textureUnitType[unit])
2481 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002482 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002483 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002484 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002485 }
2486
2487 return false;
2488 }
2489 }
2490 else
2491 {
2492 textureUnitType[unit] = mSamplersVS[i].textureType;
2493 }
2494 }
2495 }
2496
2497 return true;
2498}
2499
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002500ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2501{
2502}
2503
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002504struct AttributeSorter
2505{
2506 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2507 : originalIndices(semanticIndices)
2508 {
2509 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2510 {
2511 indices[i] = i;
2512 }
2513
2514 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2515 }
2516
2517 bool operator()(int a, int b)
2518 {
2519 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2520 }
2521
2522 int indices[MAX_VERTEX_ATTRIBS];
2523 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2524};
2525
2526void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2527{
2528 AttributeSorter sorter(mSemanticIndex);
2529
2530 int oldIndices[MAX_VERTEX_ATTRIBS];
2531 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2532
2533 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2534 {
2535 oldIndices[i] = mSemanticIndex[i];
2536 oldTranslatedAttributes[i] = attributes[i];
2537 }
2538
2539 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2540 {
2541 int oldIndex = sorter.indices[i];
2542 sortedSemanticIndices[i] = oldIndices[oldIndex];
2543 attributes[i] = oldTranslatedAttributes[oldIndex];
2544 }
2545}
2546
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002547}