blob: df2f0fe7a0710a1f0b658557f597fd9fa2478779 [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
2// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
3// 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/Program.h"
12#include "libGLESv2/ProgramBinary.h"
13
14#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000015#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/Shader.h"
19#include "libGLESv2/utilities.h"
20
21#include <string>
22
23#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
24#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
25#endif
26
27namespace gl
28{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029std::string str(int i)
30{
31 char buffer[20];
32 snprintf(buffer, sizeof(buffer), "%d", i);
33 return buffer;
34}
35
36Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
37 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
38{
39 int bytes = UniformInternalSize(type) * arraySize;
40 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
43}
44
45Uniform::~Uniform()
46{
47 delete[] data;
48}
49
50bool Uniform::isArray()
51{
52 return _name.compare(0, 3, "ar_") == 0;
53}
54
55UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
56 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
57{
58}
59
daniel@transgaming.come87ca002012-07-24 18:30:43 +000060unsigned int ProgramBinary::mCurrentSerial = 1;
61
daniel@transgaming.com989c1c82012-07-24 18:40:38 +000062ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000063{
64 mDevice = getDevice();
65
66 mPixelExecutable = NULL;
67 mVertexExecutable = NULL;
68 mConstantTablePS = NULL;
69 mConstantTableVS = NULL;
70
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071 mValidated = false;
72
73 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
74 {
75 mSemanticIndex[index] = -1;
76 }
77
78 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
79 {
80 mSamplersPS[index].active = false;
81 }
82
83 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
84 {
85 mSamplersVS[index].active = false;
86 }
87
88 mUsedVertexSamplerRange = 0;
89 mUsedPixelSamplerRange = 0;
90
91 mDxDepthRangeLocation = -1;
92 mDxDepthLocation = -1;
93 mDxCoordLocation = -1;
94 mDxHalfPixelSizeLocation = -1;
95 mDxFrontCCWLocation = -1;
96 mDxPointsOrLinesLocation = -1;
97}
98
99ProgramBinary::~ProgramBinary()
100{
101 if (mPixelExecutable)
102 {
103 mPixelExecutable->Release();
104 }
105
106 if (mVertexExecutable)
107 {
108 mVertexExecutable->Release();
109 }
110
111 if (mConstantTablePS)
112 {
113 mConstantTablePS->Release();
114 }
115
116 if (mConstantTableVS)
117 {
118 mConstantTableVS->Release();
119 }
120
121 while (!mUniforms.empty())
122 {
123 delete mUniforms.back();
124 mUniforms.pop_back();
125 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000126}
127
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000128unsigned int ProgramBinary::getSerial() const
129{
130 return mSerial;
131}
132
133unsigned int ProgramBinary::issueSerial()
134{
135 return mCurrentSerial++;
136}
137
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000138IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
139{
140 return mPixelExecutable;
141}
142
143IDirect3DVertexShader9 *ProgramBinary::getVertexShader()
144{
145 return mVertexExecutable;
146}
147
148GLuint ProgramBinary::getAttributeLocation(const char *name)
149{
150 if (name)
151 {
152 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
153 {
154 if (mLinkedAttribute[index].name == std::string(name))
155 {
156 return index;
157 }
158 }
159 }
160
161 return -1;
162}
163
164int ProgramBinary::getSemanticIndex(int attributeIndex)
165{
166 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
167
168 return mSemanticIndex[attributeIndex];
169}
170
171// Returns one more than the highest sampler index used.
172GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
173{
174 switch (type)
175 {
176 case SAMPLER_PIXEL:
177 return mUsedPixelSamplerRange;
178 case SAMPLER_VERTEX:
179 return mUsedVertexSamplerRange;
180 default:
181 UNREACHABLE();
182 return 0;
183 }
184}
185
186// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
187// index (0-15 for the pixel shader and 0-3 for the vertex shader).
188GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
189{
190 GLint logicalTextureUnit = -1;
191
192 switch (type)
193 {
194 case SAMPLER_PIXEL:
195 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
196
197 if (mSamplersPS[samplerIndex].active)
198 {
199 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
200 }
201 break;
202 case SAMPLER_VERTEX:
203 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
204
205 if (mSamplersVS[samplerIndex].active)
206 {
207 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
208 }
209 break;
210 default: UNREACHABLE();
211 }
212
213 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
214 {
215 return logicalTextureUnit;
216 }
217
218 return -1;
219}
220
221// Returns the texture type for a given Direct3D 9 sampler type and
222// index (0-15 for the pixel shader and 0-3 for the vertex shader).
223TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
224{
225 switch (type)
226 {
227 case SAMPLER_PIXEL:
228 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
229 ASSERT(mSamplersPS[samplerIndex].active);
230 return mSamplersPS[samplerIndex].textureType;
231 case SAMPLER_VERTEX:
232 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
233 ASSERT(mSamplersVS[samplerIndex].active);
234 return mSamplersVS[samplerIndex].textureType;
235 default: UNREACHABLE();
236 }
237
238 return TEXTURE_2D;
239}
240
241GLint ProgramBinary::getUniformLocation(std::string name)
242{
243 unsigned int subscript = 0;
244
245 // Strip any trailing array operator and retrieve the subscript
246 size_t open = name.find_last_of('[');
247 size_t close = name.find_last_of(']');
248 if (open != std::string::npos && close == name.length() - 1)
249 {
250 subscript = atoi(name.substr(open + 1).c_str());
251 name.erase(open);
252 }
253
254 unsigned int numUniforms = mUniformIndex.size();
255 for (unsigned int location = 0; location < numUniforms; location++)
256 {
257 if (mUniformIndex[location].name == name &&
258 mUniformIndex[location].element == subscript)
259 {
260 return location;
261 }
262 }
263
264 return -1;
265}
266
267bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
268{
269 if (location < 0 || location >= (int)mUniformIndex.size())
270 {
271 return false;
272 }
273
274 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
275 targetUniform->dirty = true;
276
277 if (targetUniform->type == GL_FLOAT)
278 {
279 int arraySize = targetUniform->arraySize;
280
281 if (arraySize == 1 && count > 1)
282 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
283
284 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
285
286 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
287
288 for (int i = 0; i < count; i++)
289 {
290 target[0] = v[0];
291 target[1] = 0;
292 target[2] = 0;
293 target[3] = 0;
294 target += 4;
295 v += 1;
296 }
297 }
298 else if (targetUniform->type == GL_BOOL)
299 {
300 int arraySize = targetUniform->arraySize;
301
302 if (arraySize == 1 && count > 1)
303 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
304
305 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
306 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
307
308 for (int i = 0; i < count; ++i)
309 {
310 if (v[i] == 0.0f)
311 {
312 boolParams[i] = GL_FALSE;
313 }
314 else
315 {
316 boolParams[i] = GL_TRUE;
317 }
318 }
319 }
320 else
321 {
322 return false;
323 }
324
325 return true;
326}
327
328bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
329{
330 if (location < 0 || location >= (int)mUniformIndex.size())
331 {
332 return false;
333 }
334
335 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
336 targetUniform->dirty = true;
337
338 if (targetUniform->type == GL_FLOAT_VEC2)
339 {
340 int arraySize = targetUniform->arraySize;
341
342 if (arraySize == 1 && count > 1)
343 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
344
345 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
346
347 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
348
349 for (int i = 0; i < count; i++)
350 {
351 target[0] = v[0];
352 target[1] = v[1];
353 target[2] = 0;
354 target[3] = 0;
355 target += 4;
356 v += 2;
357 }
358 }
359 else if (targetUniform->type == GL_BOOL_VEC2)
360 {
361 int arraySize = targetUniform->arraySize;
362
363 if (arraySize == 1 && count > 1)
364 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
365
366 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
367
368 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
369
370 for (int i = 0; i < count * 2; ++i)
371 {
372 if (v[i] == 0.0f)
373 {
374 boolParams[i] = GL_FALSE;
375 }
376 else
377 {
378 boolParams[i] = GL_TRUE;
379 }
380 }
381 }
382 else
383 {
384 return false;
385 }
386
387 return true;
388}
389
390bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
391{
392 if (location < 0 || location >= (int)mUniformIndex.size())
393 {
394 return false;
395 }
396
397 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
398 targetUniform->dirty = true;
399
400 if (targetUniform->type == GL_FLOAT_VEC3)
401 {
402 int arraySize = targetUniform->arraySize;
403
404 if (arraySize == 1 && count > 1)
405 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
406
407 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
408
409 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
410
411 for (int i = 0; i < count; i++)
412 {
413 target[0] = v[0];
414 target[1] = v[1];
415 target[2] = v[2];
416 target[3] = 0;
417 target += 4;
418 v += 3;
419 }
420 }
421 else if (targetUniform->type == GL_BOOL_VEC3)
422 {
423 int arraySize = targetUniform->arraySize;
424
425 if (arraySize == 1 && count > 1)
426 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
427
428 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
429 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
430
431 for (int i = 0; i < count * 3; ++i)
432 {
433 if (v[i] == 0.0f)
434 {
435 boolParams[i] = GL_FALSE;
436 }
437 else
438 {
439 boolParams[i] = GL_TRUE;
440 }
441 }
442 }
443 else
444 {
445 return false;
446 }
447
448 return true;
449}
450
451bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
452{
453 if (location < 0 || location >= (int)mUniformIndex.size())
454 {
455 return false;
456 }
457
458 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
459 targetUniform->dirty = true;
460
461 if (targetUniform->type == GL_FLOAT_VEC4)
462 {
463 int arraySize = targetUniform->arraySize;
464
465 if (arraySize == 1 && count > 1)
466 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
467
468 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
469
470 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
471 v, 4 * sizeof(GLfloat) * count);
472 }
473 else if (targetUniform->type == GL_BOOL_VEC4)
474 {
475 int arraySize = targetUniform->arraySize;
476
477 if (arraySize == 1 && count > 1)
478 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
479
480 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
481 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
482
483 for (int i = 0; i < count * 4; ++i)
484 {
485 if (v[i] == 0.0f)
486 {
487 boolParams[i] = GL_FALSE;
488 }
489 else
490 {
491 boolParams[i] = GL_TRUE;
492 }
493 }
494 }
495 else
496 {
497 return false;
498 }
499
500 return true;
501}
502
503template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
504void transposeMatrix(T *target, const GLfloat *value)
505{
506 int copyWidth = std::min(targetWidth, srcWidth);
507 int copyHeight = std::min(targetHeight, srcHeight);
508
509 for (int x = 0; x < copyWidth; x++)
510 {
511 for (int y = 0; y < copyHeight; y++)
512 {
513 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
514 }
515 }
516 // clear unfilled right side
517 for (int y = 0; y < copyHeight; y++)
518 {
519 for (int x = srcWidth; x < targetWidth; x++)
520 {
521 target[y * targetWidth + x] = (T)0;
522 }
523 }
524 // clear unfilled bottom.
525 for (int y = srcHeight; y < targetHeight; y++)
526 {
527 for (int x = 0; x < targetWidth; x++)
528 {
529 target[y * targetWidth + x] = (T)0;
530 }
531 }
532}
533
534bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
535{
536 if (location < 0 || location >= (int)mUniformIndex.size())
537 {
538 return false;
539 }
540
541 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
542 targetUniform->dirty = true;
543
544 if (targetUniform->type != GL_FLOAT_MAT2)
545 {
546 return false;
547 }
548
549 int arraySize = targetUniform->arraySize;
550
551 if (arraySize == 1 && count > 1)
552 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
553
554 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
555
556 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
557 for (int i = 0; i < count; i++)
558 {
559 transposeMatrix<GLfloat,4,2,2,2>(target, value);
560 target += 8;
561 value += 4;
562 }
563
564 return true;
565}
566
567bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
568{
569 if (location < 0 || location >= (int)mUniformIndex.size())
570 {
571 return false;
572 }
573
574 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
575 targetUniform->dirty = true;
576
577 if (targetUniform->type != GL_FLOAT_MAT3)
578 {
579 return false;
580 }
581
582 int arraySize = targetUniform->arraySize;
583
584 if (arraySize == 1 && count > 1)
585 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
586
587 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
588
589 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
590 for (int i = 0; i < count; i++)
591 {
592 transposeMatrix<GLfloat,4,3,3,3>(target, value);
593 target += 12;
594 value += 9;
595 }
596
597 return true;
598}
599
600
601bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
602{
603 if (location < 0 || location >= (int)mUniformIndex.size())
604 {
605 return false;
606 }
607
608 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
609 targetUniform->dirty = true;
610
611 if (targetUniform->type != GL_FLOAT_MAT4)
612 {
613 return false;
614 }
615
616 int arraySize = targetUniform->arraySize;
617
618 if (arraySize == 1 && count > 1)
619 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
620
621 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
622
623 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
624 for (int i = 0; i < count; i++)
625 {
626 transposeMatrix<GLfloat,4,4,4,4>(target, value);
627 target += 16;
628 value += 16;
629 }
630
631 return true;
632}
633
634bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
635{
636 if (location < 0 || location >= (int)mUniformIndex.size())
637 {
638 return false;
639 }
640
641 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
642 targetUniform->dirty = true;
643
644 if (targetUniform->type == GL_INT ||
645 targetUniform->type == GL_SAMPLER_2D ||
646 targetUniform->type == GL_SAMPLER_CUBE)
647 {
648 int arraySize = targetUniform->arraySize;
649
650 if (arraySize == 1 && count > 1)
651 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
652
653 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
654
655 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
656 v, sizeof(GLint) * count);
657 }
658 else if (targetUniform->type == GL_BOOL)
659 {
660 int arraySize = targetUniform->arraySize;
661
662 if (arraySize == 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(arraySize - (int)mUniformIndex[location].element, count);
666 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
667
668 for (int i = 0; i < count; ++i)
669 {
670 if (v[i] == 0)
671 {
672 boolParams[i] = GL_FALSE;
673 }
674 else
675 {
676 boolParams[i] = GL_TRUE;
677 }
678 }
679 }
680 else
681 {
682 return false;
683 }
684
685 return true;
686}
687
688bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
689{
690 if (location < 0 || location >= (int)mUniformIndex.size())
691 {
692 return false;
693 }
694
695 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
696 targetUniform->dirty = true;
697
698 if (targetUniform->type == GL_INT_VEC2)
699 {
700 int arraySize = targetUniform->arraySize;
701
702 if (arraySize == 1 && count > 1)
703 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
704
705 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
706
707 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
708 v, 2 * sizeof(GLint) * count);
709 }
710 else if (targetUniform->type == GL_BOOL_VEC2)
711 {
712 int arraySize = targetUniform->arraySize;
713
714 if (arraySize == 1 && count > 1)
715 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
716
717 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
718 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
719
720 for (int i = 0; i < count * 2; ++i)
721 {
722 if (v[i] == 0)
723 {
724 boolParams[i] = GL_FALSE;
725 }
726 else
727 {
728 boolParams[i] = GL_TRUE;
729 }
730 }
731 }
732 else
733 {
734 return false;
735 }
736
737 return true;
738}
739
740bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
741{
742 if (location < 0 || location >= (int)mUniformIndex.size())
743 {
744 return false;
745 }
746
747 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
748 targetUniform->dirty = true;
749
750 if (targetUniform->type == GL_INT_VEC3)
751 {
752 int arraySize = targetUniform->arraySize;
753
754 if (arraySize == 1 && count > 1)
755 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
756
757 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
758
759 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
760 v, 3 * sizeof(GLint) * count);
761 }
762 else if (targetUniform->type == GL_BOOL_VEC3)
763 {
764 int arraySize = targetUniform->arraySize;
765
766 if (arraySize == 1 && count > 1)
767 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
768
769 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
770 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
771
772 for (int i = 0; i < count * 3; ++i)
773 {
774 if (v[i] == 0)
775 {
776 boolParams[i] = GL_FALSE;
777 }
778 else
779 {
780 boolParams[i] = GL_TRUE;
781 }
782 }
783 }
784 else
785 {
786 return false;
787 }
788
789 return true;
790}
791
792bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
793{
794 if (location < 0 || location >= (int)mUniformIndex.size())
795 {
796 return false;
797 }
798
799 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
800 targetUniform->dirty = true;
801
802 if (targetUniform->type == GL_INT_VEC4)
803 {
804 int arraySize = targetUniform->arraySize;
805
806 if (arraySize == 1 && count > 1)
807 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
808
809 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
810
811 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
812 v, 4 * sizeof(GLint) * count);
813 }
814 else if (targetUniform->type == GL_BOOL_VEC4)
815 {
816 int arraySize = targetUniform->arraySize;
817
818 if (arraySize == 1 && count > 1)
819 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
820
821 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
822 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
823
824 for (int i = 0; i < count * 4; ++i)
825 {
826 if (v[i] == 0)
827 {
828 boolParams[i] = GL_FALSE;
829 }
830 else
831 {
832 boolParams[i] = GL_TRUE;
833 }
834 }
835 }
836 else
837 {
838 return false;
839 }
840
841 return true;
842}
843
844bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
845{
846 if (location < 0 || location >= (int)mUniformIndex.size())
847 {
848 return false;
849 }
850
851 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
852
853 // sized queries -- ensure the provided buffer is large enough
854 if (bufSize)
855 {
856 int requiredBytes = UniformExternalSize(targetUniform->type);
857 if (*bufSize < requiredBytes)
858 {
859 return false;
860 }
861 }
862
863 switch (targetUniform->type)
864 {
865 case GL_FLOAT_MAT2:
866 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
867 break;
868 case GL_FLOAT_MAT3:
869 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
870 break;
871 case GL_FLOAT_MAT4:
872 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
873 break;
874 default:
875 {
876 unsigned int count = UniformExternalComponentCount(targetUniform->type);
877 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
878
879 switch (UniformComponentType(targetUniform->type))
880 {
881 case GL_BOOL:
882 {
883 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
884
885 for (unsigned int i = 0; i < count; ++i)
886 {
887 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
888 }
889 }
890 break;
891 case GL_FLOAT:
892 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
893 count * sizeof(GLfloat));
894 break;
895 case GL_INT:
896 {
897 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
898
899 for (unsigned int i = 0; i < count; ++i)
900 {
901 params[i] = (float)intParams[i];
902 }
903 }
904 break;
905 default: UNREACHABLE();
906 }
907 }
908 }
909
910 return true;
911}
912
913bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
914{
915 if (location < 0 || location >= (int)mUniformIndex.size())
916 {
917 return false;
918 }
919
920 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
921
922 // sized queries -- ensure the provided buffer is large enough
923 if (bufSize)
924 {
925 int requiredBytes = UniformExternalSize(targetUniform->type);
926 if (*bufSize < requiredBytes)
927 {
928 return false;
929 }
930 }
931
932 switch (targetUniform->type)
933 {
934 case GL_FLOAT_MAT2:
935 {
936 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
937 }
938 break;
939 case GL_FLOAT_MAT3:
940 {
941 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
942 }
943 break;
944 case GL_FLOAT_MAT4:
945 {
946 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
947 }
948 break;
949 default:
950 {
951 unsigned int count = UniformExternalComponentCount(targetUniform->type);
952 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
953
954 switch (UniformComponentType(targetUniform->type))
955 {
956 case GL_BOOL:
957 {
958 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
959
960 for (unsigned int i = 0; i < count; ++i)
961 {
962 params[i] = (GLint)boolParams[i];
963 }
964 }
965 break;
966 case GL_FLOAT:
967 {
968 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
969
970 for (unsigned int i = 0; i < count; ++i)
971 {
972 params[i] = (GLint)floatParams[i];
973 }
974 }
975 break;
976 case GL_INT:
977 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
978 count * sizeof(GLint));
979 break;
980 default: UNREACHABLE();
981 }
982 }
983 }
984
985 return true;
986}
987
988void ProgramBinary::dirtyAllUniforms()
989{
990 unsigned int numUniforms = mUniforms.size();
991 for (unsigned int index = 0; index < numUniforms; index++)
992 {
993 mUniforms[index]->dirty = true;
994 }
995}
996
997// Applies all the uniforms set for this program object to the Direct3D 9 device
998void ProgramBinary::applyUniforms()
999{
1000 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1001 Uniform *targetUniform = *ub;
1002
1003 if (targetUniform->dirty)
1004 {
1005 int arraySize = targetUniform->arraySize;
1006 GLfloat *f = (GLfloat*)targetUniform->data;
1007 GLint *i = (GLint*)targetUniform->data;
1008 GLboolean *b = (GLboolean*)targetUniform->data;
1009
1010 switch (targetUniform->type)
1011 {
1012 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1013 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1014 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1015 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1016 case GL_FLOAT:
1017 case GL_FLOAT_VEC2:
1018 case GL_FLOAT_VEC3:
1019 case GL_FLOAT_VEC4:
1020 case GL_FLOAT_MAT2:
1021 case GL_FLOAT_MAT3:
1022 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1023 case GL_SAMPLER_2D:
1024 case GL_SAMPLER_CUBE:
1025 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1026 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1027 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1028 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1029 default:
1030 UNREACHABLE();
1031 }
1032
1033 targetUniform->dirty = false;
1034 }
1035 }
1036}
1037
1038// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001039ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001040{
1041 if (!hlsl)
1042 {
1043 return NULL;
1044 }
1045
1046 DWORD result;
1047 UINT flags = 0;
1048 std::string sourceText;
1049 if (perfActive())
1050 {
1051 flags |= D3DCOMPILE_DEBUG;
1052#ifdef NDEBUG
1053 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1054#else
1055 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
1056#endif
1057
1058 std::string sourcePath = getTempPath();
1059 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
1060 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
1061 }
1062 else
1063 {
1064 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1065 sourceText = hlsl;
1066 }
1067
1068 ID3D10Blob *binary = NULL;
1069 ID3D10Blob *errorMessage = NULL;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001070 result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001071
1072 if (errorMessage)
1073 {
1074 const char *message = (const char*)errorMessage->GetBufferPointer();
1075
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001076 infoLog.appendSanitized(message);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001077 TRACE("\n%s", hlsl);
1078 TRACE("\n%s", message);
1079
1080 errorMessage->Release();
1081 errorMessage = NULL;
1082 }
1083
1084 if (FAILED(result))
1085 {
1086 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1087 {
1088 error(GL_OUT_OF_MEMORY);
1089 }
1090
1091 return NULL;
1092 }
1093
1094 result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
1095
1096 if (FAILED(result))
1097 {
1098 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1099 {
1100 error(GL_OUT_OF_MEMORY);
1101 }
1102
1103 binary->Release();
1104
1105 return NULL;
1106 }
1107
1108 return binary;
1109}
1110
1111// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1112// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001113int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001114{
1115 Context *context = getContext();
1116 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1117
1118 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1119 {
1120 int n = VariableRowCount(varying->type) * varying->size;
1121 int m = VariableColumnCount(varying->type);
1122 bool success = false;
1123
1124 if (m == 2 || m == 3 || m == 4)
1125 {
1126 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1127 {
1128 bool available = true;
1129
1130 for (int y = 0; y < n && available; y++)
1131 {
1132 for (int x = 0; x < m && available; x++)
1133 {
1134 if (packing[r + y][x])
1135 {
1136 available = false;
1137 }
1138 }
1139 }
1140
1141 if (available)
1142 {
1143 varying->reg = r;
1144 varying->col = 0;
1145
1146 for (int y = 0; y < n; y++)
1147 {
1148 for (int x = 0; x < m; x++)
1149 {
1150 packing[r + y][x] = &*varying;
1151 }
1152 }
1153
1154 success = true;
1155 }
1156 }
1157
1158 if (!success && m == 2)
1159 {
1160 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1161 {
1162 bool available = true;
1163
1164 for (int y = 0; y < n && available; y++)
1165 {
1166 for (int x = 2; x < 4 && available; x++)
1167 {
1168 if (packing[r + y][x])
1169 {
1170 available = false;
1171 }
1172 }
1173 }
1174
1175 if (available)
1176 {
1177 varying->reg = r;
1178 varying->col = 2;
1179
1180 for (int y = 0; y < n; y++)
1181 {
1182 for (int x = 2; x < 4; x++)
1183 {
1184 packing[r + y][x] = &*varying;
1185 }
1186 }
1187
1188 success = true;
1189 }
1190 }
1191 }
1192 }
1193 else if (m == 1)
1194 {
1195 int space[4] = {0};
1196
1197 for (int y = 0; y < maxVaryingVectors; y++)
1198 {
1199 for (int x = 0; x < 4; x++)
1200 {
1201 space[x] += packing[y][x] ? 0 : 1;
1202 }
1203 }
1204
1205 int column = 0;
1206
1207 for (int x = 0; x < 4; x++)
1208 {
1209 if (space[x] >= n && space[x] < space[column])
1210 {
1211 column = x;
1212 }
1213 }
1214
1215 if (space[column] >= n)
1216 {
1217 for (int r = 0; r < maxVaryingVectors; r++)
1218 {
1219 if (!packing[r][column])
1220 {
1221 varying->reg = r;
1222
1223 for (int y = r; y < r + n; y++)
1224 {
1225 packing[y][column] = &*varying;
1226 }
1227
1228 break;
1229 }
1230 }
1231
1232 varying->col = column;
1233
1234 success = true;
1235 }
1236 }
1237 else UNREACHABLE();
1238
1239 if (!success)
1240 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001241 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001242
1243 return -1;
1244 }
1245 }
1246
1247 // Return the number of used registers
1248 int registers = 0;
1249
1250 for (int r = 0; r < maxVaryingVectors; r++)
1251 {
1252 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1253 {
1254 registers++;
1255 }
1256 }
1257
1258 return registers;
1259}
1260
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001261bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262{
1263 if (pixelHLSL.empty() || vertexHLSL.empty())
1264 {
1265 return false;
1266 }
1267
1268 // Reset the varying register assignments
1269 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1270 {
1271 fragVar->reg = -1;
1272 fragVar->col = -1;
1273 }
1274
1275 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1276 {
1277 vtxVar->reg = -1;
1278 vtxVar->col = -1;
1279 }
1280
1281 // Map the varyings to the register file
1282 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001283 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001284
1285 if (registers < 0)
1286 {
1287 return false;
1288 }
1289
1290 // Write the HLSL input/output declarations
1291 Context *context = getContext();
1292 const bool sm3 = context->supportsShaderModel3();
1293 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1294
1295 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1296 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001297 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298
1299 return false;
1300 }
1301
1302 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1303 {
1304 bool matched = false;
1305
1306 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1307 {
1308 if (output->name == input->name)
1309 {
1310 if (output->type != input->type || output->size != input->size)
1311 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001312 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 +00001313
1314 return false;
1315 }
1316
1317 output->reg = input->reg;
1318 output->col = input->col;
1319
1320 matched = true;
1321 break;
1322 }
1323 }
1324
1325 if (!matched)
1326 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001327 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001328
1329 return false;
1330 }
1331 }
1332
daniel@transgaming.com08b3e402012-07-04 19:16:35 +00001333 std::string varyingSemantic = (vertexShader->mUsesPointSize && sm3 ? "COLOR" : "TEXCOORD");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001334
1335 vertexHLSL += "struct VS_INPUT\n"
1336 "{\n";
1337
1338 int semanticIndex = 0;
1339 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1340 {
1341 switch (attribute->type)
1342 {
1343 case GL_FLOAT: vertexHLSL += " float "; break;
1344 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1345 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1346 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1347 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1348 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1349 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1350 default: UNREACHABLE();
1351 }
1352
1353 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1354
1355 semanticIndex += VariableRowCount(attribute->type);
1356 }
1357
1358 vertexHLSL += "};\n"
1359 "\n"
1360 "struct VS_OUTPUT\n"
1361 "{\n"
1362 " float4 gl_Position : POSITION;\n";
1363
1364 for (int r = 0; r < registers; r++)
1365 {
1366 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1367
1368 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1369 }
1370
1371 if (fragmentShader->mUsesFragCoord)
1372 {
1373 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1374 }
1375
1376 if (vertexShader->mUsesPointSize && sm3)
1377 {
1378 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1379 }
1380
1381 vertexHLSL += "};\n"
1382 "\n"
1383 "VS_OUTPUT main(VS_INPUT input)\n"
1384 "{\n";
1385
1386 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1387 {
1388 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1389
1390 if (VariableRowCount(attribute->type) > 1) // Matrix
1391 {
1392 vertexHLSL += "transpose";
1393 }
1394
1395 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1396 }
1397
1398 vertexHLSL += "\n"
1399 " gl_main();\n"
1400 "\n"
1401 " VS_OUTPUT output;\n"
1402 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001403 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001404 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1405 " output.gl_Position.w = gl_Position.w;\n";
1406
1407 if (vertexShader->mUsesPointSize && sm3)
1408 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001409 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001410 }
1411
1412 if (fragmentShader->mUsesFragCoord)
1413 {
1414 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1415 }
1416
1417 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1418 {
1419 if (varying->reg >= 0)
1420 {
1421 for (int i = 0; i < varying->size; i++)
1422 {
1423 int rows = VariableRowCount(varying->type);
1424
1425 for (int j = 0; j < rows; j++)
1426 {
1427 int r = varying->reg + i * rows + j;
1428 vertexHLSL += " output.v" + str(r);
1429
1430 bool sharedRegister = false; // Register used by multiple varyings
1431
1432 for (int x = 0; x < 4; x++)
1433 {
1434 if (packing[r][x] && packing[r][x] != packing[r][0])
1435 {
1436 sharedRegister = true;
1437 break;
1438 }
1439 }
1440
1441 if(sharedRegister)
1442 {
1443 vertexHLSL += ".";
1444
1445 for (int x = 0; x < 4; x++)
1446 {
1447 if (packing[r][x] == &*varying)
1448 {
1449 switch(x)
1450 {
1451 case 0: vertexHLSL += "x"; break;
1452 case 1: vertexHLSL += "y"; break;
1453 case 2: vertexHLSL += "z"; break;
1454 case 3: vertexHLSL += "w"; break;
1455 }
1456 }
1457 }
1458 }
1459
1460 vertexHLSL += " = " + varying->name;
1461
1462 if (varying->array)
1463 {
1464 vertexHLSL += "[" + str(i) + "]";
1465 }
1466
1467 if (rows > 1)
1468 {
1469 vertexHLSL += "[" + str(j) + "]";
1470 }
1471
1472 vertexHLSL += ";\n";
1473 }
1474 }
1475 }
1476 }
1477
1478 vertexHLSL += "\n"
1479 " return output;\n"
1480 "}\n";
1481
1482 pixelHLSL += "struct PS_INPUT\n"
1483 "{\n";
1484
1485 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1486 {
1487 if (varying->reg >= 0)
1488 {
1489 for (int i = 0; i < varying->size; i++)
1490 {
1491 int rows = VariableRowCount(varying->type);
1492 for (int j = 0; j < rows; j++)
1493 {
1494 std::string n = str(varying->reg + i * rows + j);
1495 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1496 }
1497 }
1498 }
1499 else UNREACHABLE();
1500 }
1501
1502 if (fragmentShader->mUsesFragCoord)
1503 {
1504 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1505 if (sm3) {
1506 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1507 }
1508 }
1509
1510 if (fragmentShader->mUsesPointCoord && sm3)
1511 {
1512 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1513 }
1514
1515 if (fragmentShader->mUsesFrontFacing)
1516 {
1517 pixelHLSL += " float vFace : VFACE;\n";
1518 }
1519
1520 pixelHLSL += "};\n"
1521 "\n"
1522 "struct PS_OUTPUT\n"
1523 "{\n"
1524 " float4 gl_Color[1] : COLOR;\n"
1525 "};\n"
1526 "\n"
1527 "PS_OUTPUT main(PS_INPUT input)\n"
1528 "{\n";
1529
1530 if (fragmentShader->mUsesFragCoord)
1531 {
1532 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1533
1534 if (sm3)
1535 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001536 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001537 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001538 }
1539 else
1540 {
1541 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1542 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001543 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001544 }
1545
1546 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1547 " gl_FragCoord.w = rhw;\n";
1548 }
1549
1550 if (fragmentShader->mUsesPointCoord && sm3)
1551 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001552 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1553 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001554 }
1555
1556 if (fragmentShader->mUsesFrontFacing)
1557 {
1558 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1559 }
1560
1561 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1562 {
1563 if (varying->reg >= 0)
1564 {
1565 for (int i = 0; i < varying->size; i++)
1566 {
1567 int rows = VariableRowCount(varying->type);
1568 for (int j = 0; j < rows; j++)
1569 {
1570 std::string n = str(varying->reg + i * rows + j);
1571 pixelHLSL += " " + varying->name;
1572
1573 if (varying->array)
1574 {
1575 pixelHLSL += "[" + str(i) + "]";
1576 }
1577
1578 if (rows > 1)
1579 {
1580 pixelHLSL += "[" + str(j) + "]";
1581 }
1582
1583 pixelHLSL += " = input.v" + n + ";\n";
1584 }
1585 }
1586 }
1587 else UNREACHABLE();
1588 }
1589
1590 pixelHLSL += "\n"
1591 " gl_main();\n"
1592 "\n"
1593 " PS_OUTPUT output;\n"
1594 " output.gl_Color[0] = gl_Color[0];\n"
1595 "\n"
1596 " return output;\n"
1597 "}\n";
1598
1599 return true;
1600}
1601
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001602bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1603{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001604 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605
1606 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001607 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001608 if (format != GL_PROGRAM_BINARY_ANGLE)
1609 {
1610 infoLog.append("Invalid program binary format.");
1611 return false;
1612 }
1613
1614 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001615 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001616 if (version != BUILD_REVISION)
1617 {
1618 infoLog.append("Invalid program binary version.");
1619 return false;
1620 }
1621
1622 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1623 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001625 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001626 stream.read(&name);
1627 mLinkedAttribute[i].name = name;
1628 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001629 }
1630
1631 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1632 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001633 stream.read(&mSamplersPS[i].active);
1634 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001635
1636 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001637 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 mSamplersPS[i].textureType = (TextureType) textureType;
1639 }
1640
1641 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1642 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001643 stream.read(&mSamplersVS[i].active);
1644 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001645
1646 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001648 mSamplersVS[i].textureType = (TextureType) textureType;
1649 }
1650
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001651 stream.read(&mUsedVertexSamplerRange);
1652 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001653
1654 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 stream.read(&size);
1656 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001657 {
1658 infoLog.append("Invalid program binary.");
1659 return false;
1660 }
1661
1662 mUniforms.resize(size);
1663 for (unsigned int i = 0; i < size; ++i)
1664 {
1665 GLenum type;
1666 std::string _name;
1667 unsigned int arraySize;
1668
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001669 stream.read(&type);
1670 stream.read(&_name);
1671 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001675 stream.read(&mUniforms[i]->ps.float4Index);
1676 stream.read(&mUniforms[i]->ps.samplerIndex);
1677 stream.read(&mUniforms[i]->ps.boolIndex);
1678 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001680 stream.read(&mUniforms[i]->vs.float4Index);
1681 stream.read(&mUniforms[i]->vs.samplerIndex);
1682 stream.read(&mUniforms[i]->vs.boolIndex);
1683 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684 }
1685
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001686 stream.read(&size);
1687 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 {
1689 infoLog.append("Invalid program binary.");
1690 return false;
1691 }
1692
1693 mUniformIndex.resize(size);
1694 for (unsigned int i = 0; i < size; ++i)
1695 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001696 stream.read(&mUniformIndex[i].name);
1697 stream.read(&mUniformIndex[i].element);
1698 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001699 }
1700
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001701 stream.read(&mDxDepthRangeLocation);
1702 stream.read(&mDxDepthLocation);
1703 stream.read(&mDxCoordLocation);
1704 stream.read(&mDxHalfPixelSizeLocation);
1705 stream.read(&mDxFrontCCWLocation);
1706 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001707
1708 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001709 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710
1711 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001712 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001713
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001714 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001715
1716 const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
1717 ptr += sizeof(GUID);
1718
1719 D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier();
1720 if (memcmp(&currentIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0)
1721 {
1722 infoLog.append("Invalid program binary.");
1723 return false;
1724 }
1725
1726 const char *pixelShaderFunction = ptr;
1727 ptr += pixelShaderSize;
1728
1729 const char *vertexShaderFunction = ptr;
1730 ptr += vertexShaderSize;
1731
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001732 mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
1733 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001734 {
1735 infoLog.append("Could not create pixel shader.");
1736 return false;
1737 }
1738
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001739 mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
1740 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741 {
1742 infoLog.append("Could not create vertex shader.");
1743 mPixelExecutable->Release();
1744 mPixelExecutable = NULL;
1745 return false;
1746 }
1747
1748 return true;
1749}
1750
1751bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1752{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001753 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001755 stream.write(GL_PROGRAM_BINARY_ANGLE);
1756 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001757
1758 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1759 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001760 stream.write(mLinkedAttribute[i].type);
1761 stream.write(mLinkedAttribute[i].name);
1762 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763 }
1764
1765 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1766 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001767 stream.write(mSamplersPS[i].active);
1768 stream.write(mSamplersPS[i].logicalTextureUnit);
1769 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001770 }
1771
1772 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1773 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001774 stream.write(mSamplersVS[i].active);
1775 stream.write(mSamplersVS[i].logicalTextureUnit);
1776 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001777 }
1778
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001779 stream.write(mUsedVertexSamplerRange);
1780 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001781
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1784 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.write(mUniforms[i]->type);
1786 stream.write(mUniforms[i]->_name);
1787 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001789 stream.write(mUniforms[i]->ps.float4Index);
1790 stream.write(mUniforms[i]->ps.samplerIndex);
1791 stream.write(mUniforms[i]->ps.boolIndex);
1792 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001793
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001794 stream.write(mUniforms[i]->vs.float4Index);
1795 stream.write(mUniforms[i]->vs.samplerIndex);
1796 stream.write(mUniforms[i]->vs.boolIndex);
1797 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001798 }
1799
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001800 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1802 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001803 stream.write(mUniformIndex[i].name);
1804 stream.write(mUniformIndex[i].element);
1805 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001806 }
1807
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001808 stream.write(mDxDepthRangeLocation);
1809 stream.write(mDxDepthLocation);
1810 stream.write(mDxCoordLocation);
1811 stream.write(mDxHalfPixelSizeLocation);
1812 stream.write(mDxFrontCCWLocation);
1813 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814
1815 UINT pixelShaderSize;
1816 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1817 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001818 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819
1820 UINT vertexShaderSize;
1821 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1822 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001823 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824
1825 D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier();
1826
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001827 GLsizei streamLength = stream.length();
1828 const void *streamData = stream.data();
1829
1830 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831 if (totalLength > bufSize)
1832 {
1833 if (length)
1834 {
1835 *length = 0;
1836 }
1837
1838 return false;
1839 }
1840
1841 if (binary)
1842 {
1843 char *ptr = (char*) binary;
1844
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001845 memcpy(ptr, streamData, streamLength);
1846 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001847
1848 memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID));
1849 ptr += sizeof(GUID);
1850
1851 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1852 ASSERT(SUCCEEDED(result));
1853 ptr += pixelShaderSize;
1854
1855 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1856 ASSERT(SUCCEEDED(result));
1857 ptr += vertexShaderSize;
1858
1859 ASSERT(ptr - totalLength == binary);
1860 }
1861
1862 if (length)
1863 {
1864 *length = totalLength;
1865 }
1866
1867 return true;
1868}
1869
1870GLint ProgramBinary::getLength()
1871{
1872 GLint length;
1873 if (save(NULL, INT_MAX, &length))
1874 {
1875 return length;
1876 }
1877 else
1878 {
1879 return 0;
1880 }
1881}
1882
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001883bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001884{
1885 if (!fragmentShader || !fragmentShader->isCompiled())
1886 {
1887 return false;
1888 }
1889
1890 if (!vertexShader || !vertexShader->isCompiled())
1891 {
1892 return false;
1893 }
1894
1895 std::string pixelHLSL = fragmentShader->getHLSL();
1896 std::string vertexHLSL = vertexShader->getHLSL();
1897
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001898 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001899 {
1900 return false;
1901 }
1902
1903 Context *context = getContext();
1904 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1905 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1906
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001907 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1908 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001909
1910 if (vertexBinary && pixelBinary)
1911 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001912 mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
1913 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001914 {
1915 return error(GL_OUT_OF_MEMORY, false);
1916 }
1917
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001918 mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
1919 if (!mPixelExecutable)
1920 {
1921 mVertexExecutable->Release();
1922 mVertexExecutable = NULL;
1923 return error(GL_OUT_OF_MEMORY, false);
1924 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001925
1926 vertexBinary->Release();
1927 pixelBinary->Release();
1928 vertexBinary = NULL;
1929 pixelBinary = NULL;
1930
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001931 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001932 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001933 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001934 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001935
1936 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1937 {
1938 return false;
1939 }
1940
1941 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1942 {
1943 return false;
1944 }
1945
1946 // these uniforms are searched as already-decorated because gl_ and dx_
1947 // are reserved prefixes, and do not receive additional decoration
1948 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1949 mDxDepthLocation = getUniformLocation("dx_Depth");
1950 mDxCoordLocation = getUniformLocation("dx_Coord");
1951 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1952 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1953 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1954
1955 context->markDxUniformsDirty();
1956
1957 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001958 }
1959
1960 return false;
1961}
1962
1963// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001964bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001965{
1966 unsigned int usedLocations = 0;
1967
1968 // Link attributes that have a binding location
1969 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1970 {
1971 int location = attributeBindings.getAttributeBinding(attribute->name);
1972
1973 if (location != -1) // Set by glBindAttribLocation
1974 {
1975 if (!mLinkedAttribute[location].name.empty())
1976 {
1977 // Multiple active attributes bound to the same location; not an error
1978 }
1979
1980 mLinkedAttribute[location] = *attribute;
1981
1982 int rows = VariableRowCount(attribute->type);
1983
1984 if (rows + location > MAX_VERTEX_ATTRIBS)
1985 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001986 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 +00001987
1988 return false;
1989 }
1990
1991 for (int i = 0; i < rows; i++)
1992 {
1993 usedLocations |= 1 << (location + i);
1994 }
1995 }
1996 }
1997
1998 // Link attributes that don't have a binding location
1999 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2000 {
2001 int location = attributeBindings.getAttributeBinding(attribute->name);
2002
2003 if (location == -1) // Not set by glBindAttribLocation
2004 {
2005 int rows = VariableRowCount(attribute->type);
2006 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2007
2008 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2009 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002010 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002011
2012 return false; // Fail to link
2013 }
2014
2015 mLinkedAttribute[availableIndex] = *attribute;
2016 }
2017 }
2018
2019 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2020 {
2021 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2022 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2023
2024 for (int r = 0; r < rows; r++)
2025 {
2026 mSemanticIndex[attributeIndex++] = index++;
2027 }
2028 }
2029
2030 return true;
2031}
2032
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002033bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, ID3DXConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002034{
2035 D3DXCONSTANTTABLE_DESC constantTableDescription;
2036
2037 constantTable->GetDesc(&constantTableDescription);
2038
2039 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
2040 {
2041 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
2042
2043 D3DXCONSTANT_DESC constantDescription;
2044 UINT descriptionCount = 1;
2045 HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
2046 ASSERT(SUCCEEDED(result));
2047
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002048 if (!defineUniform(infoLog, shader, constantHandle, constantDescription))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002049 {
2050 return false;
2051 }
2052 }
2053
2054 return true;
2055}
2056
2057// Adds the description of a constant found in the binary shader to the list of uniforms
2058// Returns true if succesful (uniform not already defined)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002059bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002060{
2061 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
2062 {
2063 for (unsigned int i = 0; i < constantDescription.RegisterCount; i++)
2064 {
2065 D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name);
2066 D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name);
2067
2068 if (psConstant)
2069 {
2070 unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i;
2071
2072 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2073 {
2074 mSamplersPS[samplerIndex].active = true;
2075 mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2076 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2077 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2078 }
2079 else
2080 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002081 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082 return false;
2083 }
2084 }
2085
2086 if (vsConstant)
2087 {
2088 unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i;
2089
2090 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2091 {
2092 mSamplersVS[samplerIndex].active = true;
2093 mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2094 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2095 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2096 }
2097 else
2098 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002099 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002100 return false;
2101 }
2102 }
2103 }
2104 }
2105
2106 switch(constantDescription.Class)
2107 {
2108 case D3DXPC_STRUCT:
2109 {
2110 for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
2111 {
2112 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
2113 {
2114 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
2115
2116 D3DXCONSTANT_DESC fieldDescription;
2117 UINT descriptionCount = 1;
2118
2119 HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
2120 ASSERT(SUCCEEDED(result));
2121
2122 std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
2123
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002124 if (!defineUniform(infoLog, shader, fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002125 {
2126 return false;
2127 }
2128 }
2129 }
2130
2131 return true;
2132 }
2133 case D3DXPC_SCALAR:
2134 case D3DXPC_VECTOR:
2135 case D3DXPC_MATRIX_COLUMNS:
2136 case D3DXPC_OBJECT:
2137 return defineUniform(shader, constantDescription, name + constantDescription.Name);
2138 default:
2139 UNREACHABLE();
2140 return false;
2141 }
2142}
2143
2144bool ProgramBinary::defineUniform(GLenum shader, const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
2145{
2146 Uniform *uniform = createUniform(constantDescription, _name);
2147
2148 if(!uniform)
2149 {
2150 return false;
2151 }
2152
2153 // Check if already defined
2154 GLint location = getUniformLocation(uniform->name);
2155 GLenum type = uniform->type;
2156
2157 if (location >= 0)
2158 {
2159 delete uniform;
2160 uniform = mUniforms[mUniformIndex[location].index];
2161 }
2162
2163 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constantDescription);
2164 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constantDescription);
2165
2166 if (location >= 0)
2167 {
2168 return uniform->type == type;
2169 }
2170
2171 mUniforms.push_back(uniform);
2172 unsigned int uniformIndex = mUniforms.size() - 1;
2173
2174 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2175 {
2176 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2177 }
2178
2179 return true;
2180}
2181
2182Uniform *ProgramBinary::createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &_name)
2183{
2184 if (constantDescription.Rows == 1) // Vectors and scalars
2185 {
2186 switch (constantDescription.Type)
2187 {
2188 case D3DXPT_SAMPLER2D:
2189 switch (constantDescription.Columns)
2190 {
2191 case 1: return new Uniform(GL_SAMPLER_2D, _name, constantDescription.Elements);
2192 default: UNREACHABLE();
2193 }
2194 break;
2195 case D3DXPT_SAMPLERCUBE:
2196 switch (constantDescription.Columns)
2197 {
2198 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constantDescription.Elements);
2199 default: UNREACHABLE();
2200 }
2201 break;
2202 case D3DXPT_BOOL:
2203 switch (constantDescription.Columns)
2204 {
2205 case 1: return new Uniform(GL_BOOL, _name, constantDescription.Elements);
2206 case 2: return new Uniform(GL_BOOL_VEC2, _name, constantDescription.Elements);
2207 case 3: return new Uniform(GL_BOOL_VEC3, _name, constantDescription.Elements);
2208 case 4: return new Uniform(GL_BOOL_VEC4, _name, constantDescription.Elements);
2209 default: UNREACHABLE();
2210 }
2211 break;
2212 case D3DXPT_INT:
2213 switch (constantDescription.Columns)
2214 {
2215 case 1: return new Uniform(GL_INT, _name, constantDescription.Elements);
2216 case 2: return new Uniform(GL_INT_VEC2, _name, constantDescription.Elements);
2217 case 3: return new Uniform(GL_INT_VEC3, _name, constantDescription.Elements);
2218 case 4: return new Uniform(GL_INT_VEC4, _name, constantDescription.Elements);
2219 default: UNREACHABLE();
2220 }
2221 break;
2222 case D3DXPT_FLOAT:
2223 switch (constantDescription.Columns)
2224 {
2225 case 1: return new Uniform(GL_FLOAT, _name, constantDescription.Elements);
2226 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constantDescription.Elements);
2227 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constantDescription.Elements);
2228 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constantDescription.Elements);
2229 default: UNREACHABLE();
2230 }
2231 break;
2232 default:
2233 UNREACHABLE();
2234 }
2235 }
2236 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
2237 {
2238 switch (constantDescription.Type)
2239 {
2240 case D3DXPT_FLOAT:
2241 switch (constantDescription.Rows)
2242 {
2243 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constantDescription.Elements);
2244 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constantDescription.Elements);
2245 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constantDescription.Elements);
2246 default: UNREACHABLE();
2247 }
2248 break;
2249 default: UNREACHABLE();
2250 }
2251 }
2252 else UNREACHABLE();
2253
2254 return 0;
2255}
2256
2257// This method needs to match OutputHLSL::decorate
2258std::string ProgramBinary::decorateAttribute(const std::string &name)
2259{
2260 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2261 {
2262 return "_" + name;
2263 }
2264
2265 return name;
2266}
2267
2268std::string ProgramBinary::undecorateUniform(const std::string &_name)
2269{
2270 std::string name = _name;
2271
2272 // Remove any structure field decoration
2273 size_t pos = 0;
2274 while ((pos = name.find("._", pos)) != std::string::npos)
2275 {
2276 name.replace(pos, 2, ".");
2277 }
2278
2279 // Remove the leading decoration
2280 if (name[0] == '_')
2281 {
2282 return name.substr(1);
2283 }
2284 else if (name.compare(0, 3, "ar_") == 0)
2285 {
2286 return name.substr(3);
2287 }
2288
2289 return name;
2290}
2291
2292void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2293{
2294 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2295 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2296
2297 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2298 {
2299 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2300 for (int i = 0; i < count; i++)
2301 {
2302 for (int j = 0; j < 4; j++)
2303 {
2304 if (j < width)
2305 {
2306 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2307 }
2308 else
2309 {
2310 vector[i * 4 + j] = 0.0f;
2311 }
2312 }
2313 }
2314 }
2315
2316 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2317 {
2318 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2319 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2320 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2321 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2322 for (int i = 0; i < copyCount; i++)
2323 {
2324 boolVector[i] = v[i] != GL_FALSE;
2325 }
2326 }
2327
2328 if (targetUniform->ps.float4Index >= 0)
2329 {
2330 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2331 }
2332
2333 if (targetUniform->ps.boolIndex >= 0)
2334 {
2335 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2336 }
2337
2338 if (targetUniform->vs.float4Index >= 0)
2339 {
2340 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2341 }
2342
2343 if (targetUniform->vs.boolIndex >= 0)
2344 {
2345 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2346 }
2347}
2348
2349bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2350{
2351 if (targetUniform->ps.registerCount)
2352 {
2353 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2354 }
2355
2356 if (targetUniform->vs.registerCount)
2357 {
2358 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2359 }
2360
2361 return true;
2362}
2363
2364bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2365{
2366 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2367 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
2368
2369 for (int i = 0; i < count; i++)
2370 {
2371 vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
2372 }
2373
2374 if (targetUniform->ps.registerCount)
2375 {
2376 if (targetUniform->ps.samplerIndex >= 0)
2377 {
2378 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2379
2380 for (int i = 0; i < count; i++)
2381 {
2382 unsigned int samplerIndex = firstIndex + i;
2383
2384 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2385 {
2386 ASSERT(mSamplersPS[samplerIndex].active);
2387 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2388 }
2389 }
2390 }
2391 else
2392 {
2393 ASSERT(targetUniform->ps.float4Index >= 0);
2394 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2395 }
2396 }
2397
2398 if (targetUniform->vs.registerCount)
2399 {
2400 if (targetUniform->vs.samplerIndex >= 0)
2401 {
2402 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2403
2404 for (int i = 0; i < count; i++)
2405 {
2406 unsigned int samplerIndex = firstIndex + i;
2407
2408 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2409 {
2410 ASSERT(mSamplersVS[samplerIndex].active);
2411 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2412 }
2413 }
2414 }
2415 else
2416 {
2417 ASSERT(targetUniform->vs.float4Index >= 0);
2418 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2419 }
2420 }
2421
2422 return true;
2423}
2424
2425bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2426{
2427 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2428 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
2429
2430 for (int i = 0; i < count; i++)
2431 {
2432 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
2433
2434 v += 2;
2435 }
2436
2437 applyUniformniv(targetUniform, count, vector);
2438
2439 return true;
2440}
2441
2442bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2443{
2444 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2445 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
2446
2447 for (int i = 0; i < count; i++)
2448 {
2449 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
2450
2451 v += 3;
2452 }
2453
2454 applyUniformniv(targetUniform, count, vector);
2455
2456 return true;
2457}
2458
2459bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2460{
2461 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2462 D3DXVECTOR4 vector[D3D9_MAX_FLOAT_CONSTANTS];
2463
2464 for (int i = 0; i < count; i++)
2465 {
2466 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
2467
2468 v += 4;
2469 }
2470
2471 applyUniformniv(targetUniform, count, vector);
2472
2473 return true;
2474}
2475
2476void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
2477{
2478 if (targetUniform->ps.registerCount)
2479 {
2480 ASSERT(targetUniform->ps.float4Index >= 0);
2481 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2482 }
2483
2484 if (targetUniform->vs.registerCount)
2485 {
2486 ASSERT(targetUniform->vs.float4Index >= 0);
2487 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2488 }
2489}
2490
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002491bool ProgramBinary::isValidated() const
2492{
2493 return mValidated;
2494}
2495
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002496void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2497{
2498 // Skip over inactive attributes
2499 unsigned int activeAttribute = 0;
2500 unsigned int attribute;
2501 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2502 {
2503 if (mLinkedAttribute[attribute].name.empty())
2504 {
2505 continue;
2506 }
2507
2508 if (activeAttribute == index)
2509 {
2510 break;
2511 }
2512
2513 activeAttribute++;
2514 }
2515
2516 if (bufsize > 0)
2517 {
2518 const char *string = mLinkedAttribute[attribute].name.c_str();
2519
2520 strncpy(name, string, bufsize);
2521 name[bufsize - 1] = '\0';
2522
2523 if (length)
2524 {
2525 *length = strlen(name);
2526 }
2527 }
2528
2529 *size = 1; // Always a single 'type' instance
2530
2531 *type = mLinkedAttribute[attribute].type;
2532}
2533
2534GLint ProgramBinary::getActiveAttributeCount()
2535{
2536 int count = 0;
2537
2538 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2539 {
2540 if (!mLinkedAttribute[attributeIndex].name.empty())
2541 {
2542 count++;
2543 }
2544 }
2545
2546 return count;
2547}
2548
2549GLint ProgramBinary::getActiveAttributeMaxLength()
2550{
2551 int maxLength = 0;
2552
2553 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2554 {
2555 if (!mLinkedAttribute[attributeIndex].name.empty())
2556 {
2557 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2558 }
2559 }
2560
2561 return maxLength;
2562}
2563
2564void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2565{
2566 // Skip over internal uniforms
2567 unsigned int activeUniform = 0;
2568 unsigned int uniform;
2569 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2570 {
2571 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2572 {
2573 continue;
2574 }
2575
2576 if (activeUniform == index)
2577 {
2578 break;
2579 }
2580
2581 activeUniform++;
2582 }
2583
2584 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2585
2586 if (bufsize > 0)
2587 {
2588 std::string string = mUniforms[uniform]->name;
2589
2590 if (mUniforms[uniform]->isArray())
2591 {
2592 string += "[0]";
2593 }
2594
2595 strncpy(name, string.c_str(), bufsize);
2596 name[bufsize - 1] = '\0';
2597
2598 if (length)
2599 {
2600 *length = strlen(name);
2601 }
2602 }
2603
2604 *size = mUniforms[uniform]->arraySize;
2605
2606 *type = mUniforms[uniform]->type;
2607}
2608
2609GLint ProgramBinary::getActiveUniformCount()
2610{
2611 int count = 0;
2612
2613 unsigned int numUniforms = mUniforms.size();
2614 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2615 {
2616 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2617 {
2618 count++;
2619 }
2620 }
2621
2622 return count;
2623}
2624
2625GLint ProgramBinary::getActiveUniformMaxLength()
2626{
2627 int maxLength = 0;
2628
2629 unsigned int numUniforms = mUniforms.size();
2630 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2631 {
2632 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2633 {
2634 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2635 if (mUniforms[uniformIndex]->isArray())
2636 {
2637 length += 3; // Counting in "[0]".
2638 }
2639 maxLength = std::max(length, maxLength);
2640 }
2641 }
2642
2643 return maxLength;
2644}
2645
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002646void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002647{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002648 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002649 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002650 {
2651 mValidated = false;
2652 }
2653 else
2654 {
2655 mValidated = true;
2656 }
2657}
2658
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002659bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002660{
2661 // if any two active samplers in a program are of different types, but refer to the same
2662 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2663 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2664
2665 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2666 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2667
2668 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2669 {
2670 textureUnitType[i] = TEXTURE_UNKNOWN;
2671 }
2672
2673 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2674 {
2675 if (mSamplersPS[i].active)
2676 {
2677 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2678
2679 if (unit >= maxCombinedTextureImageUnits)
2680 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002681 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002682 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002683 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002684 }
2685
2686 return false;
2687 }
2688
2689 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2690 {
2691 if (mSamplersPS[i].textureType != textureUnitType[unit])
2692 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002693 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002694 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002695 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002696 }
2697
2698 return false;
2699 }
2700 }
2701 else
2702 {
2703 textureUnitType[unit] = mSamplersPS[i].textureType;
2704 }
2705 }
2706 }
2707
2708 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2709 {
2710 if (mSamplersVS[i].active)
2711 {
2712 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2713
2714 if (unit >= maxCombinedTextureImageUnits)
2715 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002716 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002717 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002718 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002719 }
2720
2721 return false;
2722 }
2723
2724 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2725 {
2726 if (mSamplersVS[i].textureType != textureUnitType[unit])
2727 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002728 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002729 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002730 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002731 }
2732
2733 return false;
2734 }
2735 }
2736 else
2737 {
2738 textureUnitType[unit] = mSamplersVS[i].textureType;
2739 }
2740 }
2741 }
2742
2743 return true;
2744}
2745
2746GLint ProgramBinary::getDxDepthRangeLocation() const
2747{
2748 return mDxDepthRangeLocation;
2749}
2750
2751GLint ProgramBinary::getDxDepthLocation() const
2752{
2753 return mDxDepthLocation;
2754}
2755
2756GLint ProgramBinary::getDxCoordLocation() const
2757{
2758 return mDxCoordLocation;
2759}
2760
2761GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2762{
2763 return mDxHalfPixelSizeLocation;
2764}
2765
2766GLint ProgramBinary::getDxFrontCCWLocation() const
2767{
2768 return mDxFrontCCWLocation;
2769}
2770
2771GLint ProgramBinary::getDxPointsOrLinesLocation() const
2772{
2773 return mDxPointsOrLinesLocation;
2774}
2775
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002776ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2777{
2778}
2779
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002780}