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