blob: 4651dbd6eb43f61bc45068b103dbefd483e61d16 [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000012#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000013
14#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000015#include "common/version.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000016#include "utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000017
18#include "libGLESv2/main.h"
19#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000020#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000021#include "libGLESv2/renderer/Renderer.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000022
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/Renderer.h"
24#include "libGLESv2/renderer/VertexDataManager.h"
25
26#include <algorithm>
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000027
daniel@transgaming.com88853c52012-12-20 20:56:40 +000028#undef near
29#undef far
30
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031namespace gl
32{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000033std::string str(int i)
34{
35 char buffer[20];
36 snprintf(buffer, sizeof(buffer), "%d", i);
37 return buffer;
38}
39
daniel@transgaming.comdb019952012-12-20 21:13:32 +000040UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
41 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000042{
43}
44
daniel@transgaming.come87ca002012-07-24 18:30:43 +000045unsigned int ProgramBinary::mCurrentSerial = 1;
46
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000047ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000048{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000049 mPixelExecutable = NULL;
50 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000051 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000052
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000053 mValidated = false;
54
55 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
56 {
57 mSemanticIndex[index] = -1;
58 }
59
60 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
61 {
62 mSamplersPS[index].active = false;
63 }
64
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000065 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000066 {
67 mSamplersVS[index].active = false;
68 }
69
70 mUsedVertexSamplerRange = 0;
71 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000072 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000073}
74
75ProgramBinary::~ProgramBinary()
76{
daniel@transgaming.com95892412012-11-28 20:59:09 +000077 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000078 mPixelExecutable = NULL;
79
daniel@transgaming.com95892412012-11-28 20:59:09 +000080 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000081 mVertexExecutable = NULL;
82
83 delete mGeometryExecutable;
84 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000085
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000086 while (!mUniforms.empty())
87 {
88 delete mUniforms.back();
89 mUniforms.pop_back();
90 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000091}
92
daniel@transgaming.come87ca002012-07-24 18:30:43 +000093unsigned int ProgramBinary::getSerial() const
94{
95 return mSerial;
96}
97
98unsigned int ProgramBinary::issueSerial()
99{
100 return mCurrentSerial++;
101}
102
daniel@transgaming.com95892412012-11-28 20:59:09 +0000103rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000104{
105 return mPixelExecutable;
106}
107
daniel@transgaming.com95892412012-11-28 20:59:09 +0000108rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000109{
110 return mVertexExecutable;
111}
112
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000113rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
114{
115 return mGeometryExecutable;
116}
117
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118GLuint ProgramBinary::getAttributeLocation(const char *name)
119{
120 if (name)
121 {
122 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
123 {
124 if (mLinkedAttribute[index].name == std::string(name))
125 {
126 return index;
127 }
128 }
129 }
130
131 return -1;
132}
133
134int ProgramBinary::getSemanticIndex(int attributeIndex)
135{
136 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
137
138 return mSemanticIndex[attributeIndex];
139}
140
141// Returns one more than the highest sampler index used.
142GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
143{
144 switch (type)
145 {
146 case SAMPLER_PIXEL:
147 return mUsedPixelSamplerRange;
148 case SAMPLER_VERTEX:
149 return mUsedVertexSamplerRange;
150 default:
151 UNREACHABLE();
152 return 0;
153 }
154}
155
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000156bool ProgramBinary::usesPointSize() const
157{
158 return mUsesPointSize;
159}
160
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000161bool ProgramBinary::usesPointSpriteEmulation() const
162{
163 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
164}
165
166bool ProgramBinary::usesGeometryShader() const
167{
168 return usesPointSpriteEmulation();
169}
170
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000171// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
172// index (0-15 for the pixel shader and 0-3 for the vertex shader).
173GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
174{
175 GLint logicalTextureUnit = -1;
176
177 switch (type)
178 {
179 case SAMPLER_PIXEL:
180 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
181
182 if (mSamplersPS[samplerIndex].active)
183 {
184 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
185 }
186 break;
187 case SAMPLER_VERTEX:
188 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
189
190 if (mSamplersVS[samplerIndex].active)
191 {
192 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
193 }
194 break;
195 default: UNREACHABLE();
196 }
197
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000198 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000199 {
200 return logicalTextureUnit;
201 }
202
203 return -1;
204}
205
206// Returns the texture type for a given Direct3D 9 sampler type and
207// index (0-15 for the pixel shader and 0-3 for the vertex shader).
208TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
209{
210 switch (type)
211 {
212 case SAMPLER_PIXEL:
213 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
214 ASSERT(mSamplersPS[samplerIndex].active);
215 return mSamplersPS[samplerIndex].textureType;
216 case SAMPLER_VERTEX:
217 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
218 ASSERT(mSamplersVS[samplerIndex].active);
219 return mSamplersVS[samplerIndex].textureType;
220 default: UNREACHABLE();
221 }
222
223 return TEXTURE_2D;
224}
225
226GLint ProgramBinary::getUniformLocation(std::string name)
227{
228 unsigned int subscript = 0;
229
230 // Strip any trailing array operator and retrieve the subscript
231 size_t open = name.find_last_of('[');
232 size_t close = name.find_last_of(']');
233 if (open != std::string::npos && close == name.length() - 1)
234 {
235 subscript = atoi(name.substr(open + 1).c_str());
236 name.erase(open);
237 }
238
239 unsigned int numUniforms = mUniformIndex.size();
240 for (unsigned int location = 0; location < numUniforms; location++)
241 {
242 if (mUniformIndex[location].name == name &&
243 mUniformIndex[location].element == subscript)
244 {
245 return location;
246 }
247 }
248
249 return -1;
250}
251
252bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
253{
254 if (location < 0 || location >= (int)mUniformIndex.size())
255 {
256 return false;
257 }
258
259 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
260 targetUniform->dirty = true;
261
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000262 int elementCount = targetUniform->elementCount();
263
264 if (elementCount == 1 && count > 1)
265 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
266
267 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
268
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000269 if (targetUniform->type == GL_FLOAT)
270 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000271 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
272
273 for (int i = 0; i < count; i++)
274 {
275 target[0] = v[0];
276 target[1] = 0;
277 target[2] = 0;
278 target[3] = 0;
279 target += 4;
280 v += 1;
281 }
282 }
283 else if (targetUniform->type == GL_BOOL)
284 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000285 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000286
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000287 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000288 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000289 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
290 boolParams[1] = GL_FALSE;
291 boolParams[2] = GL_FALSE;
292 boolParams[3] = GL_FALSE;
293 boolParams += 4;
294 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000295 }
296 }
297 else
298 {
299 return false;
300 }
301
302 return true;
303}
304
305bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
306{
307 if (location < 0 || location >= (int)mUniformIndex.size())
308 {
309 return false;
310 }
311
312 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
313 targetUniform->dirty = true;
314
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000315 int elementCount = targetUniform->elementCount();
316
317 if (elementCount == 1 && count > 1)
318 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
319
320 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
321
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000322 if (targetUniform->type == GL_FLOAT_VEC2)
323 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000324 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
325
326 for (int i = 0; i < count; i++)
327 {
328 target[0] = v[0];
329 target[1] = v[1];
330 target[2] = 0;
331 target[3] = 0;
332 target += 4;
333 v += 2;
334 }
335 }
336 else if (targetUniform->type == GL_BOOL_VEC2)
337 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000338 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000339
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000340 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000341 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000342 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
343 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
344 boolParams[2] = GL_FALSE;
345 boolParams[3] = GL_FALSE;
346 boolParams += 4;
347 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000348 }
349 }
350 else
351 {
352 return false;
353 }
354
355 return true;
356}
357
358bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
359{
360 if (location < 0 || location >= (int)mUniformIndex.size())
361 {
362 return false;
363 }
364
365 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
366 targetUniform->dirty = true;
367
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000368 int elementCount = targetUniform->elementCount();
369
370 if (elementCount == 1 && count > 1)
371 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
372
373 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
374
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000375 if (targetUniform->type == GL_FLOAT_VEC3)
376 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
378
379 for (int i = 0; i < count; i++)
380 {
381 target[0] = v[0];
382 target[1] = v[1];
383 target[2] = v[2];
384 target[3] = 0;
385 target += 4;
386 v += 3;
387 }
388 }
389 else if (targetUniform->type == GL_BOOL_VEC3)
390 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000391 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000393 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000395 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
396 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
397 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
398 boolParams[3] = GL_FALSE;
399 boolParams += 4;
400 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000401 }
402 }
403 else
404 {
405 return false;
406 }
407
408 return true;
409}
410
411bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
412{
413 if (location < 0 || location >= (int)mUniformIndex.size())
414 {
415 return false;
416 }
417
418 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
419 targetUniform->dirty = true;
420
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000421 int elementCount = targetUniform->elementCount();
422
423 if (elementCount == 1 && count > 1)
424 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
425
426 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
427
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000428 if (targetUniform->type == GL_FLOAT_VEC4)
429 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000430 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000431
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000432 for (int i = 0; i < count; i++)
433 {
434 target[0] = v[0];
435 target[1] = v[1];
436 target[2] = v[2];
437 target[3] = v[3];
438 target += 4;
439 v += 4;
440 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000441 }
442 else if (targetUniform->type == GL_BOOL_VEC4)
443 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000444 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000446 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000447 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000448 boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
449 boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
450 boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
451 boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
452 boolParams += 4;
453 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000454 }
455 }
456 else
457 {
458 return false;
459 }
460
461 return true;
462}
463
464template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
465void transposeMatrix(T *target, const GLfloat *value)
466{
467 int copyWidth = std::min(targetWidth, srcWidth);
468 int copyHeight = std::min(targetHeight, srcHeight);
469
470 for (int x = 0; x < copyWidth; x++)
471 {
472 for (int y = 0; y < copyHeight; y++)
473 {
474 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
475 }
476 }
477 // clear unfilled right side
478 for (int y = 0; y < copyHeight; y++)
479 {
480 for (int x = srcWidth; x < targetWidth; x++)
481 {
482 target[y * targetWidth + x] = (T)0;
483 }
484 }
485 // clear unfilled bottom.
486 for (int y = srcHeight; y < targetHeight; y++)
487 {
488 for (int x = 0; x < targetWidth; x++)
489 {
490 target[y * targetWidth + x] = (T)0;
491 }
492 }
493}
494
495bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
496{
497 if (location < 0 || location >= (int)mUniformIndex.size())
498 {
499 return false;
500 }
501
502 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
503 targetUniform->dirty = true;
504
505 if (targetUniform->type != GL_FLOAT_MAT2)
506 {
507 return false;
508 }
509
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000510 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000511
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000512 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000513 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
514
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000515 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000516 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000517
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000518 for (int i = 0; i < count; i++)
519 {
520 transposeMatrix<GLfloat,4,2,2,2>(target, value);
521 target += 8;
522 value += 4;
523 }
524
525 return true;
526}
527
528bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
529{
530 if (location < 0 || location >= (int)mUniformIndex.size())
531 {
532 return false;
533 }
534
535 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
536 targetUniform->dirty = true;
537
538 if (targetUniform->type != GL_FLOAT_MAT3)
539 {
540 return false;
541 }
542
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000543 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000544
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000545 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000546 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
547
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000548 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000549 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000550
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000551 for (int i = 0; i < count; i++)
552 {
553 transposeMatrix<GLfloat,4,3,3,3>(target, value);
554 target += 12;
555 value += 9;
556 }
557
558 return true;
559}
560
561
562bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
563{
564 if (location < 0 || location >= (int)mUniformIndex.size())
565 {
566 return false;
567 }
568
569 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
570 targetUniform->dirty = true;
571
572 if (targetUniform->type != GL_FLOAT_MAT4)
573 {
574 return false;
575 }
576
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000577 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000579 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000580 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
581
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000582 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000583 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000584
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000585 for (int i = 0; i < count; i++)
586 {
587 transposeMatrix<GLfloat,4,4,4,4>(target, value);
588 target += 16;
589 value += 16;
590 }
591
592 return true;
593}
594
595bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
596{
597 if (location < 0 || location >= (int)mUniformIndex.size())
598 {
599 return false;
600 }
601
602 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
603 targetUniform->dirty = true;
604
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000605 int elementCount = targetUniform->elementCount();
606
607 if (elementCount == 1 && count > 1)
608 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
609
610 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
611
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000612 if (targetUniform->type == GL_INT ||
613 targetUniform->type == GL_SAMPLER_2D ||
614 targetUniform->type == GL_SAMPLER_CUBE)
615 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000616 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000617
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000618 for (int i = 0; i < count; i++)
619 {
620 target[0] = v[0];
621 target[1] = 0;
622 target[2] = 0;
623 target[3] = 0;
624 target += 4;
625 v += 1;
626 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000627 }
628 else if (targetUniform->type == GL_BOOL)
629 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000630 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000632 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000633 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000634 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
635 boolParams[1] = GL_FALSE;
636 boolParams[2] = GL_FALSE;
637 boolParams[3] = GL_FALSE;
638 boolParams += 4;
639 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000640 }
641 }
642 else
643 {
644 return false;
645 }
646
647 return true;
648}
649
650bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
651{
652 if (location < 0 || location >= (int)mUniformIndex.size())
653 {
654 return false;
655 }
656
657 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
658 targetUniform->dirty = true;
659
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000660 int elementCount = targetUniform->elementCount();
661
662 if (elementCount == 1 && count > 1)
663 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
664
665 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
666
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000667 if (targetUniform->type == GL_INT_VEC2)
668 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000669 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000670
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000671 for (int i = 0; i < count; i++)
672 {
673 target[0] = v[0];
674 target[1] = v[1];
675 target[2] = 0;
676 target[3] = 0;
677 target += 4;
678 v += 2;
679 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000680 }
681 else if (targetUniform->type == GL_BOOL_VEC2)
682 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000683 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000684
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000685 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000686 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000687 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
688 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
689 boolParams[2] = GL_FALSE;
690 boolParams[3] = GL_FALSE;
691 boolParams += 4;
692 v += 2;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693 }
694 }
695 else
696 {
697 return false;
698 }
699
700 return true;
701}
702
703bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
704{
705 if (location < 0 || location >= (int)mUniformIndex.size())
706 {
707 return false;
708 }
709
710 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
711 targetUniform->dirty = true;
712
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000713 int elementCount = targetUniform->elementCount();
714
715 if (elementCount == 1 && count > 1)
716 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
717
718 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
719
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720 if (targetUniform->type == GL_INT_VEC3)
721 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000722 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000723
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000724 for (int i = 0; i < count; i++)
725 {
726 target[0] = v[0];
727 target[1] = v[1];
728 target[2] = v[2];
729 target[3] = 0;
730 target += 4;
731 v += 3;
732 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733 }
734 else if (targetUniform->type == GL_BOOL_VEC3)
735 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000736 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000737
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000738 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000739 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000740 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
741 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
742 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
743 boolParams[3] = GL_FALSE;
744 boolParams += 4;
745 v += 3;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000746 }
747 }
748 else
749 {
750 return false;
751 }
752
753 return true;
754}
755
756bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
757{
758 if (location < 0 || location >= (int)mUniformIndex.size())
759 {
760 return false;
761 }
762
763 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
764 targetUniform->dirty = true;
765
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000766 int elementCount = targetUniform->elementCount();
767
768 if (elementCount == 1 && count > 1)
769 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
770
771 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
772
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773 if (targetUniform->type == GL_INT_VEC4)
774 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000775 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000776
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000777 for (int i = 0; i < count; i++)
778 {
779 target[0] = v[0];
780 target[1] = v[1];
781 target[2] = v[2];
782 target[3] = v[3];
783 target += 4;
784 v += 4;
785 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000786 }
787 else if (targetUniform->type == GL_BOOL_VEC4)
788 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000789 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000790
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000791 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000792 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000793 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
794 boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
795 boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
796 boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
797 boolParams += 4;
798 v += 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000799 }
800 }
801 else
802 {
803 return false;
804 }
805
806 return true;
807}
808
809bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
810{
811 if (location < 0 || location >= (int)mUniformIndex.size())
812 {
813 return false;
814 }
815
816 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
817
818 // sized queries -- ensure the provided buffer is large enough
819 if (bufSize)
820 {
821 int requiredBytes = UniformExternalSize(targetUniform->type);
822 if (*bufSize < requiredBytes)
823 {
824 return false;
825 }
826 }
827
828 switch (targetUniform->type)
829 {
830 case GL_FLOAT_MAT2:
831 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
832 break;
833 case GL_FLOAT_MAT3:
834 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
835 break;
836 case GL_FLOAT_MAT4:
837 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
838 break;
839 default:
840 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000841 unsigned int size = UniformComponentCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000842
843 switch (UniformComponentType(targetUniform->type))
844 {
845 case GL_BOOL:
846 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000847 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000848
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000849 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000850 {
851 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
852 }
853 }
854 break;
855 case GL_FLOAT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000856 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
857 size * sizeof(GLfloat));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000858 break;
859 case GL_INT:
860 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000861 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000862
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000863 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000864 {
865 params[i] = (float)intParams[i];
866 }
867 }
868 break;
869 default: UNREACHABLE();
870 }
871 }
872 }
873
874 return true;
875}
876
877bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
878{
879 if (location < 0 || location >= (int)mUniformIndex.size())
880 {
881 return false;
882 }
883
884 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
885
886 // sized queries -- ensure the provided buffer is large enough
887 if (bufSize)
888 {
889 int requiredBytes = UniformExternalSize(targetUniform->type);
890 if (*bufSize < requiredBytes)
891 {
892 return false;
893 }
894 }
895
896 switch (targetUniform->type)
897 {
898 case GL_FLOAT_MAT2:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000899 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000900 break;
901 case GL_FLOAT_MAT3:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000902 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000903 break;
904 case GL_FLOAT_MAT4:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000905 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000906 break;
907 default:
908 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000909 unsigned int size = VariableColumnCount(targetUniform->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000910
911 switch (UniformComponentType(targetUniform->type))
912 {
913 case GL_BOOL:
914 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000915 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000916
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000917 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000918 {
shannon.woods@transgaming.comcd714ef2013-02-28 23:09:50 +0000919 params[i] = boolParams[i];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000920 }
921 }
922 break;
923 case GL_FLOAT:
924 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000925 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000926
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000927 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000928 {
929 params[i] = (GLint)floatParams[i];
930 }
931 }
932 break;
933 case GL_INT:
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000934 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
935 size * sizeof(GLint));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000936 break;
937 default: UNREACHABLE();
938 }
939 }
940 }
941
942 return true;
943}
944
945void ProgramBinary::dirtyAllUniforms()
946{
947 unsigned int numUniforms = mUniforms.size();
948 for (unsigned int index = 0; index < numUniforms; index++)
949 {
950 mUniforms[index]->dirty = true;
951 }
952}
953
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000954// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000955void ProgramBinary::applyUniforms()
956{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000957 // Retrieve sampler uniform values
958 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
959 {
960 Uniform *targetUniform = *ub;
961
962 if (targetUniform->dirty)
963 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000964 if (targetUniform->type == GL_SAMPLER_2D ||
965 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000966 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000967 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000968 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000969
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000970 if (targetUniform->psRegisterIndex >= 0)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000971 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000972 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000973
974 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000975 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000976 unsigned int samplerIndex = firstIndex + i;
977
978 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000979 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000980 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000981 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000982 }
983 }
984 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000985
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000986 if (targetUniform->vsRegisterIndex >= 0)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000987 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000988 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000989
990 for (int i = 0; i < count; i++)
991 {
992 unsigned int samplerIndex = firstIndex + i;
993
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000994 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000995 {
996 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000997 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000998 }
999 }
1000 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +00001001 }
1002 }
1003 }
1004
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +00001005 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001006}
1007
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001008// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1009// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001010int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001011{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001012 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001013
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001014 fragmentShader->resetVaryingsRegisterAssignment();
1015
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001016 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1017 {
1018 int n = VariableRowCount(varying->type) * varying->size;
1019 int m = VariableColumnCount(varying->type);
1020 bool success = false;
1021
1022 if (m == 2 || m == 3 || m == 4)
1023 {
1024 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1025 {
1026 bool available = true;
1027
1028 for (int y = 0; y < n && available; y++)
1029 {
1030 for (int x = 0; x < m && available; x++)
1031 {
1032 if (packing[r + y][x])
1033 {
1034 available = false;
1035 }
1036 }
1037 }
1038
1039 if (available)
1040 {
1041 varying->reg = r;
1042 varying->col = 0;
1043
1044 for (int y = 0; y < n; y++)
1045 {
1046 for (int x = 0; x < m; x++)
1047 {
1048 packing[r + y][x] = &*varying;
1049 }
1050 }
1051
1052 success = true;
1053 }
1054 }
1055
1056 if (!success && m == 2)
1057 {
1058 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1059 {
1060 bool available = true;
1061
1062 for (int y = 0; y < n && available; y++)
1063 {
1064 for (int x = 2; x < 4 && available; x++)
1065 {
1066 if (packing[r + y][x])
1067 {
1068 available = false;
1069 }
1070 }
1071 }
1072
1073 if (available)
1074 {
1075 varying->reg = r;
1076 varying->col = 2;
1077
1078 for (int y = 0; y < n; y++)
1079 {
1080 for (int x = 2; x < 4; x++)
1081 {
1082 packing[r + y][x] = &*varying;
1083 }
1084 }
1085
1086 success = true;
1087 }
1088 }
1089 }
1090 }
1091 else if (m == 1)
1092 {
1093 int space[4] = {0};
1094
1095 for (int y = 0; y < maxVaryingVectors; y++)
1096 {
1097 for (int x = 0; x < 4; x++)
1098 {
1099 space[x] += packing[y][x] ? 0 : 1;
1100 }
1101 }
1102
1103 int column = 0;
1104
1105 for (int x = 0; x < 4; x++)
1106 {
1107 if (space[x] >= n && space[x] < space[column])
1108 {
1109 column = x;
1110 }
1111 }
1112
1113 if (space[column] >= n)
1114 {
1115 for (int r = 0; r < maxVaryingVectors; r++)
1116 {
1117 if (!packing[r][column])
1118 {
1119 varying->reg = r;
1120
1121 for (int y = r; y < r + n; y++)
1122 {
1123 packing[y][column] = &*varying;
1124 }
1125
1126 break;
1127 }
1128 }
1129
1130 varying->col = column;
1131
1132 success = true;
1133 }
1134 }
1135 else UNREACHABLE();
1136
1137 if (!success)
1138 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001139 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001140
1141 return -1;
1142 }
1143 }
1144
1145 // Return the number of used registers
1146 int registers = 0;
1147
1148 for (int r = 0; r < maxVaryingVectors; r++)
1149 {
1150 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1151 {
1152 registers++;
1153 }
1154 }
1155
1156 return registers;
1157}
1158
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001159bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1160 std::string& pixelHLSL, std::string& vertexHLSL,
1161 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001162{
1163 if (pixelHLSL.empty() || vertexHLSL.empty())
1164 {
1165 return false;
1166 }
1167
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001168 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001169 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001170 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001171
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001172 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1173
1174 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001176 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001177
1178 return false;
1179 }
1180
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001181 vertexShader->resetVaryingsRegisterAssignment();
1182
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001183 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1184 {
1185 bool matched = false;
1186
1187 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1188 {
1189 if (output->name == input->name)
1190 {
1191 if (output->type != input->type || output->size != input->size)
1192 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001193 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 +00001194
1195 return false;
1196 }
1197
1198 output->reg = input->reg;
1199 output->col = input->col;
1200
1201 matched = true;
1202 break;
1203 }
1204 }
1205
1206 if (!matched)
1207 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001208 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001209
1210 return false;
1211 }
1212 }
1213
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001214 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001215 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001216 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001217 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1218
1219 // special varyings that use reserved registers
1220 int reservedRegisterIndex = registers;
1221 std::string fragCoordSemantic;
1222 std::string pointCoordSemantic;
1223
1224 if (fragmentShader->mUsesFragCoord)
1225 {
1226 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1227 }
1228
1229 if (fragmentShader->mUsesPointCoord)
1230 {
1231 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1232 // In DX11 we compute this in the GS.
1233 if (shaderModel == 3)
1234 {
1235 pointCoordSemantic = "TEXCOORD0";
1236 }
1237 else if (shaderModel >= 4)
1238 {
1239 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1240 }
1241 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001244 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001245
1246 int semanticIndex = 0;
1247 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1248 {
1249 switch (attribute->type)
1250 {
1251 case GL_FLOAT: vertexHLSL += " float "; break;
1252 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1253 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1254 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1255 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1256 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1257 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1258 default: UNREACHABLE();
1259 }
1260
1261 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1262
1263 semanticIndex += VariableRowCount(attribute->type);
1264 }
1265
1266 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001267 "\n"
1268 "struct VS_OUTPUT\n"
1269 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001270
1271 for (int r = 0; r < registers; r++)
1272 {
1273 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1274
1275 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1276 }
1277
1278 if (fragmentShader->mUsesFragCoord)
1279 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001280 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281 }
1282
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001283 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001284 {
1285 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1286 }
1287
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001288 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"
1289 "};\n"
1290 "\n"
1291 "VS_OUTPUT main(VS_INPUT input)\n"
1292 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001293
1294 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1295 {
1296 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1297
1298 if (VariableRowCount(attribute->type) > 1) // Matrix
1299 {
1300 vertexHLSL += "transpose";
1301 }
1302
1303 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1304 }
1305
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001306 if (shaderModel >= 4)
1307 {
1308 vertexHLSL += "\n"
1309 " gl_main();\n"
1310 "\n"
1311 " VS_OUTPUT output;\n"
1312 " output.gl_Position.x = gl_Position.x;\n"
1313 " output.gl_Position.y = -gl_Position.y;\n"
1314 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1315 " output.gl_Position.w = gl_Position.w;\n";
1316 }
1317 else
1318 {
1319 vertexHLSL += "\n"
1320 " gl_main();\n"
1321 "\n"
1322 " VS_OUTPUT output;\n"
1323 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
1324 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
1325 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1326 " output.gl_Position.w = gl_Position.w;\n";
1327 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001328
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001329 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001330 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001331 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001332 }
1333
1334 if (fragmentShader->mUsesFragCoord)
1335 {
1336 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1337 }
1338
1339 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1340 {
1341 if (varying->reg >= 0)
1342 {
1343 for (int i = 0; i < varying->size; i++)
1344 {
1345 int rows = VariableRowCount(varying->type);
1346
1347 for (int j = 0; j < rows; j++)
1348 {
1349 int r = varying->reg + i * rows + j;
1350 vertexHLSL += " output.v" + str(r);
1351
1352 bool sharedRegister = false; // Register used by multiple varyings
1353
1354 for (int x = 0; x < 4; x++)
1355 {
1356 if (packing[r][x] && packing[r][x] != packing[r][0])
1357 {
1358 sharedRegister = true;
1359 break;
1360 }
1361 }
1362
1363 if(sharedRegister)
1364 {
1365 vertexHLSL += ".";
1366
1367 for (int x = 0; x < 4; x++)
1368 {
1369 if (packing[r][x] == &*varying)
1370 {
1371 switch(x)
1372 {
1373 case 0: vertexHLSL += "x"; break;
1374 case 1: vertexHLSL += "y"; break;
1375 case 2: vertexHLSL += "z"; break;
1376 case 3: vertexHLSL += "w"; break;
1377 }
1378 }
1379 }
1380 }
1381
1382 vertexHLSL += " = " + varying->name;
1383
1384 if (varying->array)
1385 {
1386 vertexHLSL += "[" + str(i) + "]";
1387 }
1388
1389 if (rows > 1)
1390 {
1391 vertexHLSL += "[" + str(j) + "]";
1392 }
1393
1394 vertexHLSL += ";\n";
1395 }
1396 }
1397 }
1398 }
1399
1400 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001401 " return output;\n"
1402 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001403
1404 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001405 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001406
1407 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1408 {
1409 if (varying->reg >= 0)
1410 {
1411 for (int i = 0; i < varying->size; i++)
1412 {
1413 int rows = VariableRowCount(varying->type);
1414 for (int j = 0; j < rows; j++)
1415 {
1416 std::string n = str(varying->reg + i * rows + j);
daniel@transgaming.com00c0d152013-01-11 04:07:23 +00001417 pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001418 }
1419 }
1420 }
1421 else UNREACHABLE();
1422 }
1423
1424 if (fragmentShader->mUsesFragCoord)
1425 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001426 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001427
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001428 // Must consume the PSIZE element if the geometry shader is not active
1429 // We won't know if we use a GS until we draw
1430 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1431 {
1432 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1433 }
1434
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001435 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001436 {
1437 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1438 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001439 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001440 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001441 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1442 }
1443 }
1444
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001445 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001446 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001447 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001448 }
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;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001633 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001634 unsigned int arraySize;
1635
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001636 stream.read(&type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001637 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001638 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001639
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001640 mUniforms[i] = new Uniform(type, name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001642 stream.read(&mUniforms[i]->psRegisterIndex);
1643 stream.read(&mUniforms[i]->vsRegisterIndex);
1644 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001645 }
1646
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.read(&size);
1648 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649 {
1650 infoLog.append("Invalid program binary.");
1651 return false;
1652 }
1653
1654 mUniformIndex.resize(size);
1655 for (unsigned int i = 0; i < size; ++i)
1656 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001657 stream.read(&mUniformIndex[i].name);
1658 stream.read(&mUniformIndex[i].element);
1659 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 }
1661
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664
1665 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001666 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001668 unsigned int geometryShaderSize;
1669 stream.read(&geometryShaderSize);
1670
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672
daniel@transgaming.com36038542012-11-28 20:59:26 +00001673 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674 ptr += sizeof(GUID);
1675
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001676 GUID identifier = mRenderer->getAdapterIdentifier();
1677 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001678 {
1679 infoLog.append("Invalid program binary.");
1680 return false;
1681 }
1682
1683 const char *pixelShaderFunction = ptr;
1684 ptr += pixelShaderSize;
1685
1686 const char *vertexShaderFunction = ptr;
1687 ptr += vertexShaderSize;
1688
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001689 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1690 ptr += geometryShaderSize;
1691
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001692 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001693 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001694 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001695 {
1696 infoLog.append("Could not create pixel shader.");
1697 return false;
1698 }
1699
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001700 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001701 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001702 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001703 {
1704 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001705 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001706 mPixelExecutable = NULL;
1707 return false;
1708 }
1709
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001710 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1711 {
1712 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1713 geometryShaderSize, rx::SHADER_GEOMETRY);
1714 if (!mGeometryExecutable)
1715 {
1716 infoLog.append("Could not create geometry shader.");
1717 delete mPixelExecutable;
1718 mPixelExecutable = NULL;
1719 delete mVertexExecutable;
1720 mVertexExecutable = NULL;
1721 return false;
1722 }
1723 }
1724 else
1725 {
1726 mGeometryExecutable = NULL;
1727 }
1728
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 return true;
1730}
1731
1732bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1733{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001734 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001736 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001737 stream.write(VERSION_DWORD);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001738
1739 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1740 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001741 stream.write(mLinkedAttribute[i].type);
1742 stream.write(mLinkedAttribute[i].name);
1743 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001744 }
1745
1746 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1747 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001748 stream.write(mSamplersPS[i].active);
1749 stream.write(mSamplersPS[i].logicalTextureUnit);
1750 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001751 }
1752
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001753 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001755 stream.write(mSamplersVS[i].active);
1756 stream.write(mSamplersVS[i].logicalTextureUnit);
1757 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758 }
1759
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001760 stream.write(mUsedVertexSamplerRange);
1761 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001762 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001764 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1766 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.write(mUniforms[i]->type);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001768 stream.write(mUniforms[i]->name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001769 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001770
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001771 stream.write(mUniforms[i]->psRegisterIndex);
1772 stream.write(mUniforms[i]->vsRegisterIndex);
1773 stream.write(mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 }
1775
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001776 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1778 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001779 stream.write(mUniformIndex[i].name);
1780 stream.write(mUniformIndex[i].element);
1781 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001782 }
1783
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001784 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001787 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001788 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001789
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001790 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1791 stream.write(geometryShaderSize);
1792
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001793 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001795 GLsizei streamLength = stream.length();
1796 const void *streamData = stream.data();
1797
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001798 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001799 if (totalLength > bufSize)
1800 {
1801 if (length)
1802 {
1803 *length = 0;
1804 }
1805
1806 return false;
1807 }
1808
1809 if (binary)
1810 {
1811 char *ptr = (char*) binary;
1812
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001813 memcpy(ptr, streamData, streamLength);
1814 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001815
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001816 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817 ptr += sizeof(GUID);
1818
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001819 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820 ptr += pixelShaderSize;
1821
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001822 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823 ptr += vertexShaderSize;
1824
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001825 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1826 {
1827 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1828 ptr += geometryShaderSize;
1829 }
1830
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831 ASSERT(ptr - totalLength == binary);
1832 }
1833
1834 if (length)
1835 {
1836 *length = totalLength;
1837 }
1838
1839 return true;
1840}
1841
1842GLint ProgramBinary::getLength()
1843{
1844 GLint length;
1845 if (save(NULL, INT_MAX, &length))
1846 {
1847 return length;
1848 }
1849 else
1850 {
1851 return 0;
1852 }
1853}
1854
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001855bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001856{
1857 if (!fragmentShader || !fragmentShader->isCompiled())
1858 {
1859 return false;
1860 }
1861
1862 if (!vertexShader || !vertexShader->isCompiled())
1863 {
1864 return false;
1865 }
1866
1867 std::string pixelHLSL = fragmentShader->getHLSL();
1868 std::string vertexHLSL = vertexShader->getHLSL();
1869
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001870 // Map the varyings to the register file
1871 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1872 int registers = packVaryings(infoLog, packing, fragmentShader);
1873
1874 if (registers < 0)
1875 {
1876 return false;
1877 }
1878
1879 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001880 {
1881 return false;
1882 }
1883
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001884 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001885 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1886 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001887
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001888 if (usesGeometryShader())
1889 {
1890 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1891 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1892 }
1893
1894 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001895 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001896 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001897 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001898
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001899 delete mVertexExecutable;
1900 mVertexExecutable = NULL;
1901 delete mPixelExecutable;
1902 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001903 delete mGeometryExecutable;
1904 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001905 }
1906
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001907 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1908 {
1909 success = false;
1910 }
1911
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001912 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001913 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001914 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001915 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001916
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001917 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001918}
1919
1920// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001921bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001922{
1923 unsigned int usedLocations = 0;
1924
1925 // Link attributes that have a binding location
1926 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1927 {
1928 int location = attributeBindings.getAttributeBinding(attribute->name);
1929
1930 if (location != -1) // Set by glBindAttribLocation
1931 {
1932 if (!mLinkedAttribute[location].name.empty())
1933 {
1934 // Multiple active attributes bound to the same location; not an error
1935 }
1936
1937 mLinkedAttribute[location] = *attribute;
1938
1939 int rows = VariableRowCount(attribute->type);
1940
1941 if (rows + location > MAX_VERTEX_ATTRIBS)
1942 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001943 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 +00001944
1945 return false;
1946 }
1947
1948 for (int i = 0; i < rows; i++)
1949 {
1950 usedLocations |= 1 << (location + i);
1951 }
1952 }
1953 }
1954
1955 // Link attributes that don't have a binding location
1956 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1957 {
1958 int location = attributeBindings.getAttributeBinding(attribute->name);
1959
1960 if (location == -1) // Not set by glBindAttribLocation
1961 {
1962 int rows = VariableRowCount(attribute->type);
1963 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1964
1965 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1966 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001967 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001968
1969 return false; // Fail to link
1970 }
1971
1972 mLinkedAttribute[availableIndex] = *attribute;
1973 }
1974 }
1975
1976 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1977 {
1978 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1979 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1980
1981 for (int r = 0; r < rows; r++)
1982 {
1983 mSemanticIndex[attributeIndex++] = index++;
1984 }
1985 }
1986
1987 return true;
1988}
1989
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001990bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001991{
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001992 for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001993 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001994 if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001995 {
1996 return false;
1997 }
1998 }
1999
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002000 for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002001 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002002 if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002003 {
2004 return false;
2005 }
2006 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002007
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002008 return true;
2009}
2010
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002011bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002012{
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002013 if (constant.type == GL_SAMPLER_2D ||
2014 constant.type == GL_SAMPLER_CUBE)
2015 {
2016 unsigned int samplerIndex = constant.registerIndex;
2017
2018 do
2019 {
2020 if (shader == GL_VERTEX_SHADER)
2021 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002022 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002023 {
2024 mSamplersVS[samplerIndex].active = true;
2025 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2026 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2027 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2028 }
2029 else
2030 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002031 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002032 return false;
2033 }
2034 }
2035 else if (shader == GL_FRAGMENT_SHADER)
2036 {
2037 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2038 {
2039 mSamplersPS[samplerIndex].active = true;
2040 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2041 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2042 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2043 }
2044 else
2045 {
2046 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2047 return false;
2048 }
2049 }
2050 else UNREACHABLE();
2051
2052 samplerIndex++;
2053 }
2054 while (samplerIndex < constant.registerIndex + constant.arraySize);
2055 }
2056
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002057 Uniform *uniform = NULL;
2058 GLint location = getUniformLocation(constant.name);
2059
2060 if (location >= 0) // Previously defined, types must match
2061 {
2062 uniform = mUniforms[mUniformIndex[location].index];
2063
2064 if (uniform->type != constant.type)
2065 {
2066 return false;
2067 }
2068 }
2069 else
2070 {
2071 uniform = new Uniform(constant.type, constant.name, constant.arraySize);
2072 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002073
2074 if (!uniform)
2075 {
2076 return false;
2077 }
2078
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002079 if (shader == GL_FRAGMENT_SHADER)
2080 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002081 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002082 }
2083 else if (shader == GL_VERTEX_SHADER)
2084 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002085 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002086 }
2087 else UNREACHABLE();
2088
2089 if (location >= 0)
2090 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002091 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002092 }
2093
2094 mUniforms.push_back(uniform);
2095 unsigned int uniformIndex = mUniforms.size() - 1;
2096
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002097 for (unsigned int i = 0; i < uniform->elementCount(); i++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002098 {
2099 mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
2100 }
2101
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002102 if (shader == GL_VERTEX_SHADER)
2103 {
2104 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2105 {
2106 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2107 return false;
2108 }
2109 }
2110 else if (shader == GL_FRAGMENT_SHADER)
2111 {
2112 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2113 {
2114 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2115 return false;
2116 }
2117 }
2118 else UNREACHABLE();
2119
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002120 return true;
2121}
2122
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002123std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2124{
2125 // for now we only handle point sprite emulation
2126 ASSERT(usesPointSpriteEmulation());
2127 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2128}
2129
2130std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2131{
2132 ASSERT(registers >= 0);
2133 ASSERT(vertexShader->mUsesPointSize);
2134 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2135
2136 std::string geomHLSL;
2137
2138 std::string varyingSemantic = "TEXCOORD";
2139
2140 std::string fragCoordSemantic;
2141 std::string pointCoordSemantic;
2142
2143 int reservedRegisterIndex = registers;
2144
2145 if (fragmentShader->mUsesFragCoord)
2146 {
2147 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2148 }
2149
2150 if (fragmentShader->mUsesPointCoord)
2151 {
2152 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2153 }
2154
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002155 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2156 "\n"
2157 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002158 "{\n";
2159
2160 for (int r = 0; r < registers; r++)
2161 {
2162 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2163
2164 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2165 }
2166
2167 if (fragmentShader->mUsesFragCoord)
2168 {
2169 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2170 }
2171
2172 geomHLSL += " float gl_PointSize : PSIZE;\n"
2173 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002174 "};\n"
2175 "\n"
2176 "struct GS_OUTPUT\n"
2177 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002178
2179 for (int r = 0; r < registers; r++)
2180 {
2181 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
2182
2183 geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
2184 }
2185
2186 if (fragmentShader->mUsesFragCoord)
2187 {
2188 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2189 }
2190
2191 if (fragmentShader->mUsesPointCoord)
2192 {
2193 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2194 }
2195
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002196 geomHLSL += " float gl_PointSize : PSIZE;\n"
2197 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002198 "};\n"
2199 "\n"
2200 "static float2 pointSpriteCorners[] = \n"
2201 "{\n"
2202 " float2( 0.5f, -0.5f),\n"
2203 " float2( 0.5f, 0.5f),\n"
2204 " float2(-0.5f, -0.5f),\n"
2205 " float2(-0.5f, 0.5f)\n"
2206 "};\n"
2207 "\n"
2208 "static float2 pointSpriteTexcoords[] = \n"
2209 "{\n"
2210 " float2(1.0f, 1.0f),\n"
2211 " float2(1.0f, 0.0f),\n"
2212 " float2(0.0f, 1.0f),\n"
2213 " float2(0.0f, 0.0f)\n"
2214 "};\n"
2215 "\n"
2216 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2217 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2218 "\n"
2219 "[maxvertexcount(4)]\n"
2220 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2221 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002222 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2223 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002224
2225 for (int r = 0; r < registers; r++)
2226 {
2227 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2228 }
2229
2230 if (fragmentShader->mUsesFragCoord)
2231 {
2232 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2233 }
2234
2235 geomHLSL += " \n"
2236 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2237 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002238 " 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 +00002239
2240 for (int corner = 0; corner < 4; corner++)
2241 {
2242 geomHLSL += " \n"
2243 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2244
2245 if (fragmentShader->mUsesPointCoord)
2246 {
2247 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2248 }
2249
2250 geomHLSL += " outStream.Append(output);\n";
2251 }
2252
2253 geomHLSL += " \n"
2254 " outStream.RestartStrip();\n"
2255 "}\n";
2256
2257 return geomHLSL;
2258}
2259
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002260// This method needs to match OutputHLSL::decorate
2261std::string ProgramBinary::decorateAttribute(const std::string &name)
2262{
2263 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2264 {
2265 return "_" + name;
2266 }
2267
2268 return name;
2269}
2270
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002271bool ProgramBinary::isValidated() const
2272{
2273 return mValidated;
2274}
2275
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002276void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002277{
2278 // Skip over inactive attributes
2279 unsigned int activeAttribute = 0;
2280 unsigned int attribute;
2281 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2282 {
2283 if (mLinkedAttribute[attribute].name.empty())
2284 {
2285 continue;
2286 }
2287
2288 if (activeAttribute == index)
2289 {
2290 break;
2291 }
2292
2293 activeAttribute++;
2294 }
2295
2296 if (bufsize > 0)
2297 {
2298 const char *string = mLinkedAttribute[attribute].name.c_str();
2299
2300 strncpy(name, string, bufsize);
2301 name[bufsize - 1] = '\0';
2302
2303 if (length)
2304 {
2305 *length = strlen(name);
2306 }
2307 }
2308
2309 *size = 1; // Always a single 'type' instance
2310
2311 *type = mLinkedAttribute[attribute].type;
2312}
2313
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002314GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002315{
2316 int count = 0;
2317
2318 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2319 {
2320 if (!mLinkedAttribute[attributeIndex].name.empty())
2321 {
2322 count++;
2323 }
2324 }
2325
2326 return count;
2327}
2328
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002329GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002330{
2331 int maxLength = 0;
2332
2333 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2334 {
2335 if (!mLinkedAttribute[attributeIndex].name.empty())
2336 {
2337 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2338 }
2339 }
2340
2341 return maxLength;
2342}
2343
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002344void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002345{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002346 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002347
2348 if (bufsize > 0)
2349 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002350 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002351
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002352 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002353 {
2354 string += "[0]";
2355 }
2356
2357 strncpy(name, string.c_str(), bufsize);
2358 name[bufsize - 1] = '\0';
2359
2360 if (length)
2361 {
2362 *length = strlen(name);
2363 }
2364 }
2365
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002366 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002367
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002368 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002369}
2370
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002371GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002372{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002373 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002374}
2375
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002376GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002377{
2378 int maxLength = 0;
2379
2380 unsigned int numUniforms = mUniforms.size();
2381 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2382 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002383 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002384 {
2385 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2386 if (mUniforms[uniformIndex]->isArray())
2387 {
2388 length += 3; // Counting in "[0]".
2389 }
2390 maxLength = std::max(length, maxLength);
2391 }
2392 }
2393
2394 return maxLength;
2395}
2396
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002397void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002398{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002399 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002400 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002401 {
2402 mValidated = false;
2403 }
2404 else
2405 {
2406 mValidated = true;
2407 }
2408}
2409
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002410bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002411{
2412 // if any two active samplers in a program are of different types, but refer to the same
2413 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2414 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2415
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002416 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002417 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002418
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002419 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002420 {
2421 textureUnitType[i] = TEXTURE_UNKNOWN;
2422 }
2423
2424 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2425 {
2426 if (mSamplersPS[i].active)
2427 {
2428 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2429
2430 if (unit >= maxCombinedTextureImageUnits)
2431 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002432 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002433 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002434 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002435 }
2436
2437 return false;
2438 }
2439
2440 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2441 {
2442 if (mSamplersPS[i].textureType != textureUnitType[unit])
2443 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002444 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002445 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002446 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002447 }
2448
2449 return false;
2450 }
2451 }
2452 else
2453 {
2454 textureUnitType[unit] = mSamplersPS[i].textureType;
2455 }
2456 }
2457 }
2458
2459 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2460 {
2461 if (mSamplersVS[i].active)
2462 {
2463 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2464
2465 if (unit >= maxCombinedTextureImageUnits)
2466 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002467 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002468 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002469 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002470 }
2471
2472 return false;
2473 }
2474
2475 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2476 {
2477 if (mSamplersVS[i].textureType != textureUnitType[unit])
2478 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002479 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002480 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002481 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002482 }
2483
2484 return false;
2485 }
2486 }
2487 else
2488 {
2489 textureUnitType[unit] = mSamplersVS[i].textureType;
2490 }
2491 }
2492 }
2493
2494 return true;
2495}
2496
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002497ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2498{
2499}
2500
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002501struct AttributeSorter
2502{
2503 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2504 : originalIndices(semanticIndices)
2505 {
2506 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2507 {
2508 indices[i] = i;
2509 }
2510
2511 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2512 }
2513
2514 bool operator()(int a, int b)
2515 {
2516 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2517 }
2518
2519 int indices[MAX_VERTEX_ATTRIBS];
2520 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2521};
2522
2523void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2524{
2525 AttributeSorter sorter(mSemanticIndex);
2526
2527 int oldIndices[MAX_VERTEX_ATTRIBS];
2528 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2529
2530 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2531 {
2532 oldIndices[i] = mSemanticIndex[i];
2533 oldTranslatedAttributes[i] = attributes[i];
2534 }
2535
2536 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2537 {
2538 int oldIndex = sorter.indices[i];
2539 sortedSemanticIndices[i] = oldIndices[oldIndex];
2540 attributes[i] = oldTranslatedAttributes[oldIndex];
2541 }
2542}
2543
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002544}