blob: 1ce785bcf53a01b43901248646c0aa9c0ebfef54 [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
2// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/Program.h"
12#include "libGLESv2/ProgramBinary.h"
13
14#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000015#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/Shader.h"
19#include "libGLESv2/utilities.h"
20
21#include <string>
22
23#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
24#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
25#endif
26
27namespace gl
28{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029std::string str(int i)
30{
31 char buffer[20];
32 snprintf(buffer, sizeof(buffer), "%d", i);
33 return buffer;
34}
35
36Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
37 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
38{
39 int bytes = UniformInternalSize(type) * arraySize;
40 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
43}
44
45Uniform::~Uniform()
46{
47 delete[] data;
48}
49
50bool Uniform::isArray()
51{
daniel@transgaming.com22ba0f72012-09-27 17:46:04 +000052 size_t dot = _name.find_last_of('.');
53 if (dot == std::string::npos) dot = -1;
54
55 return _name.compare(dot + 1, dot + 4, "ar_") == 0;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000056}
57
58UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
59 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
60{
61}
62
daniel@transgaming.come87ca002012-07-24 18:30:43 +000063unsigned int ProgramBinary::mCurrentSerial = 1;
64
daniel@transgaming.com989c1c82012-07-24 18:40:38 +000065ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000066{
67 mDevice = getDevice();
68
69 mPixelExecutable = NULL;
70 mVertexExecutable = NULL;
71 mConstantTablePS = NULL;
72 mConstantTableVS = NULL;
73
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000074 mValidated = false;
75
76 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
77 {
78 mSemanticIndex[index] = -1;
79 }
80
81 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
82 {
83 mSamplersPS[index].active = false;
84 }
85
86 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
87 {
88 mSamplersVS[index].active = false;
89 }
90
91 mUsedVertexSamplerRange = 0;
92 mUsedPixelSamplerRange = 0;
93
94 mDxDepthRangeLocation = -1;
95 mDxDepthLocation = -1;
96 mDxCoordLocation = -1;
97 mDxHalfPixelSizeLocation = -1;
98 mDxFrontCCWLocation = -1;
99 mDxPointsOrLinesLocation = -1;
100}
101
102ProgramBinary::~ProgramBinary()
103{
104 if (mPixelExecutable)
105 {
106 mPixelExecutable->Release();
107 }
108
109 if (mVertexExecutable)
110 {
111 mVertexExecutable->Release();
112 }
113
apatrick@chromium.org60dafe82012-09-05 22:26:10 +0000114 delete mConstantTablePS;
115 delete mConstantTableVS;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000116
117 while (!mUniforms.empty())
118 {
119 delete mUniforms.back();
120 mUniforms.pop_back();
121 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000122}
123
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000124unsigned int ProgramBinary::getSerial() const
125{
126 return mSerial;
127}
128
129unsigned int ProgramBinary::issueSerial()
130{
131 return mCurrentSerial++;
132}
133
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000134IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
135{
136 return mPixelExecutable;
137}
138
139IDirect3DVertexShader9 *ProgramBinary::getVertexShader()
140{
141 return mVertexExecutable;
142}
143
144GLuint ProgramBinary::getAttributeLocation(const char *name)
145{
146 if (name)
147 {
148 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
149 {
150 if (mLinkedAttribute[index].name == std::string(name))
151 {
152 return index;
153 }
154 }
155 }
156
157 return -1;
158}
159
160int ProgramBinary::getSemanticIndex(int attributeIndex)
161{
162 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
163
164 return mSemanticIndex[attributeIndex];
165}
166
167// Returns one more than the highest sampler index used.
168GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
169{
170 switch (type)
171 {
172 case SAMPLER_PIXEL:
173 return mUsedPixelSamplerRange;
174 case SAMPLER_VERTEX:
175 return mUsedVertexSamplerRange;
176 default:
177 UNREACHABLE();
178 return 0;
179 }
180}
181
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000182bool ProgramBinary::usesPointSize() const
183{
184 return mUsesPointSize;
185}
186
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000187// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
188// index (0-15 for the pixel shader and 0-3 for the vertex shader).
189GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
190{
191 GLint logicalTextureUnit = -1;
192
193 switch (type)
194 {
195 case SAMPLER_PIXEL:
196 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
197
198 if (mSamplersPS[samplerIndex].active)
199 {
200 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
201 }
202 break;
203 case SAMPLER_VERTEX:
204 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
205
206 if (mSamplersVS[samplerIndex].active)
207 {
208 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
209 }
210 break;
211 default: UNREACHABLE();
212 }
213
214 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
215 {
216 return logicalTextureUnit;
217 }
218
219 return -1;
220}
221
222// Returns the texture type for a given Direct3D 9 sampler type and
223// index (0-15 for the pixel shader and 0-3 for the vertex shader).
224TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
225{
226 switch (type)
227 {
228 case SAMPLER_PIXEL:
229 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
230 ASSERT(mSamplersPS[samplerIndex].active);
231 return mSamplersPS[samplerIndex].textureType;
232 case SAMPLER_VERTEX:
233 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
234 ASSERT(mSamplersVS[samplerIndex].active);
235 return mSamplersVS[samplerIndex].textureType;
236 default: UNREACHABLE();
237 }
238
239 return TEXTURE_2D;
240}
241
242GLint ProgramBinary::getUniformLocation(std::string name)
243{
244 unsigned int subscript = 0;
245
246 // Strip any trailing array operator and retrieve the subscript
247 size_t open = name.find_last_of('[');
248 size_t close = name.find_last_of(']');
249 if (open != std::string::npos && close == name.length() - 1)
250 {
251 subscript = atoi(name.substr(open + 1).c_str());
252 name.erase(open);
253 }
254
255 unsigned int numUniforms = mUniformIndex.size();
256 for (unsigned int location = 0; location < numUniforms; location++)
257 {
258 if (mUniformIndex[location].name == name &&
259 mUniformIndex[location].element == subscript)
260 {
261 return location;
262 }
263 }
264
265 return -1;
266}
267
268bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
269{
270 if (location < 0 || location >= (int)mUniformIndex.size())
271 {
272 return false;
273 }
274
275 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
276 targetUniform->dirty = true;
277
278 if (targetUniform->type == GL_FLOAT)
279 {
280 int arraySize = targetUniform->arraySize;
281
282 if (arraySize == 1 && count > 1)
283 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
284
285 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
286
287 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
288
289 for (int i = 0; i < count; i++)
290 {
291 target[0] = v[0];
292 target[1] = 0;
293 target[2] = 0;
294 target[3] = 0;
295 target += 4;
296 v += 1;
297 }
298 }
299 else if (targetUniform->type == GL_BOOL)
300 {
301 int arraySize = targetUniform->arraySize;
302
303 if (arraySize == 1 && count > 1)
304 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
305
306 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
307 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
308
309 for (int i = 0; i < count; ++i)
310 {
311 if (v[i] == 0.0f)
312 {
313 boolParams[i] = GL_FALSE;
314 }
315 else
316 {
317 boolParams[i] = GL_TRUE;
318 }
319 }
320 }
321 else
322 {
323 return false;
324 }
325
326 return true;
327}
328
329bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
330{
331 if (location < 0 || location >= (int)mUniformIndex.size())
332 {
333 return false;
334 }
335
336 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
337 targetUniform->dirty = true;
338
339 if (targetUniform->type == GL_FLOAT_VEC2)
340 {
341 int arraySize = targetUniform->arraySize;
342
343 if (arraySize == 1 && count > 1)
344 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
345
346 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
347
348 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
349
350 for (int i = 0; i < count; i++)
351 {
352 target[0] = v[0];
353 target[1] = v[1];
354 target[2] = 0;
355 target[3] = 0;
356 target += 4;
357 v += 2;
358 }
359 }
360 else if (targetUniform->type == GL_BOOL_VEC2)
361 {
362 int arraySize = targetUniform->arraySize;
363
364 if (arraySize == 1 && count > 1)
365 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
366
367 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
368
369 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
370
371 for (int i = 0; i < count * 2; ++i)
372 {
373 if (v[i] == 0.0f)
374 {
375 boolParams[i] = GL_FALSE;
376 }
377 else
378 {
379 boolParams[i] = GL_TRUE;
380 }
381 }
382 }
383 else
384 {
385 return false;
386 }
387
388 return true;
389}
390
391bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
392{
393 if (location < 0 || location >= (int)mUniformIndex.size())
394 {
395 return false;
396 }
397
398 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
399 targetUniform->dirty = true;
400
401 if (targetUniform->type == GL_FLOAT_VEC3)
402 {
403 int arraySize = targetUniform->arraySize;
404
405 if (arraySize == 1 && count > 1)
406 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
407
408 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
409
410 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
411
412 for (int i = 0; i < count; i++)
413 {
414 target[0] = v[0];
415 target[1] = v[1];
416 target[2] = v[2];
417 target[3] = 0;
418 target += 4;
419 v += 3;
420 }
421 }
422 else if (targetUniform->type == GL_BOOL_VEC3)
423 {
424 int arraySize = targetUniform->arraySize;
425
426 if (arraySize == 1 && count > 1)
427 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
428
429 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
430 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
431
432 for (int i = 0; i < count * 3; ++i)
433 {
434 if (v[i] == 0.0f)
435 {
436 boolParams[i] = GL_FALSE;
437 }
438 else
439 {
440 boolParams[i] = GL_TRUE;
441 }
442 }
443 }
444 else
445 {
446 return false;
447 }
448
449 return true;
450}
451
452bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
453{
454 if (location < 0 || location >= (int)mUniformIndex.size())
455 {
456 return false;
457 }
458
459 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
460 targetUniform->dirty = true;
461
462 if (targetUniform->type == GL_FLOAT_VEC4)
463 {
464 int arraySize = targetUniform->arraySize;
465
466 if (arraySize == 1 && count > 1)
467 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
468
469 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
470
471 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
472 v, 4 * sizeof(GLfloat) * count);
473 }
474 else if (targetUniform->type == GL_BOOL_VEC4)
475 {
476 int arraySize = targetUniform->arraySize;
477
478 if (arraySize == 1 && count > 1)
479 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
480
481 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
482 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
483
484 for (int i = 0; i < count * 4; ++i)
485 {
486 if (v[i] == 0.0f)
487 {
488 boolParams[i] = GL_FALSE;
489 }
490 else
491 {
492 boolParams[i] = GL_TRUE;
493 }
494 }
495 }
496 else
497 {
498 return false;
499 }
500
501 return true;
502}
503
504template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
505void transposeMatrix(T *target, const GLfloat *value)
506{
507 int copyWidth = std::min(targetWidth, srcWidth);
508 int copyHeight = std::min(targetHeight, srcHeight);
509
510 for (int x = 0; x < copyWidth; x++)
511 {
512 for (int y = 0; y < copyHeight; y++)
513 {
514 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
515 }
516 }
517 // clear unfilled right side
518 for (int y = 0; y < copyHeight; y++)
519 {
520 for (int x = srcWidth; x < targetWidth; x++)
521 {
522 target[y * targetWidth + x] = (T)0;
523 }
524 }
525 // clear unfilled bottom.
526 for (int y = srcHeight; y < targetHeight; y++)
527 {
528 for (int x = 0; x < targetWidth; x++)
529 {
530 target[y * targetWidth + x] = (T)0;
531 }
532 }
533}
534
535bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
536{
537 if (location < 0 || location >= (int)mUniformIndex.size())
538 {
539 return false;
540 }
541
542 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
543 targetUniform->dirty = true;
544
545 if (targetUniform->type != GL_FLOAT_MAT2)
546 {
547 return false;
548 }
549
550 int arraySize = targetUniform->arraySize;
551
552 if (arraySize == 1 && count > 1)
553 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
554
555 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
556
557 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
558 for (int i = 0; i < count; i++)
559 {
560 transposeMatrix<GLfloat,4,2,2,2>(target, value);
561 target += 8;
562 value += 4;
563 }
564
565 return true;
566}
567
568bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
569{
570 if (location < 0 || location >= (int)mUniformIndex.size())
571 {
572 return false;
573 }
574
575 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
576 targetUniform->dirty = true;
577
578 if (targetUniform->type != GL_FLOAT_MAT3)
579 {
580 return false;
581 }
582
583 int arraySize = targetUniform->arraySize;
584
585 if (arraySize == 1 && count > 1)
586 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
587
588 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
589
590 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
591 for (int i = 0; i < count; i++)
592 {
593 transposeMatrix<GLfloat,4,3,3,3>(target, value);
594 target += 12;
595 value += 9;
596 }
597
598 return true;
599}
600
601
602bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
603{
604 if (location < 0 || location >= (int)mUniformIndex.size())
605 {
606 return false;
607 }
608
609 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
610 targetUniform->dirty = true;
611
612 if (targetUniform->type != GL_FLOAT_MAT4)
613 {
614 return false;
615 }
616
617 int arraySize = targetUniform->arraySize;
618
619 if (arraySize == 1 && count > 1)
620 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
621
622 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
623
624 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
625 for (int i = 0; i < count; i++)
626 {
627 transposeMatrix<GLfloat,4,4,4,4>(target, value);
628 target += 16;
629 value += 16;
630 }
631
632 return true;
633}
634
635bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
636{
637 if (location < 0 || location >= (int)mUniformIndex.size())
638 {
639 return false;
640 }
641
642 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
643 targetUniform->dirty = true;
644
645 if (targetUniform->type == GL_INT ||
646 targetUniform->type == GL_SAMPLER_2D ||
647 targetUniform->type == GL_SAMPLER_CUBE)
648 {
649 int arraySize = targetUniform->arraySize;
650
651 if (arraySize == 1 && count > 1)
652 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
653
654 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
655
656 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
657 v, sizeof(GLint) * count);
658 }
659 else if (targetUniform->type == GL_BOOL)
660 {
661 int arraySize = targetUniform->arraySize;
662
663 if (arraySize == 1 && count > 1)
664 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
665
666 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
667 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
668
669 for (int i = 0; i < count; ++i)
670 {
671 if (v[i] == 0)
672 {
673 boolParams[i] = GL_FALSE;
674 }
675 else
676 {
677 boolParams[i] = GL_TRUE;
678 }
679 }
680 }
681 else
682 {
683 return false;
684 }
685
686 return true;
687}
688
689bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
690{
691 if (location < 0 || location >= (int)mUniformIndex.size())
692 {
693 return false;
694 }
695
696 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
697 targetUniform->dirty = true;
698
699 if (targetUniform->type == GL_INT_VEC2)
700 {
701 int arraySize = targetUniform->arraySize;
702
703 if (arraySize == 1 && count > 1)
704 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
705
706 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
707
708 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
709 v, 2 * sizeof(GLint) * count);
710 }
711 else if (targetUniform->type == GL_BOOL_VEC2)
712 {
713 int arraySize = targetUniform->arraySize;
714
715 if (arraySize == 1 && count > 1)
716 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
717
718 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
719 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
720
721 for (int i = 0; i < count * 2; ++i)
722 {
723 if (v[i] == 0)
724 {
725 boolParams[i] = GL_FALSE;
726 }
727 else
728 {
729 boolParams[i] = GL_TRUE;
730 }
731 }
732 }
733 else
734 {
735 return false;
736 }
737
738 return true;
739}
740
741bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
742{
743 if (location < 0 || location >= (int)mUniformIndex.size())
744 {
745 return false;
746 }
747
748 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
749 targetUniform->dirty = true;
750
751 if (targetUniform->type == GL_INT_VEC3)
752 {
753 int arraySize = targetUniform->arraySize;
754
755 if (arraySize == 1 && count > 1)
756 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
757
758 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
759
760 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
761 v, 3 * sizeof(GLint) * count);
762 }
763 else if (targetUniform->type == GL_BOOL_VEC3)
764 {
765 int arraySize = targetUniform->arraySize;
766
767 if (arraySize == 1 && count > 1)
768 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
769
770 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
771 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
772
773 for (int i = 0; i < count * 3; ++i)
774 {
775 if (v[i] == 0)
776 {
777 boolParams[i] = GL_FALSE;
778 }
779 else
780 {
781 boolParams[i] = GL_TRUE;
782 }
783 }
784 }
785 else
786 {
787 return false;
788 }
789
790 return true;
791}
792
793bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
794{
795 if (location < 0 || location >= (int)mUniformIndex.size())
796 {
797 return false;
798 }
799
800 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
801 targetUniform->dirty = true;
802
803 if (targetUniform->type == GL_INT_VEC4)
804 {
805 int arraySize = targetUniform->arraySize;
806
807 if (arraySize == 1 && count > 1)
808 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
809
810 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
811
812 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
813 v, 4 * sizeof(GLint) * count);
814 }
815 else if (targetUniform->type == GL_BOOL_VEC4)
816 {
817 int arraySize = targetUniform->arraySize;
818
819 if (arraySize == 1 && count > 1)
820 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
821
822 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
823 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
824
825 for (int i = 0; i < count * 4; ++i)
826 {
827 if (v[i] == 0)
828 {
829 boolParams[i] = GL_FALSE;
830 }
831 else
832 {
833 boolParams[i] = GL_TRUE;
834 }
835 }
836 }
837 else
838 {
839 return false;
840 }
841
842 return true;
843}
844
845bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
846{
847 if (location < 0 || location >= (int)mUniformIndex.size())
848 {
849 return false;
850 }
851
852 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
853
854 // sized queries -- ensure the provided buffer is large enough
855 if (bufSize)
856 {
857 int requiredBytes = UniformExternalSize(targetUniform->type);
858 if (*bufSize < requiredBytes)
859 {
860 return false;
861 }
862 }
863
864 switch (targetUniform->type)
865 {
866 case GL_FLOAT_MAT2:
867 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
868 break;
869 case GL_FLOAT_MAT3:
870 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
871 break;
872 case GL_FLOAT_MAT4:
873 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
874 break;
875 default:
876 {
877 unsigned int count = UniformExternalComponentCount(targetUniform->type);
878 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
879
880 switch (UniformComponentType(targetUniform->type))
881 {
882 case GL_BOOL:
883 {
884 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
885
886 for (unsigned int i = 0; i < count; ++i)
887 {
888 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
889 }
890 }
891 break;
892 case GL_FLOAT:
893 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
894 count * sizeof(GLfloat));
895 break;
896 case GL_INT:
897 {
898 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
899
900 for (unsigned int i = 0; i < count; ++i)
901 {
902 params[i] = (float)intParams[i];
903 }
904 }
905 break;
906 default: UNREACHABLE();
907 }
908 }
909 }
910
911 return true;
912}
913
914bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
915{
916 if (location < 0 || location >= (int)mUniformIndex.size())
917 {
918 return false;
919 }
920
921 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
922
923 // sized queries -- ensure the provided buffer is large enough
924 if (bufSize)
925 {
926 int requiredBytes = UniformExternalSize(targetUniform->type);
927 if (*bufSize < requiredBytes)
928 {
929 return false;
930 }
931 }
932
933 switch (targetUniform->type)
934 {
935 case GL_FLOAT_MAT2:
936 {
937 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
938 }
939 break;
940 case GL_FLOAT_MAT3:
941 {
942 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
943 }
944 break;
945 case GL_FLOAT_MAT4:
946 {
947 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
948 }
949 break;
950 default:
951 {
952 unsigned int count = UniformExternalComponentCount(targetUniform->type);
953 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
954
955 switch (UniformComponentType(targetUniform->type))
956 {
957 case GL_BOOL:
958 {
959 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
960
961 for (unsigned int i = 0; i < count; ++i)
962 {
963 params[i] = (GLint)boolParams[i];
964 }
965 }
966 break;
967 case GL_FLOAT:
968 {
969 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
970
971 for (unsigned int i = 0; i < count; ++i)
972 {
973 params[i] = (GLint)floatParams[i];
974 }
975 }
976 break;
977 case GL_INT:
978 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
979 count * sizeof(GLint));
980 break;
981 default: UNREACHABLE();
982 }
983 }
984 }
985
986 return true;
987}
988
989void ProgramBinary::dirtyAllUniforms()
990{
991 unsigned int numUniforms = mUniforms.size();
992 for (unsigned int index = 0; index < numUniforms; index++)
993 {
994 mUniforms[index]->dirty = true;
995 }
996}
997
998// Applies all the uniforms set for this program object to the Direct3D 9 device
999void ProgramBinary::applyUniforms()
1000{
1001 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1002 Uniform *targetUniform = *ub;
1003
1004 if (targetUniform->dirty)
1005 {
1006 int arraySize = targetUniform->arraySize;
1007 GLfloat *f = (GLfloat*)targetUniform->data;
1008 GLint *i = (GLint*)targetUniform->data;
1009 GLboolean *b = (GLboolean*)targetUniform->data;
1010
1011 switch (targetUniform->type)
1012 {
1013 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1014 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1015 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1016 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1017 case GL_FLOAT:
1018 case GL_FLOAT_VEC2:
1019 case GL_FLOAT_VEC3:
1020 case GL_FLOAT_VEC4:
1021 case GL_FLOAT_MAT2:
1022 case GL_FLOAT_MAT3:
1023 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1024 case GL_SAMPLER_2D:
1025 case GL_SAMPLER_CUBE:
1026 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1027 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1028 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1029 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1030 default:
1031 UNREACHABLE();
1032 }
1033
1034 targetUniform->dirty = false;
1035 }
1036 }
1037}
1038
1039// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001040ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001041{
1042 if (!hlsl)
1043 {
1044 return NULL;
1045 }
1046
1047 DWORD result;
1048 UINT flags = 0;
1049 std::string sourceText;
1050 if (perfActive())
1051 {
1052 flags |= D3DCOMPILE_DEBUG;
1053#ifdef NDEBUG
1054 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1055#else
1056 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
1057#endif
1058
1059 std::string sourcePath = getTempPath();
1060 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
1061 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
1062 }
1063 else
1064 {
1065 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1066 sourceText = hlsl;
1067 }
1068
1069 ID3D10Blob *binary = NULL;
1070 ID3D10Blob *errorMessage = NULL;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001071 result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001072
1073 if (errorMessage)
1074 {
1075 const char *message = (const char*)errorMessage->GetBufferPointer();
1076
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001077 infoLog.appendSanitized(message);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001078 TRACE("\n%s", hlsl);
1079 TRACE("\n%s", message);
1080
1081 errorMessage->Release();
1082 errorMessage = NULL;
1083 }
1084
1085 if (FAILED(result))
1086 {
1087 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1088 {
1089 error(GL_OUT_OF_MEMORY);
1090 }
1091
1092 return NULL;
1093 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001094
1095 D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize());
1096 if (table->error())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001097 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001098 delete table;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001099 binary->Release();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001100 return NULL;
1101 }
1102
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001103 *constantTable = table;
1104
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001105 return binary;
1106}
1107
1108// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1109// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001110int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001111{
1112 Context *context = getContext();
1113 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1114
1115 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1116 {
1117 int n = VariableRowCount(varying->type) * varying->size;
1118 int m = VariableColumnCount(varying->type);
1119 bool success = false;
1120
1121 if (m == 2 || m == 3 || m == 4)
1122 {
1123 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1124 {
1125 bool available = true;
1126
1127 for (int y = 0; y < n && available; y++)
1128 {
1129 for (int x = 0; x < m && available; x++)
1130 {
1131 if (packing[r + y][x])
1132 {
1133 available = false;
1134 }
1135 }
1136 }
1137
1138 if (available)
1139 {
1140 varying->reg = r;
1141 varying->col = 0;
1142
1143 for (int y = 0; y < n; y++)
1144 {
1145 for (int x = 0; x < m; x++)
1146 {
1147 packing[r + y][x] = &*varying;
1148 }
1149 }
1150
1151 success = true;
1152 }
1153 }
1154
1155 if (!success && m == 2)
1156 {
1157 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1158 {
1159 bool available = true;
1160
1161 for (int y = 0; y < n && available; y++)
1162 {
1163 for (int x = 2; x < 4 && available; x++)
1164 {
1165 if (packing[r + y][x])
1166 {
1167 available = false;
1168 }
1169 }
1170 }
1171
1172 if (available)
1173 {
1174 varying->reg = r;
1175 varying->col = 2;
1176
1177 for (int y = 0; y < n; y++)
1178 {
1179 for (int x = 2; x < 4; x++)
1180 {
1181 packing[r + y][x] = &*varying;
1182 }
1183 }
1184
1185 success = true;
1186 }
1187 }
1188 }
1189 }
1190 else if (m == 1)
1191 {
1192 int space[4] = {0};
1193
1194 for (int y = 0; y < maxVaryingVectors; y++)
1195 {
1196 for (int x = 0; x < 4; x++)
1197 {
1198 space[x] += packing[y][x] ? 0 : 1;
1199 }
1200 }
1201
1202 int column = 0;
1203
1204 for (int x = 0; x < 4; x++)
1205 {
1206 if (space[x] >= n && space[x] < space[column])
1207 {
1208 column = x;
1209 }
1210 }
1211
1212 if (space[column] >= n)
1213 {
1214 for (int r = 0; r < maxVaryingVectors; r++)
1215 {
1216 if (!packing[r][column])
1217 {
1218 varying->reg = r;
1219
1220 for (int y = r; y < r + n; y++)
1221 {
1222 packing[y][column] = &*varying;
1223 }
1224
1225 break;
1226 }
1227 }
1228
1229 varying->col = column;
1230
1231 success = true;
1232 }
1233 }
1234 else UNREACHABLE();
1235
1236 if (!success)
1237 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001238 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001239
1240 return -1;
1241 }
1242 }
1243
1244 // Return the number of used registers
1245 int registers = 0;
1246
1247 for (int r = 0; r < maxVaryingVectors; r++)
1248 {
1249 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1250 {
1251 registers++;
1252 }
1253 }
1254
1255 return registers;
1256}
1257
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001258bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001259{
1260 if (pixelHLSL.empty() || vertexHLSL.empty())
1261 {
1262 return false;
1263 }
1264
1265 // Reset the varying register assignments
1266 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1267 {
1268 fragVar->reg = -1;
1269 fragVar->col = -1;
1270 }
1271
1272 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1273 {
1274 vtxVar->reg = -1;
1275 vtxVar->col = -1;
1276 }
1277
1278 // Map the varyings to the register file
1279 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001280 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281
1282 if (registers < 0)
1283 {
1284 return false;
1285 }
1286
1287 // Write the HLSL input/output declarations
1288 Context *context = getContext();
1289 const bool sm3 = context->supportsShaderModel3();
1290 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1291
1292 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1293 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001294 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001295
1296 return false;
1297 }
1298
1299 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1300 {
1301 bool matched = false;
1302
1303 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1304 {
1305 if (output->name == input->name)
1306 {
1307 if (output->type != input->type || output->size != input->size)
1308 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001309 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 +00001310
1311 return false;
1312 }
1313
1314 output->reg = input->reg;
1315 output->col = input->col;
1316
1317 matched = true;
1318 break;
1319 }
1320 }
1321
1322 if (!matched)
1323 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001324 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001325
1326 return false;
1327 }
1328 }
1329
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001330 mUsesPointSize = vertexShader->mUsesPointSize;
1331 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001332
1333 vertexHLSL += "struct VS_INPUT\n"
1334 "{\n";
1335
1336 int semanticIndex = 0;
1337 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1338 {
1339 switch (attribute->type)
1340 {
1341 case GL_FLOAT: vertexHLSL += " float "; break;
1342 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1343 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1344 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1345 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1346 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1347 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1348 default: UNREACHABLE();
1349 }
1350
1351 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1352
1353 semanticIndex += VariableRowCount(attribute->type);
1354 }
1355
1356 vertexHLSL += "};\n"
1357 "\n"
1358 "struct VS_OUTPUT\n"
1359 "{\n"
1360 " float4 gl_Position : POSITION;\n";
1361
1362 for (int r = 0; r < registers; r++)
1363 {
1364 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1365
1366 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1367 }
1368
1369 if (fragmentShader->mUsesFragCoord)
1370 {
1371 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1372 }
1373
1374 if (vertexShader->mUsesPointSize && sm3)
1375 {
1376 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1377 }
1378
1379 vertexHLSL += "};\n"
1380 "\n"
1381 "VS_OUTPUT main(VS_INPUT input)\n"
1382 "{\n";
1383
1384 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1385 {
1386 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1387
1388 if (VariableRowCount(attribute->type) > 1) // Matrix
1389 {
1390 vertexHLSL += "transpose";
1391 }
1392
1393 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1394 }
1395
1396 vertexHLSL += "\n"
1397 " gl_main();\n"
1398 "\n"
1399 " VS_OUTPUT output;\n"
1400 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001401 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001402 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1403 " output.gl_Position.w = gl_Position.w;\n";
1404
1405 if (vertexShader->mUsesPointSize && sm3)
1406 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001407 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001408 }
1409
1410 if (fragmentShader->mUsesFragCoord)
1411 {
1412 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1413 }
1414
1415 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1416 {
1417 if (varying->reg >= 0)
1418 {
1419 for (int i = 0; i < varying->size; i++)
1420 {
1421 int rows = VariableRowCount(varying->type);
1422
1423 for (int j = 0; j < rows; j++)
1424 {
1425 int r = varying->reg + i * rows + j;
1426 vertexHLSL += " output.v" + str(r);
1427
1428 bool sharedRegister = false; // Register used by multiple varyings
1429
1430 for (int x = 0; x < 4; x++)
1431 {
1432 if (packing[r][x] && packing[r][x] != packing[r][0])
1433 {
1434 sharedRegister = true;
1435 break;
1436 }
1437 }
1438
1439 if(sharedRegister)
1440 {
1441 vertexHLSL += ".";
1442
1443 for (int x = 0; x < 4; x++)
1444 {
1445 if (packing[r][x] == &*varying)
1446 {
1447 switch(x)
1448 {
1449 case 0: vertexHLSL += "x"; break;
1450 case 1: vertexHLSL += "y"; break;
1451 case 2: vertexHLSL += "z"; break;
1452 case 3: vertexHLSL += "w"; break;
1453 }
1454 }
1455 }
1456 }
1457
1458 vertexHLSL += " = " + varying->name;
1459
1460 if (varying->array)
1461 {
1462 vertexHLSL += "[" + str(i) + "]";
1463 }
1464
1465 if (rows > 1)
1466 {
1467 vertexHLSL += "[" + str(j) + "]";
1468 }
1469
1470 vertexHLSL += ";\n";
1471 }
1472 }
1473 }
1474 }
1475
1476 vertexHLSL += "\n"
1477 " return output;\n"
1478 "}\n";
1479
1480 pixelHLSL += "struct PS_INPUT\n"
1481 "{\n";
1482
1483 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1484 {
1485 if (varying->reg >= 0)
1486 {
1487 for (int i = 0; i < varying->size; i++)
1488 {
1489 int rows = VariableRowCount(varying->type);
1490 for (int j = 0; j < rows; j++)
1491 {
1492 std::string n = str(varying->reg + i * rows + j);
1493 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1494 }
1495 }
1496 }
1497 else UNREACHABLE();
1498 }
1499
1500 if (fragmentShader->mUsesFragCoord)
1501 {
1502 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1503 if (sm3) {
1504 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1505 }
1506 }
1507
1508 if (fragmentShader->mUsesPointCoord && sm3)
1509 {
1510 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1511 }
1512
1513 if (fragmentShader->mUsesFrontFacing)
1514 {
1515 pixelHLSL += " float vFace : VFACE;\n";
1516 }
1517
1518 pixelHLSL += "};\n"
1519 "\n"
1520 "struct PS_OUTPUT\n"
1521 "{\n"
1522 " float4 gl_Color[1] : COLOR;\n"
1523 "};\n"
1524 "\n"
1525 "PS_OUTPUT main(PS_INPUT input)\n"
1526 "{\n";
1527
1528 if (fragmentShader->mUsesFragCoord)
1529 {
1530 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1531
1532 if (sm3)
1533 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001534 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001535 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001536 }
1537 else
1538 {
1539 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1540 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001541 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001542 }
1543
1544 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1545 " gl_FragCoord.w = rhw;\n";
1546 }
1547
1548 if (fragmentShader->mUsesPointCoord && sm3)
1549 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001550 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1551 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001552 }
1553
1554 if (fragmentShader->mUsesFrontFacing)
1555 {
1556 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1557 }
1558
1559 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1560 {
1561 if (varying->reg >= 0)
1562 {
1563 for (int i = 0; i < varying->size; i++)
1564 {
1565 int rows = VariableRowCount(varying->type);
1566 for (int j = 0; j < rows; j++)
1567 {
1568 std::string n = str(varying->reg + i * rows + j);
1569 pixelHLSL += " " + varying->name;
1570
1571 if (varying->array)
1572 {
1573 pixelHLSL += "[" + str(i) + "]";
1574 }
1575
1576 if (rows > 1)
1577 {
1578 pixelHLSL += "[" + str(j) + "]";
1579 }
1580
1581 pixelHLSL += " = input.v" + n + ";\n";
1582 }
1583 }
1584 }
1585 else UNREACHABLE();
1586 }
1587
1588 pixelHLSL += "\n"
1589 " gl_main();\n"
1590 "\n"
1591 " PS_OUTPUT output;\n"
1592 " output.gl_Color[0] = gl_Color[0];\n"
1593 "\n"
1594 " return output;\n"
1595 "}\n";
1596
1597 return true;
1598}
1599
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1601{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001602 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001603
1604 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001605 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001606 if (format != GL_PROGRAM_BINARY_ANGLE)
1607 {
1608 infoLog.append("Invalid program binary format.");
1609 return false;
1610 }
1611
1612 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001613 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001614 if (version != BUILD_REVISION)
1615 {
1616 infoLog.append("Invalid program binary version.");
1617 return false;
1618 }
1619
1620 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1621 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001622 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001623 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001624 stream.read(&name);
1625 mLinkedAttribute[i].name = name;
1626 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001627 }
1628
1629 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1630 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001631 stream.read(&mSamplersPS[i].active);
1632 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633
1634 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636 mSamplersPS[i].textureType = (TextureType) textureType;
1637 }
1638
1639 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1640 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001641 stream.read(&mSamplersVS[i].active);
1642 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643
1644 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001645 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 mSamplersVS[i].textureType = (TextureType) textureType;
1647 }
1648
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001649 stream.read(&mUsedVertexSamplerRange);
1650 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651
1652 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001653 stream.read(&size);
1654 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 {
1656 infoLog.append("Invalid program binary.");
1657 return false;
1658 }
1659
1660 mUniforms.resize(size);
1661 for (unsigned int i = 0; i < size; ++i)
1662 {
1663 GLenum type;
1664 std::string _name;
1665 unsigned int arraySize;
1666
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&type);
1668 stream.read(&_name);
1669 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001670
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001671 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&mUniforms[i]->ps.float4Index);
1674 stream.read(&mUniforms[i]->ps.samplerIndex);
1675 stream.read(&mUniforms[i]->ps.boolIndex);
1676 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001677
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 stream.read(&mUniforms[i]->vs.float4Index);
1679 stream.read(&mUniforms[i]->vs.samplerIndex);
1680 stream.read(&mUniforms[i]->vs.boolIndex);
1681 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682 }
1683
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001684 stream.read(&size);
1685 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001686 {
1687 infoLog.append("Invalid program binary.");
1688 return false;
1689 }
1690
1691 mUniformIndex.resize(size);
1692 for (unsigned int i = 0; i < size; ++i)
1693 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001694 stream.read(&mUniformIndex[i].name);
1695 stream.read(&mUniformIndex[i].element);
1696 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001697 }
1698
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001699 stream.read(&mDxDepthRangeLocation);
1700 stream.read(&mDxDepthLocation);
1701 stream.read(&mDxCoordLocation);
1702 stream.read(&mDxHalfPixelSizeLocation);
1703 stream.read(&mDxFrontCCWLocation);
1704 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705
1706 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001707 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708
1709 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001710 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001711
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001712 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001713
1714 const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
1715 ptr += sizeof(GUID);
1716
1717 D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier();
1718 if (memcmp(&currentIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0)
1719 {
1720 infoLog.append("Invalid program binary.");
1721 return false;
1722 }
1723
1724 const char *pixelShaderFunction = ptr;
1725 ptr += pixelShaderSize;
1726
1727 const char *vertexShaderFunction = ptr;
1728 ptr += vertexShaderSize;
1729
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001730 mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
1731 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001732 {
1733 infoLog.append("Could not create pixel shader.");
1734 return false;
1735 }
1736
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001737 mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
1738 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001739 {
1740 infoLog.append("Could not create vertex shader.");
1741 mPixelExecutable->Release();
1742 mPixelExecutable = NULL;
1743 return false;
1744 }
1745
1746 return true;
1747}
1748
1749bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1750{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001751 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001753 stream.write(GL_PROGRAM_BINARY_ANGLE);
1754 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001755
1756 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1757 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001758 stream.write(mLinkedAttribute[i].type);
1759 stream.write(mLinkedAttribute[i].name);
1760 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001761 }
1762
1763 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1764 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001765 stream.write(mSamplersPS[i].active);
1766 stream.write(mSamplersPS[i].logicalTextureUnit);
1767 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001768 }
1769
1770 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1771 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001772 stream.write(mSamplersVS[i].active);
1773 stream.write(mSamplersVS[i].logicalTextureUnit);
1774 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775 }
1776
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001777 stream.write(mUsedVertexSamplerRange);
1778 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001780 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001781 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1782 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001783 stream.write(mUniforms[i]->type);
1784 stream.write(mUniforms[i]->_name);
1785 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001786
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001787 stream.write(mUniforms[i]->ps.float4Index);
1788 stream.write(mUniforms[i]->ps.samplerIndex);
1789 stream.write(mUniforms[i]->ps.boolIndex);
1790 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001792 stream.write(mUniforms[i]->vs.float4Index);
1793 stream.write(mUniforms[i]->vs.samplerIndex);
1794 stream.write(mUniforms[i]->vs.boolIndex);
1795 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796 }
1797
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001799 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1800 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001801 stream.write(mUniformIndex[i].name);
1802 stream.write(mUniformIndex[i].element);
1803 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001804 }
1805
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001806 stream.write(mDxDepthRangeLocation);
1807 stream.write(mDxDepthLocation);
1808 stream.write(mDxCoordLocation);
1809 stream.write(mDxHalfPixelSizeLocation);
1810 stream.write(mDxFrontCCWLocation);
1811 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
1813 UINT pixelShaderSize;
1814 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1815 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817
1818 UINT vertexShaderSize;
1819 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1820 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001821 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822
1823 D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier();
1824
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 GLsizei streamLength = stream.length();
1826 const void *streamData = stream.data();
1827
1828 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 if (totalLength > bufSize)
1830 {
1831 if (length)
1832 {
1833 *length = 0;
1834 }
1835
1836 return false;
1837 }
1838
1839 if (binary)
1840 {
1841 char *ptr = (char*) binary;
1842
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001843 memcpy(ptr, streamData, streamLength);
1844 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845
1846 memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID));
1847 ptr += sizeof(GUID);
1848
1849 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1850 ASSERT(SUCCEEDED(result));
1851 ptr += pixelShaderSize;
1852
1853 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1854 ASSERT(SUCCEEDED(result));
1855 ptr += vertexShaderSize;
1856
1857 ASSERT(ptr - totalLength == binary);
1858 }
1859
1860 if (length)
1861 {
1862 *length = totalLength;
1863 }
1864
1865 return true;
1866}
1867
1868GLint ProgramBinary::getLength()
1869{
1870 GLint length;
1871 if (save(NULL, INT_MAX, &length))
1872 {
1873 return length;
1874 }
1875 else
1876 {
1877 return 0;
1878 }
1879}
1880
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001881bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001882{
1883 if (!fragmentShader || !fragmentShader->isCompiled())
1884 {
1885 return false;
1886 }
1887
1888 if (!vertexShader || !vertexShader->isCompiled())
1889 {
1890 return false;
1891 }
1892
1893 std::string pixelHLSL = fragmentShader->getHLSL();
1894 std::string vertexHLSL = vertexShader->getHLSL();
1895
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001896 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001897 {
1898 return false;
1899 }
1900
1901 Context *context = getContext();
1902 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1903 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1904
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001905 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1906 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001907
1908 if (vertexBinary && pixelBinary)
1909 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001910 mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
1911 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001912 {
1913 return error(GL_OUT_OF_MEMORY, false);
1914 }
1915
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001916 mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
1917 if (!mPixelExecutable)
1918 {
1919 mVertexExecutable->Release();
1920 mVertexExecutable = NULL;
1921 return error(GL_OUT_OF_MEMORY, false);
1922 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001923
1924 vertexBinary->Release();
1925 pixelBinary->Release();
1926 vertexBinary = NULL;
1927 pixelBinary = NULL;
1928
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001929 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001930 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001931 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001932 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001933
1934 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1935 {
1936 return false;
1937 }
1938
1939 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1940 {
1941 return false;
1942 }
1943
1944 // these uniforms are searched as already-decorated because gl_ and dx_
1945 // are reserved prefixes, and do not receive additional decoration
1946 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1947 mDxDepthLocation = getUniformLocation("dx_Depth");
1948 mDxCoordLocation = getUniformLocation("dx_Coord");
1949 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1950 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1951 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1952
1953 context->markDxUniformsDirty();
1954
1955 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001956 }
1957
1958 return false;
1959}
1960
1961// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001962bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001963{
1964 unsigned int usedLocations = 0;
1965
1966 // Link attributes that have a binding location
1967 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1968 {
1969 int location = attributeBindings.getAttributeBinding(attribute->name);
1970
1971 if (location != -1) // Set by glBindAttribLocation
1972 {
1973 if (!mLinkedAttribute[location].name.empty())
1974 {
1975 // Multiple active attributes bound to the same location; not an error
1976 }
1977
1978 mLinkedAttribute[location] = *attribute;
1979
1980 int rows = VariableRowCount(attribute->type);
1981
1982 if (rows + location > MAX_VERTEX_ATTRIBS)
1983 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001984 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 +00001985
1986 return false;
1987 }
1988
1989 for (int i = 0; i < rows; i++)
1990 {
1991 usedLocations |= 1 << (location + i);
1992 }
1993 }
1994 }
1995
1996 // Link attributes that don't have a binding location
1997 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1998 {
1999 int location = attributeBindings.getAttributeBinding(attribute->name);
2000
2001 if (location == -1) // Not set by glBindAttribLocation
2002 {
2003 int rows = VariableRowCount(attribute->type);
2004 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2005
2006 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2007 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002008 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002009
2010 return false; // Fail to link
2011 }
2012
2013 mLinkedAttribute[availableIndex] = *attribute;
2014 }
2015 }
2016
2017 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2018 {
2019 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2020 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2021
2022 for (int r = 0; r < rows; r++)
2023 {
2024 mSemanticIndex[attributeIndex++] = index++;
2025 }
2026 }
2027
2028 return true;
2029}
2030
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002031bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002032{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002033 for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002034 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002035 const D3DConstant *constant = constantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002036
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002037 if (!defineUniform(infoLog, shader, constant))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002038 {
2039 return false;
2040 }
2041 }
2042
2043 return true;
2044}
2045
2046// Adds the description of a constant found in the binary shader to the list of uniforms
2047// Returns true if succesful (uniform not already defined)
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002048bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002049{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002050 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002051 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002052 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002053 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002054 const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str());
2055 const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002056
2057 if (psConstant)
2058 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002059 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002060
2061 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2062 {
2063 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002064 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002065 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2066 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2067 }
2068 else
2069 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002070 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071 return false;
2072 }
2073 }
2074
2075 if (vsConstant)
2076 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002077 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002078
2079 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2080 {
2081 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002082 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002083 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2084 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2085 }
2086 else
2087 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002088 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002089 return false;
2090 }
2091 }
2092 }
2093 }
2094
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002095 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002096 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002097 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002098 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002099 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002100 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002101 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002102 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002103 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002105 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002106
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002107 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + "."))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002108 {
2109 return false;
2110 }
2111 }
2112 }
2113
2114 return true;
2115 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002116 case D3DConstant::CLASS_SCALAR:
2117 case D3DConstant::CLASS_VECTOR:
2118 case D3DConstant::CLASS_MATRIX_COLUMNS:
2119 case D3DConstant::CLASS_OBJECT:
2120 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121 default:
2122 UNREACHABLE();
2123 return false;
2124 }
2125}
2126
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002127bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002128{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002129 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002130
2131 if(!uniform)
2132 {
2133 return false;
2134 }
2135
2136 // Check if already defined
2137 GLint location = getUniformLocation(uniform->name);
2138 GLenum type = uniform->type;
2139
2140 if (location >= 0)
2141 {
2142 delete uniform;
2143 uniform = mUniforms[mUniformIndex[location].index];
2144 }
2145
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002146 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2147 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002148
2149 if (location >= 0)
2150 {
2151 return uniform->type == type;
2152 }
2153
2154 mUniforms.push_back(uniform);
2155 unsigned int uniformIndex = mUniforms.size() - 1;
2156
2157 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2158 {
2159 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2160 }
2161
2162 return true;
2163}
2164
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002165Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002166{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002167 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002168 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002169 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002170 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002171 case D3DConstant::PT_SAMPLER2D:
2172 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002173 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002174 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002175 default: UNREACHABLE();
2176 }
2177 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002178 case D3DConstant::PT_SAMPLERCUBE:
2179 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002180 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002181 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002182 default: UNREACHABLE();
2183 }
2184 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002185 case D3DConstant::PT_BOOL:
2186 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002187 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002188 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2189 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2190 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2191 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002192 default: UNREACHABLE();
2193 }
2194 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002195 case D3DConstant::PT_INT:
2196 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002197 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002198 case 1: return new Uniform(GL_INT, _name, constant->elements);
2199 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2200 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2201 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002202 default: UNREACHABLE();
2203 }
2204 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002205 case D3DConstant::PT_FLOAT:
2206 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002207 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002208 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2209 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2210 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2211 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002212 default: UNREACHABLE();
2213 }
2214 break;
2215 default:
2216 UNREACHABLE();
2217 }
2218 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002219 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002220 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002221 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002222 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002223 case D3DConstant::PT_FLOAT:
2224 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002225 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002226 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2227 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2228 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002229 default: UNREACHABLE();
2230 }
2231 break;
2232 default: UNREACHABLE();
2233 }
2234 }
2235 else UNREACHABLE();
2236
2237 return 0;
2238}
2239
2240// This method needs to match OutputHLSL::decorate
2241std::string ProgramBinary::decorateAttribute(const std::string &name)
2242{
2243 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2244 {
2245 return "_" + name;
2246 }
2247
2248 return name;
2249}
2250
2251std::string ProgramBinary::undecorateUniform(const std::string &_name)
2252{
2253 std::string name = _name;
2254
2255 // Remove any structure field decoration
2256 size_t pos = 0;
2257 while ((pos = name.find("._", pos)) != std::string::npos)
2258 {
2259 name.replace(pos, 2, ".");
2260 }
2261
2262 // Remove the leading decoration
2263 if (name[0] == '_')
2264 {
2265 return name.substr(1);
2266 }
2267 else if (name.compare(0, 3, "ar_") == 0)
2268 {
2269 return name.substr(3);
2270 }
2271
2272 return name;
2273}
2274
2275void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2276{
2277 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2278 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2279
2280 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2281 {
2282 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2283 for (int i = 0; i < count; i++)
2284 {
2285 for (int j = 0; j < 4; j++)
2286 {
2287 if (j < width)
2288 {
2289 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2290 }
2291 else
2292 {
2293 vector[i * 4 + j] = 0.0f;
2294 }
2295 }
2296 }
2297 }
2298
2299 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2300 {
2301 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2302 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2303 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2304 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2305 for (int i = 0; i < copyCount; i++)
2306 {
2307 boolVector[i] = v[i] != GL_FALSE;
2308 }
2309 }
2310
2311 if (targetUniform->ps.float4Index >= 0)
2312 {
2313 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2314 }
2315
2316 if (targetUniform->ps.boolIndex >= 0)
2317 {
2318 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2319 }
2320
2321 if (targetUniform->vs.float4Index >= 0)
2322 {
2323 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2324 }
2325
2326 if (targetUniform->vs.boolIndex >= 0)
2327 {
2328 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2329 }
2330}
2331
2332bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2333{
2334 if (targetUniform->ps.registerCount)
2335 {
2336 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2337 }
2338
2339 if (targetUniform->vs.registerCount)
2340 {
2341 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2342 }
2343
2344 return true;
2345}
2346
2347bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2348{
2349 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002350 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002351
2352 for (int i = 0; i < count; i++)
2353 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002354 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002355 }
2356
2357 if (targetUniform->ps.registerCount)
2358 {
2359 if (targetUniform->ps.samplerIndex >= 0)
2360 {
2361 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2362
2363 for (int i = 0; i < count; i++)
2364 {
2365 unsigned int samplerIndex = firstIndex + i;
2366
2367 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2368 {
2369 ASSERT(mSamplersPS[samplerIndex].active);
2370 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2371 }
2372 }
2373 }
2374 else
2375 {
2376 ASSERT(targetUniform->ps.float4Index >= 0);
2377 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2378 }
2379 }
2380
2381 if (targetUniform->vs.registerCount)
2382 {
2383 if (targetUniform->vs.samplerIndex >= 0)
2384 {
2385 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2386
2387 for (int i = 0; i < count; i++)
2388 {
2389 unsigned int samplerIndex = firstIndex + i;
2390
2391 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2392 {
2393 ASSERT(mSamplersVS[samplerIndex].active);
2394 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2395 }
2396 }
2397 }
2398 else
2399 {
2400 ASSERT(targetUniform->vs.float4Index >= 0);
2401 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2402 }
2403 }
2404
2405 return true;
2406}
2407
2408bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2409{
2410 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002411 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002412
2413 for (int i = 0; i < count; i++)
2414 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002415 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002416
2417 v += 2;
2418 }
2419
2420 applyUniformniv(targetUniform, count, vector);
2421
2422 return true;
2423}
2424
2425bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2426{
2427 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002428 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002429
2430 for (int i = 0; i < count; i++)
2431 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002432 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002433
2434 v += 3;
2435 }
2436
2437 applyUniformniv(targetUniform, count, vector);
2438
2439 return true;
2440}
2441
2442bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2443{
2444 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002445 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002446
2447 for (int i = 0; i < count; i++)
2448 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002449 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002450
2451 v += 4;
2452 }
2453
2454 applyUniformniv(targetUniform, count, vector);
2455
2456 return true;
2457}
2458
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002459void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002460{
2461 if (targetUniform->ps.registerCount)
2462 {
2463 ASSERT(targetUniform->ps.float4Index >= 0);
2464 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2465 }
2466
2467 if (targetUniform->vs.registerCount)
2468 {
2469 ASSERT(targetUniform->vs.float4Index >= 0);
2470 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2471 }
2472}
2473
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002474bool ProgramBinary::isValidated() const
2475{
2476 return mValidated;
2477}
2478
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002479void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2480{
2481 // Skip over inactive attributes
2482 unsigned int activeAttribute = 0;
2483 unsigned int attribute;
2484 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2485 {
2486 if (mLinkedAttribute[attribute].name.empty())
2487 {
2488 continue;
2489 }
2490
2491 if (activeAttribute == index)
2492 {
2493 break;
2494 }
2495
2496 activeAttribute++;
2497 }
2498
2499 if (bufsize > 0)
2500 {
2501 const char *string = mLinkedAttribute[attribute].name.c_str();
2502
2503 strncpy(name, string, bufsize);
2504 name[bufsize - 1] = '\0';
2505
2506 if (length)
2507 {
2508 *length = strlen(name);
2509 }
2510 }
2511
2512 *size = 1; // Always a single 'type' instance
2513
2514 *type = mLinkedAttribute[attribute].type;
2515}
2516
2517GLint ProgramBinary::getActiveAttributeCount()
2518{
2519 int count = 0;
2520
2521 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2522 {
2523 if (!mLinkedAttribute[attributeIndex].name.empty())
2524 {
2525 count++;
2526 }
2527 }
2528
2529 return count;
2530}
2531
2532GLint ProgramBinary::getActiveAttributeMaxLength()
2533{
2534 int maxLength = 0;
2535
2536 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2537 {
2538 if (!mLinkedAttribute[attributeIndex].name.empty())
2539 {
2540 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2541 }
2542 }
2543
2544 return maxLength;
2545}
2546
2547void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2548{
2549 // Skip over internal uniforms
2550 unsigned int activeUniform = 0;
2551 unsigned int uniform;
2552 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2553 {
2554 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2555 {
2556 continue;
2557 }
2558
2559 if (activeUniform == index)
2560 {
2561 break;
2562 }
2563
2564 activeUniform++;
2565 }
2566
2567 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2568
2569 if (bufsize > 0)
2570 {
2571 std::string string = mUniforms[uniform]->name;
2572
2573 if (mUniforms[uniform]->isArray())
2574 {
2575 string += "[0]";
2576 }
2577
2578 strncpy(name, string.c_str(), bufsize);
2579 name[bufsize - 1] = '\0';
2580
2581 if (length)
2582 {
2583 *length = strlen(name);
2584 }
2585 }
2586
2587 *size = mUniforms[uniform]->arraySize;
2588
2589 *type = mUniforms[uniform]->type;
2590}
2591
2592GLint ProgramBinary::getActiveUniformCount()
2593{
2594 int count = 0;
2595
2596 unsigned int numUniforms = mUniforms.size();
2597 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2598 {
2599 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2600 {
2601 count++;
2602 }
2603 }
2604
2605 return count;
2606}
2607
2608GLint ProgramBinary::getActiveUniformMaxLength()
2609{
2610 int maxLength = 0;
2611
2612 unsigned int numUniforms = mUniforms.size();
2613 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2614 {
2615 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2616 {
2617 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2618 if (mUniforms[uniformIndex]->isArray())
2619 {
2620 length += 3; // Counting in "[0]".
2621 }
2622 maxLength = std::max(length, maxLength);
2623 }
2624 }
2625
2626 return maxLength;
2627}
2628
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002629void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002630{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002631 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002632 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002633 {
2634 mValidated = false;
2635 }
2636 else
2637 {
2638 mValidated = true;
2639 }
2640}
2641
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002642bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002643{
2644 // if any two active samplers in a program are of different types, but refer to the same
2645 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2646 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2647
2648 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2649 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2650
2651 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2652 {
2653 textureUnitType[i] = TEXTURE_UNKNOWN;
2654 }
2655
2656 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2657 {
2658 if (mSamplersPS[i].active)
2659 {
2660 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2661
2662 if (unit >= maxCombinedTextureImageUnits)
2663 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002664 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002665 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002666 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002667 }
2668
2669 return false;
2670 }
2671
2672 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2673 {
2674 if (mSamplersPS[i].textureType != textureUnitType[unit])
2675 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002676 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002677 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002678 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002679 }
2680
2681 return false;
2682 }
2683 }
2684 else
2685 {
2686 textureUnitType[unit] = mSamplersPS[i].textureType;
2687 }
2688 }
2689 }
2690
2691 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2692 {
2693 if (mSamplersVS[i].active)
2694 {
2695 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2696
2697 if (unit >= maxCombinedTextureImageUnits)
2698 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002699 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002700 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002701 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002702 }
2703
2704 return false;
2705 }
2706
2707 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2708 {
2709 if (mSamplersVS[i].textureType != textureUnitType[unit])
2710 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002711 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002712 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002713 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002714 }
2715
2716 return false;
2717 }
2718 }
2719 else
2720 {
2721 textureUnitType[unit] = mSamplersVS[i].textureType;
2722 }
2723 }
2724 }
2725
2726 return true;
2727}
2728
2729GLint ProgramBinary::getDxDepthRangeLocation() const
2730{
2731 return mDxDepthRangeLocation;
2732}
2733
2734GLint ProgramBinary::getDxDepthLocation() const
2735{
2736 return mDxDepthLocation;
2737}
2738
2739GLint ProgramBinary::getDxCoordLocation() const
2740{
2741 return mDxCoordLocation;
2742}
2743
2744GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2745{
2746 return mDxHalfPixelSizeLocation;
2747}
2748
2749GLint ProgramBinary::getDxFrontCCWLocation() const
2750{
2751 return mDxFrontCCWLocation;
2752}
2753
2754GLint ProgramBinary::getDxPointsOrLinesLocation() const
2755{
2756 return mDxPointsOrLinesLocation;
2757}
2758
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002759ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2760{
2761}
2762
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002763}