blob: 9c70caec1e5fb8134c327cad4176bfd503ff5b1a [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
2// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/Program.h"
12#include "libGLESv2/ProgramBinary.h"
13
14#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000015#include "common/version.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/Shader.h"
19#include "libGLESv2/utilities.h"
20
21#include <string>
22
23#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
24#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
25#endif
26
27namespace gl
28{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029std::string str(int i)
30{
31 char buffer[20];
32 snprintf(buffer, sizeof(buffer), "%d", i);
33 return buffer;
34}
35
36Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)
37 : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize)
38{
39 int bytes = UniformInternalSize(type) * arraySize;
40 data = new unsigned char[bytes];
41 memset(data, 0, bytes);
42 dirty = true;
43}
44
45Uniform::~Uniform()
46{
47 delete[] data;
48}
49
50bool Uniform::isArray()
51{
52 return _name.compare(0, 3, "ar_") == 0;
53}
54
55UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index)
56 : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index)
57{
58}
59
daniel@transgaming.come87ca002012-07-24 18:30:43 +000060unsigned int ProgramBinary::mCurrentSerial = 1;
61
daniel@transgaming.com989c1c82012-07-24 18:40:38 +000062ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000063{
64 mDevice = getDevice();
65
66 mPixelExecutable = NULL;
67 mVertexExecutable = NULL;
68 mConstantTablePS = NULL;
69 mConstantTableVS = NULL;
70
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000071 mValidated = false;
72
73 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
74 {
75 mSemanticIndex[index] = -1;
76 }
77
78 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
79 {
80 mSamplersPS[index].active = false;
81 }
82
83 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
84 {
85 mSamplersVS[index].active = false;
86 }
87
88 mUsedVertexSamplerRange = 0;
89 mUsedPixelSamplerRange = 0;
90
91 mDxDepthRangeLocation = -1;
92 mDxDepthLocation = -1;
93 mDxCoordLocation = -1;
94 mDxHalfPixelSizeLocation = -1;
95 mDxFrontCCWLocation = -1;
96 mDxPointsOrLinesLocation = -1;
97}
98
99ProgramBinary::~ProgramBinary()
100{
101 if (mPixelExecutable)
102 {
103 mPixelExecutable->Release();
104 }
105
106 if (mVertexExecutable)
107 {
108 mVertexExecutable->Release();
109 }
110
apatrick@chromium.org60dafe82012-09-05 22:26:10 +0000111 delete mConstantTablePS;
112 delete mConstantTableVS;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000113
114 while (!mUniforms.empty())
115 {
116 delete mUniforms.back();
117 mUniforms.pop_back();
118 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000119}
120
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000121unsigned int ProgramBinary::getSerial() const
122{
123 return mSerial;
124}
125
126unsigned int ProgramBinary::issueSerial()
127{
128 return mCurrentSerial++;
129}
130
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000131IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
132{
133 return mPixelExecutable;
134}
135
136IDirect3DVertexShader9 *ProgramBinary::getVertexShader()
137{
138 return mVertexExecutable;
139}
140
141GLuint ProgramBinary::getAttributeLocation(const char *name)
142{
143 if (name)
144 {
145 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
146 {
147 if (mLinkedAttribute[index].name == std::string(name))
148 {
149 return index;
150 }
151 }
152 }
153
154 return -1;
155}
156
157int ProgramBinary::getSemanticIndex(int attributeIndex)
158{
159 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
160
161 return mSemanticIndex[attributeIndex];
162}
163
164// Returns one more than the highest sampler index used.
165GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
166{
167 switch (type)
168 {
169 case SAMPLER_PIXEL:
170 return mUsedPixelSamplerRange;
171 case SAMPLER_VERTEX:
172 return mUsedVertexSamplerRange;
173 default:
174 UNREACHABLE();
175 return 0;
176 }
177}
178
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000179bool ProgramBinary::usesPointSize() const
180{
181 return mUsesPointSize;
182}
183
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000184// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
185// index (0-15 for the pixel shader and 0-3 for the vertex shader).
186GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
187{
188 GLint logicalTextureUnit = -1;
189
190 switch (type)
191 {
192 case SAMPLER_PIXEL:
193 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
194
195 if (mSamplersPS[samplerIndex].active)
196 {
197 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
198 }
199 break;
200 case SAMPLER_VERTEX:
201 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
202
203 if (mSamplersVS[samplerIndex].active)
204 {
205 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
206 }
207 break;
208 default: UNREACHABLE();
209 }
210
211 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
212 {
213 return logicalTextureUnit;
214 }
215
216 return -1;
217}
218
219// Returns the texture type for a given Direct3D 9 sampler type and
220// index (0-15 for the pixel shader and 0-3 for the vertex shader).
221TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
222{
223 switch (type)
224 {
225 case SAMPLER_PIXEL:
226 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
227 ASSERT(mSamplersPS[samplerIndex].active);
228 return mSamplersPS[samplerIndex].textureType;
229 case SAMPLER_VERTEX:
230 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
231 ASSERT(mSamplersVS[samplerIndex].active);
232 return mSamplersVS[samplerIndex].textureType;
233 default: UNREACHABLE();
234 }
235
236 return TEXTURE_2D;
237}
238
239GLint ProgramBinary::getUniformLocation(std::string name)
240{
241 unsigned int subscript = 0;
242
243 // Strip any trailing array operator and retrieve the subscript
244 size_t open = name.find_last_of('[');
245 size_t close = name.find_last_of(']');
246 if (open != std::string::npos && close == name.length() - 1)
247 {
248 subscript = atoi(name.substr(open + 1).c_str());
249 name.erase(open);
250 }
251
252 unsigned int numUniforms = mUniformIndex.size();
253 for (unsigned int location = 0; location < numUniforms; location++)
254 {
255 if (mUniformIndex[location].name == name &&
256 mUniformIndex[location].element == subscript)
257 {
258 return location;
259 }
260 }
261
262 return -1;
263}
264
265bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
266{
267 if (location < 0 || location >= (int)mUniformIndex.size())
268 {
269 return false;
270 }
271
272 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
273 targetUniform->dirty = true;
274
275 if (targetUniform->type == GL_FLOAT)
276 {
277 int arraySize = targetUniform->arraySize;
278
279 if (arraySize == 1 && count > 1)
280 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
281
282 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
283
284 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
285
286 for (int i = 0; i < count; i++)
287 {
288 target[0] = v[0];
289 target[1] = 0;
290 target[2] = 0;
291 target[3] = 0;
292 target += 4;
293 v += 1;
294 }
295 }
296 else if (targetUniform->type == GL_BOOL)
297 {
298 int arraySize = targetUniform->arraySize;
299
300 if (arraySize == 1 && count > 1)
301 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
302
303 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
304 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
305
306 for (int i = 0; i < count; ++i)
307 {
308 if (v[i] == 0.0f)
309 {
310 boolParams[i] = GL_FALSE;
311 }
312 else
313 {
314 boolParams[i] = GL_TRUE;
315 }
316 }
317 }
318 else
319 {
320 return false;
321 }
322
323 return true;
324}
325
326bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
327{
328 if (location < 0 || location >= (int)mUniformIndex.size())
329 {
330 return false;
331 }
332
333 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
334 targetUniform->dirty = true;
335
336 if (targetUniform->type == GL_FLOAT_VEC2)
337 {
338 int arraySize = targetUniform->arraySize;
339
340 if (arraySize == 1 && count > 1)
341 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
342
343 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
344
345 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
346
347 for (int i = 0; i < count; i++)
348 {
349 target[0] = v[0];
350 target[1] = v[1];
351 target[2] = 0;
352 target[3] = 0;
353 target += 4;
354 v += 2;
355 }
356 }
357 else if (targetUniform->type == GL_BOOL_VEC2)
358 {
359 int arraySize = targetUniform->arraySize;
360
361 if (arraySize == 1 && count > 1)
362 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
363
364 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
365
366 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
367
368 for (int i = 0; i < count * 2; ++i)
369 {
370 if (v[i] == 0.0f)
371 {
372 boolParams[i] = GL_FALSE;
373 }
374 else
375 {
376 boolParams[i] = GL_TRUE;
377 }
378 }
379 }
380 else
381 {
382 return false;
383 }
384
385 return true;
386}
387
388bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
389{
390 if (location < 0 || location >= (int)mUniformIndex.size())
391 {
392 return false;
393 }
394
395 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
396 targetUniform->dirty = true;
397
398 if (targetUniform->type == GL_FLOAT_VEC3)
399 {
400 int arraySize = targetUniform->arraySize;
401
402 if (arraySize == 1 && count > 1)
403 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
404
405 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
406
407 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
408
409 for (int i = 0; i < count; i++)
410 {
411 target[0] = v[0];
412 target[1] = v[1];
413 target[2] = v[2];
414 target[3] = 0;
415 target += 4;
416 v += 3;
417 }
418 }
419 else if (targetUniform->type == GL_BOOL_VEC3)
420 {
421 int arraySize = targetUniform->arraySize;
422
423 if (arraySize == 1 && count > 1)
424 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
425
426 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
427 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
428
429 for (int i = 0; i < count * 3; ++i)
430 {
431 if (v[i] == 0.0f)
432 {
433 boolParams[i] = GL_FALSE;
434 }
435 else
436 {
437 boolParams[i] = GL_TRUE;
438 }
439 }
440 }
441 else
442 {
443 return false;
444 }
445
446 return true;
447}
448
449bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
450{
451 if (location < 0 || location >= (int)mUniformIndex.size())
452 {
453 return false;
454 }
455
456 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
457 targetUniform->dirty = true;
458
459 if (targetUniform->type == GL_FLOAT_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
468 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
469 v, 4 * sizeof(GLfloat) * count);
470 }
471 else if (targetUniform->type == GL_BOOL_VEC4)
472 {
473 int arraySize = targetUniform->arraySize;
474
475 if (arraySize == 1 && count > 1)
476 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
477
478 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
479 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
480
481 for (int i = 0; i < count * 4; ++i)
482 {
483 if (v[i] == 0.0f)
484 {
485 boolParams[i] = GL_FALSE;
486 }
487 else
488 {
489 boolParams[i] = GL_TRUE;
490 }
491 }
492 }
493 else
494 {
495 return false;
496 }
497
498 return true;
499}
500
501template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
502void transposeMatrix(T *target, const GLfloat *value)
503{
504 int copyWidth = std::min(targetWidth, srcWidth);
505 int copyHeight = std::min(targetHeight, srcHeight);
506
507 for (int x = 0; x < copyWidth; x++)
508 {
509 for (int y = 0; y < copyHeight; y++)
510 {
511 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
512 }
513 }
514 // clear unfilled right side
515 for (int y = 0; y < copyHeight; y++)
516 {
517 for (int x = srcWidth; x < targetWidth; x++)
518 {
519 target[y * targetWidth + x] = (T)0;
520 }
521 }
522 // clear unfilled bottom.
523 for (int y = srcHeight; y < targetHeight; y++)
524 {
525 for (int x = 0; x < targetWidth; x++)
526 {
527 target[y * targetWidth + x] = (T)0;
528 }
529 }
530}
531
532bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
533{
534 if (location < 0 || location >= (int)mUniformIndex.size())
535 {
536 return false;
537 }
538
539 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
540 targetUniform->dirty = true;
541
542 if (targetUniform->type != GL_FLOAT_MAT2)
543 {
544 return false;
545 }
546
547 int arraySize = targetUniform->arraySize;
548
549 if (arraySize == 1 && count > 1)
550 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
551
552 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
553
554 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
555 for (int i = 0; i < count; i++)
556 {
557 transposeMatrix<GLfloat,4,2,2,2>(target, value);
558 target += 8;
559 value += 4;
560 }
561
562 return true;
563}
564
565bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
566{
567 if (location < 0 || location >= (int)mUniformIndex.size())
568 {
569 return false;
570 }
571
572 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
573 targetUniform->dirty = true;
574
575 if (targetUniform->type != GL_FLOAT_MAT3)
576 {
577 return false;
578 }
579
580 int arraySize = targetUniform->arraySize;
581
582 if (arraySize == 1 && count > 1)
583 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
584
585 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
586
587 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
588 for (int i = 0; i < count; i++)
589 {
590 transposeMatrix<GLfloat,4,3,3,3>(target, value);
591 target += 12;
592 value += 9;
593 }
594
595 return true;
596}
597
598
599bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
600{
601 if (location < 0 || location >= (int)mUniformIndex.size())
602 {
603 return false;
604 }
605
606 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
607 targetUniform->dirty = true;
608
609 if (targetUniform->type != GL_FLOAT_MAT4)
610 {
611 return false;
612 }
613
614 int arraySize = targetUniform->arraySize;
615
616 if (arraySize == 1 && count > 1)
617 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
618
619 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
620
621 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
622 for (int i = 0; i < count; i++)
623 {
624 transposeMatrix<GLfloat,4,4,4,4>(target, value);
625 target += 16;
626 value += 16;
627 }
628
629 return true;
630}
631
632bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
633{
634 if (location < 0 || location >= (int)mUniformIndex.size())
635 {
636 return false;
637 }
638
639 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
640 targetUniform->dirty = true;
641
642 if (targetUniform->type == GL_INT ||
643 targetUniform->type == GL_SAMPLER_2D ||
644 targetUniform->type == GL_SAMPLER_CUBE)
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
653 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
654 v, sizeof(GLint) * count);
655 }
656 else if (targetUniform->type == GL_BOOL)
657 {
658 int arraySize = targetUniform->arraySize;
659
660 if (arraySize == 1 && count > 1)
661 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
662
663 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
664 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
665
666 for (int i = 0; i < count; ++i)
667 {
668 if (v[i] == 0)
669 {
670 boolParams[i] = GL_FALSE;
671 }
672 else
673 {
674 boolParams[i] = GL_TRUE;
675 }
676 }
677 }
678 else
679 {
680 return false;
681 }
682
683 return true;
684}
685
686bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
687{
688 if (location < 0 || location >= (int)mUniformIndex.size())
689 {
690 return false;
691 }
692
693 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
694 targetUniform->dirty = true;
695
696 if (targetUniform->type == GL_INT_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
705 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
706 v, 2 * sizeof(GLint) * count);
707 }
708 else if (targetUniform->type == GL_BOOL_VEC2)
709 {
710 int arraySize = targetUniform->arraySize;
711
712 if (arraySize == 1 && count > 1)
713 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
714
715 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
716 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
717
718 for (int i = 0; i < count * 2; ++i)
719 {
720 if (v[i] == 0)
721 {
722 boolParams[i] = GL_FALSE;
723 }
724 else
725 {
726 boolParams[i] = GL_TRUE;
727 }
728 }
729 }
730 else
731 {
732 return false;
733 }
734
735 return true;
736}
737
738bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
739{
740 if (location < 0 || location >= (int)mUniformIndex.size())
741 {
742 return false;
743 }
744
745 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
746 targetUniform->dirty = true;
747
748 if (targetUniform->type == GL_INT_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
757 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
758 v, 3 * sizeof(GLint) * count);
759 }
760 else if (targetUniform->type == GL_BOOL_VEC3)
761 {
762 int arraySize = targetUniform->arraySize;
763
764 if (arraySize == 1 && count > 1)
765 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
766
767 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
768 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
769
770 for (int i = 0; i < count * 3; ++i)
771 {
772 if (v[i] == 0)
773 {
774 boolParams[i] = GL_FALSE;
775 }
776 else
777 {
778 boolParams[i] = GL_TRUE;
779 }
780 }
781 }
782 else
783 {
784 return false;
785 }
786
787 return true;
788}
789
790bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
791{
792 if (location < 0 || location >= (int)mUniformIndex.size())
793 {
794 return false;
795 }
796
797 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
798 targetUniform->dirty = true;
799
800 if (targetUniform->type == GL_INT_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
809 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
810 v, 4 * sizeof(GLint) * count);
811 }
812 else if (targetUniform->type == GL_BOOL_VEC4)
813 {
814 int arraySize = targetUniform->arraySize;
815
816 if (arraySize == 1 && count > 1)
817 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
818
819 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
820 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
821
822 for (int i = 0; i < count * 4; ++i)
823 {
824 if (v[i] == 0)
825 {
826 boolParams[i] = GL_FALSE;
827 }
828 else
829 {
830 boolParams[i] = GL_TRUE;
831 }
832 }
833 }
834 else
835 {
836 return false;
837 }
838
839 return true;
840}
841
842bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
843{
844 if (location < 0 || location >= (int)mUniformIndex.size())
845 {
846 return false;
847 }
848
849 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
850
851 // sized queries -- ensure the provided buffer is large enough
852 if (bufSize)
853 {
854 int requiredBytes = UniformExternalSize(targetUniform->type);
855 if (*bufSize < requiredBytes)
856 {
857 return false;
858 }
859 }
860
861 switch (targetUniform->type)
862 {
863 case GL_FLOAT_MAT2:
864 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
865 break;
866 case GL_FLOAT_MAT3:
867 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
868 break;
869 case GL_FLOAT_MAT4:
870 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
871 break;
872 default:
873 {
874 unsigned int count = UniformExternalComponentCount(targetUniform->type);
875 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
876
877 switch (UniformComponentType(targetUniform->type))
878 {
879 case GL_BOOL:
880 {
881 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
882
883 for (unsigned int i = 0; i < count; ++i)
884 {
885 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
886 }
887 }
888 break;
889 case GL_FLOAT:
890 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
891 count * sizeof(GLfloat));
892 break;
893 case GL_INT:
894 {
895 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
896
897 for (unsigned int i = 0; i < count; ++i)
898 {
899 params[i] = (float)intParams[i];
900 }
901 }
902 break;
903 default: UNREACHABLE();
904 }
905 }
906 }
907
908 return true;
909}
910
911bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
912{
913 if (location < 0 || location >= (int)mUniformIndex.size())
914 {
915 return false;
916 }
917
918 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
919
920 // sized queries -- ensure the provided buffer is large enough
921 if (bufSize)
922 {
923 int requiredBytes = UniformExternalSize(targetUniform->type);
924 if (*bufSize < requiredBytes)
925 {
926 return false;
927 }
928 }
929
930 switch (targetUniform->type)
931 {
932 case GL_FLOAT_MAT2:
933 {
934 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
935 }
936 break;
937 case GL_FLOAT_MAT3:
938 {
939 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
940 }
941 break;
942 case GL_FLOAT_MAT4:
943 {
944 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
945 }
946 break;
947 default:
948 {
949 unsigned int count = UniformExternalComponentCount(targetUniform->type);
950 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
951
952 switch (UniformComponentType(targetUniform->type))
953 {
954 case GL_BOOL:
955 {
956 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
957
958 for (unsigned int i = 0; i < count; ++i)
959 {
960 params[i] = (GLint)boolParams[i];
961 }
962 }
963 break;
964 case GL_FLOAT:
965 {
966 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
967
968 for (unsigned int i = 0; i < count; ++i)
969 {
970 params[i] = (GLint)floatParams[i];
971 }
972 }
973 break;
974 case GL_INT:
975 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
976 count * sizeof(GLint));
977 break;
978 default: UNREACHABLE();
979 }
980 }
981 }
982
983 return true;
984}
985
986void ProgramBinary::dirtyAllUniforms()
987{
988 unsigned int numUniforms = mUniforms.size();
989 for (unsigned int index = 0; index < numUniforms; index++)
990 {
991 mUniforms[index]->dirty = true;
992 }
993}
994
995// Applies all the uniforms set for this program object to the Direct3D 9 device
996void ProgramBinary::applyUniforms()
997{
998 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
999 Uniform *targetUniform = *ub;
1000
1001 if (targetUniform->dirty)
1002 {
1003 int arraySize = targetUniform->arraySize;
1004 GLfloat *f = (GLfloat*)targetUniform->data;
1005 GLint *i = (GLint*)targetUniform->data;
1006 GLboolean *b = (GLboolean*)targetUniform->data;
1007
1008 switch (targetUniform->type)
1009 {
1010 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1011 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1012 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1013 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1014 case GL_FLOAT:
1015 case GL_FLOAT_VEC2:
1016 case GL_FLOAT_VEC3:
1017 case GL_FLOAT_VEC4:
1018 case GL_FLOAT_MAT2:
1019 case GL_FLOAT_MAT3:
1020 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1021 case GL_SAMPLER_2D:
1022 case GL_SAMPLER_CUBE:
1023 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1024 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1025 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1026 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1027 default:
1028 UNREACHABLE();
1029 }
1030
1031 targetUniform->dirty = false;
1032 }
1033 }
1034}
1035
1036// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001037ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001038{
1039 if (!hlsl)
1040 {
1041 return NULL;
1042 }
1043
1044 DWORD result;
1045 UINT flags = 0;
1046 std::string sourceText;
1047 if (perfActive())
1048 {
1049 flags |= D3DCOMPILE_DEBUG;
1050#ifdef NDEBUG
1051 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1052#else
1053 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
1054#endif
1055
1056 std::string sourcePath = getTempPath();
1057 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
1058 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
1059 }
1060 else
1061 {
1062 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1063 sourceText = hlsl;
1064 }
1065
1066 ID3D10Blob *binary = NULL;
1067 ID3D10Blob *errorMessage = NULL;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001068 result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001069
1070 if (errorMessage)
1071 {
1072 const char *message = (const char*)errorMessage->GetBufferPointer();
1073
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001074 infoLog.appendSanitized(message);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001075 TRACE("\n%s", hlsl);
1076 TRACE("\n%s", message);
1077
1078 errorMessage->Release();
1079 errorMessage = NULL;
1080 }
1081
1082 if (FAILED(result))
1083 {
1084 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1085 {
1086 error(GL_OUT_OF_MEMORY);
1087 }
1088
1089 return NULL;
1090 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001091
1092 D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize());
1093 if (table->error())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001094 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001095 delete table;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001096 binary->Release();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001097 return NULL;
1098 }
1099
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001100 *constantTable = table;
1101
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001102 return binary;
1103}
1104
1105// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1106// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001107int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001108{
1109 Context *context = getContext();
1110 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1111
1112 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1113 {
1114 int n = VariableRowCount(varying->type) * varying->size;
1115 int m = VariableColumnCount(varying->type);
1116 bool success = false;
1117
1118 if (m == 2 || m == 3 || m == 4)
1119 {
1120 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1121 {
1122 bool available = true;
1123
1124 for (int y = 0; y < n && available; y++)
1125 {
1126 for (int x = 0; x < m && available; x++)
1127 {
1128 if (packing[r + y][x])
1129 {
1130 available = false;
1131 }
1132 }
1133 }
1134
1135 if (available)
1136 {
1137 varying->reg = r;
1138 varying->col = 0;
1139
1140 for (int y = 0; y < n; y++)
1141 {
1142 for (int x = 0; x < m; x++)
1143 {
1144 packing[r + y][x] = &*varying;
1145 }
1146 }
1147
1148 success = true;
1149 }
1150 }
1151
1152 if (!success && m == 2)
1153 {
1154 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1155 {
1156 bool available = true;
1157
1158 for (int y = 0; y < n && available; y++)
1159 {
1160 for (int x = 2; x < 4 && available; x++)
1161 {
1162 if (packing[r + y][x])
1163 {
1164 available = false;
1165 }
1166 }
1167 }
1168
1169 if (available)
1170 {
1171 varying->reg = r;
1172 varying->col = 2;
1173
1174 for (int y = 0; y < n; y++)
1175 {
1176 for (int x = 2; x < 4; x++)
1177 {
1178 packing[r + y][x] = &*varying;
1179 }
1180 }
1181
1182 success = true;
1183 }
1184 }
1185 }
1186 }
1187 else if (m == 1)
1188 {
1189 int space[4] = {0};
1190
1191 for (int y = 0; y < maxVaryingVectors; y++)
1192 {
1193 for (int x = 0; x < 4; x++)
1194 {
1195 space[x] += packing[y][x] ? 0 : 1;
1196 }
1197 }
1198
1199 int column = 0;
1200
1201 for (int x = 0; x < 4; x++)
1202 {
1203 if (space[x] >= n && space[x] < space[column])
1204 {
1205 column = x;
1206 }
1207 }
1208
1209 if (space[column] >= n)
1210 {
1211 for (int r = 0; r < maxVaryingVectors; r++)
1212 {
1213 if (!packing[r][column])
1214 {
1215 varying->reg = r;
1216
1217 for (int y = r; y < r + n; y++)
1218 {
1219 packing[y][column] = &*varying;
1220 }
1221
1222 break;
1223 }
1224 }
1225
1226 varying->col = column;
1227
1228 success = true;
1229 }
1230 }
1231 else UNREACHABLE();
1232
1233 if (!success)
1234 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001235 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001236
1237 return -1;
1238 }
1239 }
1240
1241 // Return the number of used registers
1242 int registers = 0;
1243
1244 for (int r = 0; r < maxVaryingVectors; r++)
1245 {
1246 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1247 {
1248 registers++;
1249 }
1250 }
1251
1252 return registers;
1253}
1254
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001255bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001256{
1257 if (pixelHLSL.empty() || vertexHLSL.empty())
1258 {
1259 return false;
1260 }
1261
1262 // Reset the varying register assignments
1263 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1264 {
1265 fragVar->reg = -1;
1266 fragVar->col = -1;
1267 }
1268
1269 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1270 {
1271 vtxVar->reg = -1;
1272 vtxVar->col = -1;
1273 }
1274
1275 // Map the varyings to the register file
1276 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001277 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278
1279 if (registers < 0)
1280 {
1281 return false;
1282 }
1283
1284 // Write the HLSL input/output declarations
1285 Context *context = getContext();
1286 const bool sm3 = context->supportsShaderModel3();
1287 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1288
1289 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1290 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001291 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001292
1293 return false;
1294 }
1295
1296 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1297 {
1298 bool matched = false;
1299
1300 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1301 {
1302 if (output->name == input->name)
1303 {
1304 if (output->type != input->type || output->size != input->size)
1305 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001306 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 +00001307
1308 return false;
1309 }
1310
1311 output->reg = input->reg;
1312 output->col = input->col;
1313
1314 matched = true;
1315 break;
1316 }
1317 }
1318
1319 if (!matched)
1320 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001321 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001322
1323 return false;
1324 }
1325 }
1326
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001327 mUsesPointSize = vertexShader->mUsesPointSize;
1328 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001329
1330 vertexHLSL += "struct VS_INPUT\n"
1331 "{\n";
1332
1333 int semanticIndex = 0;
1334 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1335 {
1336 switch (attribute->type)
1337 {
1338 case GL_FLOAT: vertexHLSL += " float "; break;
1339 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1340 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1341 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1342 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1343 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1344 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1345 default: UNREACHABLE();
1346 }
1347
1348 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1349
1350 semanticIndex += VariableRowCount(attribute->type);
1351 }
1352
1353 vertexHLSL += "};\n"
1354 "\n"
1355 "struct VS_OUTPUT\n"
1356 "{\n"
1357 " float4 gl_Position : POSITION;\n";
1358
1359 for (int r = 0; r < registers; r++)
1360 {
1361 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1362
1363 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1364 }
1365
1366 if (fragmentShader->mUsesFragCoord)
1367 {
1368 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1369 }
1370
1371 if (vertexShader->mUsesPointSize && sm3)
1372 {
1373 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1374 }
1375
1376 vertexHLSL += "};\n"
1377 "\n"
1378 "VS_OUTPUT main(VS_INPUT input)\n"
1379 "{\n";
1380
1381 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1382 {
1383 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1384
1385 if (VariableRowCount(attribute->type) > 1) // Matrix
1386 {
1387 vertexHLSL += "transpose";
1388 }
1389
1390 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1391 }
1392
1393 vertexHLSL += "\n"
1394 " gl_main();\n"
1395 "\n"
1396 " VS_OUTPUT output;\n"
1397 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001398 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001399 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1400 " output.gl_Position.w = gl_Position.w;\n";
1401
1402 if (vertexShader->mUsesPointSize && sm3)
1403 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001404 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001405 }
1406
1407 if (fragmentShader->mUsesFragCoord)
1408 {
1409 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1410 }
1411
1412 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1413 {
1414 if (varying->reg >= 0)
1415 {
1416 for (int i = 0; i < varying->size; i++)
1417 {
1418 int rows = VariableRowCount(varying->type);
1419
1420 for (int j = 0; j < rows; j++)
1421 {
1422 int r = varying->reg + i * rows + j;
1423 vertexHLSL += " output.v" + str(r);
1424
1425 bool sharedRegister = false; // Register used by multiple varyings
1426
1427 for (int x = 0; x < 4; x++)
1428 {
1429 if (packing[r][x] && packing[r][x] != packing[r][0])
1430 {
1431 sharedRegister = true;
1432 break;
1433 }
1434 }
1435
1436 if(sharedRegister)
1437 {
1438 vertexHLSL += ".";
1439
1440 for (int x = 0; x < 4; x++)
1441 {
1442 if (packing[r][x] == &*varying)
1443 {
1444 switch(x)
1445 {
1446 case 0: vertexHLSL += "x"; break;
1447 case 1: vertexHLSL += "y"; break;
1448 case 2: vertexHLSL += "z"; break;
1449 case 3: vertexHLSL += "w"; break;
1450 }
1451 }
1452 }
1453 }
1454
1455 vertexHLSL += " = " + varying->name;
1456
1457 if (varying->array)
1458 {
1459 vertexHLSL += "[" + str(i) + "]";
1460 }
1461
1462 if (rows > 1)
1463 {
1464 vertexHLSL += "[" + str(j) + "]";
1465 }
1466
1467 vertexHLSL += ";\n";
1468 }
1469 }
1470 }
1471 }
1472
1473 vertexHLSL += "\n"
1474 " return output;\n"
1475 "}\n";
1476
1477 pixelHLSL += "struct PS_INPUT\n"
1478 "{\n";
1479
1480 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1481 {
1482 if (varying->reg >= 0)
1483 {
1484 for (int i = 0; i < varying->size; i++)
1485 {
1486 int rows = VariableRowCount(varying->type);
1487 for (int j = 0; j < rows; j++)
1488 {
1489 std::string n = str(varying->reg + i * rows + j);
1490 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1491 }
1492 }
1493 }
1494 else UNREACHABLE();
1495 }
1496
1497 if (fragmentShader->mUsesFragCoord)
1498 {
1499 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1500 if (sm3) {
1501 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1502 }
1503 }
1504
1505 if (fragmentShader->mUsesPointCoord && sm3)
1506 {
1507 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1508 }
1509
1510 if (fragmentShader->mUsesFrontFacing)
1511 {
1512 pixelHLSL += " float vFace : VFACE;\n";
1513 }
1514
1515 pixelHLSL += "};\n"
1516 "\n"
1517 "struct PS_OUTPUT\n"
1518 "{\n"
1519 " float4 gl_Color[1] : COLOR;\n"
1520 "};\n"
1521 "\n"
1522 "PS_OUTPUT main(PS_INPUT input)\n"
1523 "{\n";
1524
1525 if (fragmentShader->mUsesFragCoord)
1526 {
1527 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1528
1529 if (sm3)
1530 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001531 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001532 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001533 }
1534 else
1535 {
1536 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1537 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001538 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001539 }
1540
1541 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1542 " gl_FragCoord.w = rhw;\n";
1543 }
1544
1545 if (fragmentShader->mUsesPointCoord && sm3)
1546 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001547 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1548 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001549 }
1550
1551 if (fragmentShader->mUsesFrontFacing)
1552 {
1553 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1554 }
1555
1556 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1557 {
1558 if (varying->reg >= 0)
1559 {
1560 for (int i = 0; i < varying->size; i++)
1561 {
1562 int rows = VariableRowCount(varying->type);
1563 for (int j = 0; j < rows; j++)
1564 {
1565 std::string n = str(varying->reg + i * rows + j);
1566 pixelHLSL += " " + varying->name;
1567
1568 if (varying->array)
1569 {
1570 pixelHLSL += "[" + str(i) + "]";
1571 }
1572
1573 if (rows > 1)
1574 {
1575 pixelHLSL += "[" + str(j) + "]";
1576 }
1577
1578 pixelHLSL += " = input.v" + n + ";\n";
1579 }
1580 }
1581 }
1582 else UNREACHABLE();
1583 }
1584
1585 pixelHLSL += "\n"
1586 " gl_main();\n"
1587 "\n"
1588 " PS_OUTPUT output;\n"
1589 " output.gl_Color[0] = gl_Color[0];\n"
1590 "\n"
1591 " return output;\n"
1592 "}\n";
1593
1594 return true;
1595}
1596
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001597bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1598{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001599 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600
1601 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001602 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001603 if (format != GL_PROGRAM_BINARY_ANGLE)
1604 {
1605 infoLog.append("Invalid program binary format.");
1606 return false;
1607 }
1608
1609 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001610 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001611 if (version != BUILD_REVISION)
1612 {
1613 infoLog.append("Invalid program binary version.");
1614 return false;
1615 }
1616
1617 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1618 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001619 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001620 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001621 stream.read(&name);
1622 mLinkedAttribute[i].name = name;
1623 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001624 }
1625
1626 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1627 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001628 stream.read(&mSamplersPS[i].active);
1629 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001630
1631 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001632 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633 mSamplersPS[i].textureType = (TextureType) textureType;
1634 }
1635
1636 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1637 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001638 stream.read(&mSamplersVS[i].active);
1639 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640
1641 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001642 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643 mSamplersVS[i].textureType = (TextureType) textureType;
1644 }
1645
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001646 stream.read(&mUsedVertexSamplerRange);
1647 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001648
1649 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001650 stream.read(&size);
1651 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001652 {
1653 infoLog.append("Invalid program binary.");
1654 return false;
1655 }
1656
1657 mUniforms.resize(size);
1658 for (unsigned int i = 0; i < size; ++i)
1659 {
1660 GLenum type;
1661 std::string _name;
1662 unsigned int arraySize;
1663
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 stream.read(&type);
1665 stream.read(&_name);
1666 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001668 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001670 stream.read(&mUniforms[i]->ps.float4Index);
1671 stream.read(&mUniforms[i]->ps.samplerIndex);
1672 stream.read(&mUniforms[i]->ps.boolIndex);
1673 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001674
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001675 stream.read(&mUniforms[i]->vs.float4Index);
1676 stream.read(&mUniforms[i]->vs.samplerIndex);
1677 stream.read(&mUniforms[i]->vs.boolIndex);
1678 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 }
1680
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001681 stream.read(&size);
1682 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683 {
1684 infoLog.append("Invalid program binary.");
1685 return false;
1686 }
1687
1688 mUniformIndex.resize(size);
1689 for (unsigned int i = 0; i < size; ++i)
1690 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001691 stream.read(&mUniformIndex[i].name);
1692 stream.read(&mUniformIndex[i].element);
1693 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001694 }
1695
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001696 stream.read(&mDxDepthRangeLocation);
1697 stream.read(&mDxDepthLocation);
1698 stream.read(&mDxCoordLocation);
1699 stream.read(&mDxHalfPixelSizeLocation);
1700 stream.read(&mDxFrontCCWLocation);
1701 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001702
1703 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001704 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705
1706 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001707 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001709 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710
1711 const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
1712 ptr += sizeof(GUID);
1713
1714 D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier();
1715 if (memcmp(&currentIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0)
1716 {
1717 infoLog.append("Invalid program binary.");
1718 return false;
1719 }
1720
1721 const char *pixelShaderFunction = ptr;
1722 ptr += pixelShaderSize;
1723
1724 const char *vertexShaderFunction = ptr;
1725 ptr += vertexShaderSize;
1726
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001727 mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
1728 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 {
1730 infoLog.append("Could not create pixel shader.");
1731 return false;
1732 }
1733
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001734 mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
1735 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736 {
1737 infoLog.append("Could not create vertex shader.");
1738 mPixelExecutable->Release();
1739 mPixelExecutable = NULL;
1740 return false;
1741 }
1742
1743 return true;
1744}
1745
1746bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1747{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001748 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001749
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001750 stream.write(GL_PROGRAM_BINARY_ANGLE);
1751 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752
1753 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1754 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001755 stream.write(mLinkedAttribute[i].type);
1756 stream.write(mLinkedAttribute[i].name);
1757 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758 }
1759
1760 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1761 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001762 stream.write(mSamplersPS[i].active);
1763 stream.write(mSamplersPS[i].logicalTextureUnit);
1764 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 }
1766
1767 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1768 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001769 stream.write(mSamplersVS[i].active);
1770 stream.write(mSamplersVS[i].logicalTextureUnit);
1771 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772 }
1773
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001774 stream.write(mUsedVertexSamplerRange);
1775 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001776
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001777 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1779 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001780 stream.write(mUniforms[i]->type);
1781 stream.write(mUniforms[i]->_name);
1782 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001784 stream.write(mUniforms[i]->ps.float4Index);
1785 stream.write(mUniforms[i]->ps.samplerIndex);
1786 stream.write(mUniforms[i]->ps.boolIndex);
1787 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001789 stream.write(mUniforms[i]->vs.float4Index);
1790 stream.write(mUniforms[i]->vs.samplerIndex);
1791 stream.write(mUniforms[i]->vs.boolIndex);
1792 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001793 }
1794
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001795 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1797 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 stream.write(mUniformIndex[i].name);
1799 stream.write(mUniformIndex[i].element);
1800 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801 }
1802
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001803 stream.write(mDxDepthRangeLocation);
1804 stream.write(mDxDepthLocation);
1805 stream.write(mDxCoordLocation);
1806 stream.write(mDxHalfPixelSizeLocation);
1807 stream.write(mDxFrontCCWLocation);
1808 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001809
1810 UINT pixelShaderSize;
1811 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1812 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001813 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814
1815 UINT vertexShaderSize;
1816 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1817 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001818 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819
1820 D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier();
1821
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001822 GLsizei streamLength = stream.length();
1823 const void *streamData = stream.data();
1824
1825 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001826 if (totalLength > bufSize)
1827 {
1828 if (length)
1829 {
1830 *length = 0;
1831 }
1832
1833 return false;
1834 }
1835
1836 if (binary)
1837 {
1838 char *ptr = (char*) binary;
1839
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001840 memcpy(ptr, streamData, streamLength);
1841 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001842
1843 memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID));
1844 ptr += sizeof(GUID);
1845
1846 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1847 ASSERT(SUCCEEDED(result));
1848 ptr += pixelShaderSize;
1849
1850 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1851 ASSERT(SUCCEEDED(result));
1852 ptr += vertexShaderSize;
1853
1854 ASSERT(ptr - totalLength == binary);
1855 }
1856
1857 if (length)
1858 {
1859 *length = totalLength;
1860 }
1861
1862 return true;
1863}
1864
1865GLint ProgramBinary::getLength()
1866{
1867 GLint length;
1868 if (save(NULL, INT_MAX, &length))
1869 {
1870 return length;
1871 }
1872 else
1873 {
1874 return 0;
1875 }
1876}
1877
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001878bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001879{
1880 if (!fragmentShader || !fragmentShader->isCompiled())
1881 {
1882 return false;
1883 }
1884
1885 if (!vertexShader || !vertexShader->isCompiled())
1886 {
1887 return false;
1888 }
1889
1890 std::string pixelHLSL = fragmentShader->getHLSL();
1891 std::string vertexHLSL = vertexShader->getHLSL();
1892
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001893 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001894 {
1895 return false;
1896 }
1897
1898 Context *context = getContext();
1899 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1900 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1901
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001902 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1903 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001904
1905 if (vertexBinary && pixelBinary)
1906 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001907 mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
1908 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001909 {
1910 return error(GL_OUT_OF_MEMORY, false);
1911 }
1912
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001913 mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
1914 if (!mPixelExecutable)
1915 {
1916 mVertexExecutable->Release();
1917 mVertexExecutable = NULL;
1918 return error(GL_OUT_OF_MEMORY, false);
1919 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001920
1921 vertexBinary->Release();
1922 pixelBinary->Release();
1923 vertexBinary = NULL;
1924 pixelBinary = NULL;
1925
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001926 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001927 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001928 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001929 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001930
1931 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1932 {
1933 return false;
1934 }
1935
1936 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1937 {
1938 return false;
1939 }
1940
1941 // these uniforms are searched as already-decorated because gl_ and dx_
1942 // are reserved prefixes, and do not receive additional decoration
1943 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1944 mDxDepthLocation = getUniformLocation("dx_Depth");
1945 mDxCoordLocation = getUniformLocation("dx_Coord");
1946 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1947 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1948 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1949
1950 context->markDxUniformsDirty();
1951
1952 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001953 }
1954
1955 return false;
1956}
1957
1958// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001959bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001960{
1961 unsigned int usedLocations = 0;
1962
1963 // Link attributes that have a binding location
1964 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1965 {
1966 int location = attributeBindings.getAttributeBinding(attribute->name);
1967
1968 if (location != -1) // Set by glBindAttribLocation
1969 {
1970 if (!mLinkedAttribute[location].name.empty())
1971 {
1972 // Multiple active attributes bound to the same location; not an error
1973 }
1974
1975 mLinkedAttribute[location] = *attribute;
1976
1977 int rows = VariableRowCount(attribute->type);
1978
1979 if (rows + location > MAX_VERTEX_ATTRIBS)
1980 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001981 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 +00001982
1983 return false;
1984 }
1985
1986 for (int i = 0; i < rows; i++)
1987 {
1988 usedLocations |= 1 << (location + i);
1989 }
1990 }
1991 }
1992
1993 // Link attributes that don't have a binding location
1994 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1995 {
1996 int location = attributeBindings.getAttributeBinding(attribute->name);
1997
1998 if (location == -1) // Not set by glBindAttribLocation
1999 {
2000 int rows = VariableRowCount(attribute->type);
2001 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2002
2003 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2004 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002005 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002006
2007 return false; // Fail to link
2008 }
2009
2010 mLinkedAttribute[availableIndex] = *attribute;
2011 }
2012 }
2013
2014 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2015 {
2016 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2017 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2018
2019 for (int r = 0; r < rows; r++)
2020 {
2021 mSemanticIndex[attributeIndex++] = index++;
2022 }
2023 }
2024
2025 return true;
2026}
2027
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002028bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002029{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002030 for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002031 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002032 const D3DConstant *constant = constantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002033
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002034 if (!defineUniform(infoLog, shader, constant))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002035 {
2036 return false;
2037 }
2038 }
2039
2040 return true;
2041}
2042
2043// Adds the description of a constant found in the binary shader to the list of uniforms
2044// Returns true if succesful (uniform not already defined)
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002045bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002046{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002047 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002048 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002049 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002050 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002051 const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str());
2052 const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002053
2054 if (psConstant)
2055 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002056 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002057
2058 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2059 {
2060 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002061 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002062 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2063 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2064 }
2065 else
2066 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002067 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002068 return false;
2069 }
2070 }
2071
2072 if (vsConstant)
2073 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002074 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002075
2076 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2077 {
2078 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002079 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002080 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2081 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2082 }
2083 else
2084 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002085 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002086 return false;
2087 }
2088 }
2089 }
2090 }
2091
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002092 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002093 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002094 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002095 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002096 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002098 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002099 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002100 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002101
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002102 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002103
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002104 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + "."))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002105 {
2106 return false;
2107 }
2108 }
2109 }
2110
2111 return true;
2112 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002113 case D3DConstant::CLASS_SCALAR:
2114 case D3DConstant::CLASS_VECTOR:
2115 case D3DConstant::CLASS_MATRIX_COLUMNS:
2116 case D3DConstant::CLASS_OBJECT:
2117 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002118 default:
2119 UNREACHABLE();
2120 return false;
2121 }
2122}
2123
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002124bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002125{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002126 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002127
2128 if(!uniform)
2129 {
2130 return false;
2131 }
2132
2133 // Check if already defined
2134 GLint location = getUniformLocation(uniform->name);
2135 GLenum type = uniform->type;
2136
2137 if (location >= 0)
2138 {
2139 delete uniform;
2140 uniform = mUniforms[mUniformIndex[location].index];
2141 }
2142
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002143 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2144 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002145
2146 if (location >= 0)
2147 {
2148 return uniform->type == type;
2149 }
2150
2151 mUniforms.push_back(uniform);
2152 unsigned int uniformIndex = mUniforms.size() - 1;
2153
2154 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2155 {
2156 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2157 }
2158
2159 return true;
2160}
2161
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002162Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002163{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002164 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002165 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002166 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002167 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002168 case D3DConstant::PT_SAMPLER2D:
2169 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002170 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002171 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002172 default: UNREACHABLE();
2173 }
2174 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002175 case D3DConstant::PT_SAMPLERCUBE:
2176 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002177 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002178 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002179 default: UNREACHABLE();
2180 }
2181 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002182 case D3DConstant::PT_BOOL:
2183 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002184 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002185 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2186 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2187 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2188 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002189 default: UNREACHABLE();
2190 }
2191 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002192 case D3DConstant::PT_INT:
2193 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002194 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002195 case 1: return new Uniform(GL_INT, _name, constant->elements);
2196 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2197 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2198 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199 default: UNREACHABLE();
2200 }
2201 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002202 case D3DConstant::PT_FLOAT:
2203 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002204 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002205 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2206 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2207 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2208 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002209 default: UNREACHABLE();
2210 }
2211 break;
2212 default:
2213 UNREACHABLE();
2214 }
2215 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002216 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002217 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002218 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002219 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002220 case D3DConstant::PT_FLOAT:
2221 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002222 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002223 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2224 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2225 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002226 default: UNREACHABLE();
2227 }
2228 break;
2229 default: UNREACHABLE();
2230 }
2231 }
2232 else UNREACHABLE();
2233
2234 return 0;
2235}
2236
2237// This method needs to match OutputHLSL::decorate
2238std::string ProgramBinary::decorateAttribute(const std::string &name)
2239{
2240 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2241 {
2242 return "_" + name;
2243 }
2244
2245 return name;
2246}
2247
2248std::string ProgramBinary::undecorateUniform(const std::string &_name)
2249{
2250 std::string name = _name;
2251
2252 // Remove any structure field decoration
2253 size_t pos = 0;
2254 while ((pos = name.find("._", pos)) != std::string::npos)
2255 {
2256 name.replace(pos, 2, ".");
2257 }
2258
2259 // Remove the leading decoration
2260 if (name[0] == '_')
2261 {
2262 return name.substr(1);
2263 }
2264 else if (name.compare(0, 3, "ar_") == 0)
2265 {
2266 return name.substr(3);
2267 }
2268
2269 return name;
2270}
2271
2272void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2273{
2274 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2275 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2276
2277 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2278 {
2279 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2280 for (int i = 0; i < count; i++)
2281 {
2282 for (int j = 0; j < 4; j++)
2283 {
2284 if (j < width)
2285 {
2286 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2287 }
2288 else
2289 {
2290 vector[i * 4 + j] = 0.0f;
2291 }
2292 }
2293 }
2294 }
2295
2296 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2297 {
2298 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2299 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2300 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2301 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2302 for (int i = 0; i < copyCount; i++)
2303 {
2304 boolVector[i] = v[i] != GL_FALSE;
2305 }
2306 }
2307
2308 if (targetUniform->ps.float4Index >= 0)
2309 {
2310 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2311 }
2312
2313 if (targetUniform->ps.boolIndex >= 0)
2314 {
2315 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2316 }
2317
2318 if (targetUniform->vs.float4Index >= 0)
2319 {
2320 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2321 }
2322
2323 if (targetUniform->vs.boolIndex >= 0)
2324 {
2325 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2326 }
2327}
2328
2329bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2330{
2331 if (targetUniform->ps.registerCount)
2332 {
2333 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2334 }
2335
2336 if (targetUniform->vs.registerCount)
2337 {
2338 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2339 }
2340
2341 return true;
2342}
2343
2344bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2345{
2346 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002347 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002348
2349 for (int i = 0; i < count; i++)
2350 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002351 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002352 }
2353
2354 if (targetUniform->ps.registerCount)
2355 {
2356 if (targetUniform->ps.samplerIndex >= 0)
2357 {
2358 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2359
2360 for (int i = 0; i < count; i++)
2361 {
2362 unsigned int samplerIndex = firstIndex + i;
2363
2364 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2365 {
2366 ASSERT(mSamplersPS[samplerIndex].active);
2367 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2368 }
2369 }
2370 }
2371 else
2372 {
2373 ASSERT(targetUniform->ps.float4Index >= 0);
2374 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2375 }
2376 }
2377
2378 if (targetUniform->vs.registerCount)
2379 {
2380 if (targetUniform->vs.samplerIndex >= 0)
2381 {
2382 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2383
2384 for (int i = 0; i < count; i++)
2385 {
2386 unsigned int samplerIndex = firstIndex + i;
2387
2388 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2389 {
2390 ASSERT(mSamplersVS[samplerIndex].active);
2391 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2392 }
2393 }
2394 }
2395 else
2396 {
2397 ASSERT(targetUniform->vs.float4Index >= 0);
2398 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2399 }
2400 }
2401
2402 return true;
2403}
2404
2405bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2406{
2407 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002408 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002409
2410 for (int i = 0; i < count; i++)
2411 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002412 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002413
2414 v += 2;
2415 }
2416
2417 applyUniformniv(targetUniform, count, vector);
2418
2419 return true;
2420}
2421
2422bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2423{
2424 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002425 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002426
2427 for (int i = 0; i < count; i++)
2428 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002429 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002430
2431 v += 3;
2432 }
2433
2434 applyUniformniv(targetUniform, count, vector);
2435
2436 return true;
2437}
2438
2439bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2440{
2441 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002442 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002443
2444 for (int i = 0; i < count; i++)
2445 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002446 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002447
2448 v += 4;
2449 }
2450
2451 applyUniformniv(targetUniform, count, vector);
2452
2453 return true;
2454}
2455
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002456void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002457{
2458 if (targetUniform->ps.registerCount)
2459 {
2460 ASSERT(targetUniform->ps.float4Index >= 0);
2461 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2462 }
2463
2464 if (targetUniform->vs.registerCount)
2465 {
2466 ASSERT(targetUniform->vs.float4Index >= 0);
2467 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2468 }
2469}
2470
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002471bool ProgramBinary::isValidated() const
2472{
2473 return mValidated;
2474}
2475
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002476void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2477{
2478 // Skip over inactive attributes
2479 unsigned int activeAttribute = 0;
2480 unsigned int attribute;
2481 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2482 {
2483 if (mLinkedAttribute[attribute].name.empty())
2484 {
2485 continue;
2486 }
2487
2488 if (activeAttribute == index)
2489 {
2490 break;
2491 }
2492
2493 activeAttribute++;
2494 }
2495
2496 if (bufsize > 0)
2497 {
2498 const char *string = mLinkedAttribute[attribute].name.c_str();
2499
2500 strncpy(name, string, bufsize);
2501 name[bufsize - 1] = '\0';
2502
2503 if (length)
2504 {
2505 *length = strlen(name);
2506 }
2507 }
2508
2509 *size = 1; // Always a single 'type' instance
2510
2511 *type = mLinkedAttribute[attribute].type;
2512}
2513
2514GLint ProgramBinary::getActiveAttributeCount()
2515{
2516 int count = 0;
2517
2518 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2519 {
2520 if (!mLinkedAttribute[attributeIndex].name.empty())
2521 {
2522 count++;
2523 }
2524 }
2525
2526 return count;
2527}
2528
2529GLint ProgramBinary::getActiveAttributeMaxLength()
2530{
2531 int maxLength = 0;
2532
2533 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2534 {
2535 if (!mLinkedAttribute[attributeIndex].name.empty())
2536 {
2537 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2538 }
2539 }
2540
2541 return maxLength;
2542}
2543
2544void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2545{
2546 // Skip over internal uniforms
2547 unsigned int activeUniform = 0;
2548 unsigned int uniform;
2549 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2550 {
2551 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2552 {
2553 continue;
2554 }
2555
2556 if (activeUniform == index)
2557 {
2558 break;
2559 }
2560
2561 activeUniform++;
2562 }
2563
2564 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2565
2566 if (bufsize > 0)
2567 {
2568 std::string string = mUniforms[uniform]->name;
2569
2570 if (mUniforms[uniform]->isArray())
2571 {
2572 string += "[0]";
2573 }
2574
2575 strncpy(name, string.c_str(), bufsize);
2576 name[bufsize - 1] = '\0';
2577
2578 if (length)
2579 {
2580 *length = strlen(name);
2581 }
2582 }
2583
2584 *size = mUniforms[uniform]->arraySize;
2585
2586 *type = mUniforms[uniform]->type;
2587}
2588
2589GLint ProgramBinary::getActiveUniformCount()
2590{
2591 int count = 0;
2592
2593 unsigned int numUniforms = mUniforms.size();
2594 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2595 {
2596 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2597 {
2598 count++;
2599 }
2600 }
2601
2602 return count;
2603}
2604
2605GLint ProgramBinary::getActiveUniformMaxLength()
2606{
2607 int maxLength = 0;
2608
2609 unsigned int numUniforms = mUniforms.size();
2610 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2611 {
2612 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2613 {
2614 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2615 if (mUniforms[uniformIndex]->isArray())
2616 {
2617 length += 3; // Counting in "[0]".
2618 }
2619 maxLength = std::max(length, maxLength);
2620 }
2621 }
2622
2623 return maxLength;
2624}
2625
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002626void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002627{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002628 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002629 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002630 {
2631 mValidated = false;
2632 }
2633 else
2634 {
2635 mValidated = true;
2636 }
2637}
2638
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002639bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002640{
2641 // if any two active samplers in a program are of different types, but refer to the same
2642 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2643 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2644
2645 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2646 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2647
2648 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2649 {
2650 textureUnitType[i] = TEXTURE_UNKNOWN;
2651 }
2652
2653 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2654 {
2655 if (mSamplersPS[i].active)
2656 {
2657 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2658
2659 if (unit >= maxCombinedTextureImageUnits)
2660 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002661 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002662 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002663 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664 }
2665
2666 return false;
2667 }
2668
2669 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2670 {
2671 if (mSamplersPS[i].textureType != textureUnitType[unit])
2672 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002673 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002674 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002675 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002676 }
2677
2678 return false;
2679 }
2680 }
2681 else
2682 {
2683 textureUnitType[unit] = mSamplersPS[i].textureType;
2684 }
2685 }
2686 }
2687
2688 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2689 {
2690 if (mSamplersVS[i].active)
2691 {
2692 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2693
2694 if (unit >= maxCombinedTextureImageUnits)
2695 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002696 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002697 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002698 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002699 }
2700
2701 return false;
2702 }
2703
2704 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2705 {
2706 if (mSamplersVS[i].textureType != textureUnitType[unit])
2707 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002708 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002709 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002710 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002711 }
2712
2713 return false;
2714 }
2715 }
2716 else
2717 {
2718 textureUnitType[unit] = mSamplersVS[i].textureType;
2719 }
2720 }
2721 }
2722
2723 return true;
2724}
2725
2726GLint ProgramBinary::getDxDepthRangeLocation() const
2727{
2728 return mDxDepthRangeLocation;
2729}
2730
2731GLint ProgramBinary::getDxDepthLocation() const
2732{
2733 return mDxDepthLocation;
2734}
2735
2736GLint ProgramBinary::getDxCoordLocation() const
2737{
2738 return mDxCoordLocation;
2739}
2740
2741GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2742{
2743 return mDxHalfPixelSizeLocation;
2744}
2745
2746GLint ProgramBinary::getDxFrontCCWLocation() const
2747{
2748 return mDxFrontCCWLocation;
2749}
2750
2751GLint ProgramBinary::getDxPointsOrLinesLocation() const
2752{
2753 return mDxPointsOrLinesLocation;
2754}
2755
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002756ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2757{
2758}
2759
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002760}