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