blob: b3e152142b8a3f663c21c9a15b57c4458982a31c [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.com70062c92012-11-28 19:32:30 +000065ProgramBinary::ProgramBinary(rx::Renderer *renderer) : RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000066{
daniel@transgaming.com70062c92012-11-28 19:32:30 +000067 ASSERT(dynamic_cast<rx::Renderer9*>(renderer) != NULL); // D3D9_REPLACE
68 mRenderer = static_cast<rx::Renderer9*>(renderer);
daniel@transgaming.come4733d72012-10-31 18:07:01 +000069 mDevice = mRenderer->getDevice(); // D3D9_REPLACE
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000070
71 mPixelExecutable = NULL;
72 mVertexExecutable = NULL;
73 mConstantTablePS = NULL;
74 mConstantTableVS = NULL;
75
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000076 mValidated = false;
77
78 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
79 {
80 mSemanticIndex[index] = -1;
81 }
82
83 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
84 {
85 mSamplersPS[index].active = false;
86 }
87
88 for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
89 {
90 mSamplersVS[index].active = false;
91 }
92
93 mUsedVertexSamplerRange = 0;
94 mUsedPixelSamplerRange = 0;
95
96 mDxDepthRangeLocation = -1;
97 mDxDepthLocation = -1;
98 mDxCoordLocation = -1;
99 mDxHalfPixelSizeLocation = -1;
100 mDxFrontCCWLocation = -1;
101 mDxPointsOrLinesLocation = -1;
102}
103
104ProgramBinary::~ProgramBinary()
105{
106 if (mPixelExecutable)
107 {
108 mPixelExecutable->Release();
109 }
110
111 if (mVertexExecutable)
112 {
113 mVertexExecutable->Release();
114 }
115
apatrick@chromium.org60dafe82012-09-05 22:26:10 +0000116 delete mConstantTablePS;
117 delete mConstantTableVS;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118
119 while (!mUniforms.empty())
120 {
121 delete mUniforms.back();
122 mUniforms.pop_back();
123 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000124}
125
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000126unsigned int ProgramBinary::getSerial() const
127{
128 return mSerial;
129}
130
131unsigned int ProgramBinary::issueSerial()
132{
133 return mCurrentSerial++;
134}
135
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
137{
138 return mPixelExecutable;
139}
140
141IDirect3DVertexShader9 *ProgramBinary::getVertexShader()
142{
143 return mVertexExecutable;
144}
145
146GLuint ProgramBinary::getAttributeLocation(const char *name)
147{
148 if (name)
149 {
150 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
151 {
152 if (mLinkedAttribute[index].name == std::string(name))
153 {
154 return index;
155 }
156 }
157 }
158
159 return -1;
160}
161
162int ProgramBinary::getSemanticIndex(int attributeIndex)
163{
164 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
165
166 return mSemanticIndex[attributeIndex];
167}
168
169// Returns one more than the highest sampler index used.
170GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
171{
172 switch (type)
173 {
174 case SAMPLER_PIXEL:
175 return mUsedPixelSamplerRange;
176 case SAMPLER_VERTEX:
177 return mUsedVertexSamplerRange;
178 default:
179 UNREACHABLE();
180 return 0;
181 }
182}
183
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000184bool ProgramBinary::usesPointSize() const
185{
186 return mUsesPointSize;
187}
188
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000189// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
190// index (0-15 for the pixel shader and 0-3 for the vertex shader).
191GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
192{
193 GLint logicalTextureUnit = -1;
194
195 switch (type)
196 {
197 case SAMPLER_PIXEL:
198 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
199
200 if (mSamplersPS[samplerIndex].active)
201 {
202 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
203 }
204 break;
205 case SAMPLER_VERTEX:
206 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
207
208 if (mSamplersVS[samplerIndex].active)
209 {
210 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
211 }
212 break;
213 default: UNREACHABLE();
214 }
215
216 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits())
217 {
218 return logicalTextureUnit;
219 }
220
221 return -1;
222}
223
224// Returns the texture type for a given Direct3D 9 sampler type and
225// index (0-15 for the pixel shader and 0-3 for the vertex shader).
226TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
227{
228 switch (type)
229 {
230 case SAMPLER_PIXEL:
231 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
232 ASSERT(mSamplersPS[samplerIndex].active);
233 return mSamplersPS[samplerIndex].textureType;
234 case SAMPLER_VERTEX:
235 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
236 ASSERT(mSamplersVS[samplerIndex].active);
237 return mSamplersVS[samplerIndex].textureType;
238 default: UNREACHABLE();
239 }
240
241 return TEXTURE_2D;
242}
243
244GLint ProgramBinary::getUniformLocation(std::string name)
245{
246 unsigned int subscript = 0;
247
248 // Strip any trailing array operator and retrieve the subscript
249 size_t open = name.find_last_of('[');
250 size_t close = name.find_last_of(']');
251 if (open != std::string::npos && close == name.length() - 1)
252 {
253 subscript = atoi(name.substr(open + 1).c_str());
254 name.erase(open);
255 }
256
257 unsigned int numUniforms = mUniformIndex.size();
258 for (unsigned int location = 0; location < numUniforms; location++)
259 {
260 if (mUniformIndex[location].name == name &&
261 mUniformIndex[location].element == subscript)
262 {
263 return location;
264 }
265 }
266
267 return -1;
268}
269
270bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
271{
272 if (location < 0 || location >= (int)mUniformIndex.size())
273 {
274 return false;
275 }
276
277 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
278 targetUniform->dirty = true;
279
280 if (targetUniform->type == GL_FLOAT)
281 {
282 int arraySize = targetUniform->arraySize;
283
284 if (arraySize == 1 && count > 1)
285 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
286
287 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
288
289 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
290
291 for (int i = 0; i < count; i++)
292 {
293 target[0] = v[0];
294 target[1] = 0;
295 target[2] = 0;
296 target[3] = 0;
297 target += 4;
298 v += 1;
299 }
300 }
301 else if (targetUniform->type == GL_BOOL)
302 {
303 int arraySize = targetUniform->arraySize;
304
305 if (arraySize == 1 && count > 1)
306 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
307
308 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
309 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
310
311 for (int i = 0; i < count; ++i)
312 {
313 if (v[i] == 0.0f)
314 {
315 boolParams[i] = GL_FALSE;
316 }
317 else
318 {
319 boolParams[i] = GL_TRUE;
320 }
321 }
322 }
323 else
324 {
325 return false;
326 }
327
328 return true;
329}
330
331bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
332{
333 if (location < 0 || location >= (int)mUniformIndex.size())
334 {
335 return false;
336 }
337
338 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
339 targetUniform->dirty = true;
340
341 if (targetUniform->type == GL_FLOAT_VEC2)
342 {
343 int arraySize = targetUniform->arraySize;
344
345 if (arraySize == 1 && count > 1)
346 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
347
348 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
349
350 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
351
352 for (int i = 0; i < count; i++)
353 {
354 target[0] = v[0];
355 target[1] = v[1];
356 target[2] = 0;
357 target[3] = 0;
358 target += 4;
359 v += 2;
360 }
361 }
362 else if (targetUniform->type == GL_BOOL_VEC2)
363 {
364 int arraySize = targetUniform->arraySize;
365
366 if (arraySize == 1 && count > 1)
367 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
368
369 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
370
371 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
372
373 for (int i = 0; i < count * 2; ++i)
374 {
375 if (v[i] == 0.0f)
376 {
377 boolParams[i] = GL_FALSE;
378 }
379 else
380 {
381 boolParams[i] = GL_TRUE;
382 }
383 }
384 }
385 else
386 {
387 return false;
388 }
389
390 return true;
391}
392
393bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
394{
395 if (location < 0 || location >= (int)mUniformIndex.size())
396 {
397 return false;
398 }
399
400 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
401 targetUniform->dirty = true;
402
403 if (targetUniform->type == GL_FLOAT_VEC3)
404 {
405 int arraySize = targetUniform->arraySize;
406
407 if (arraySize == 1 && count > 1)
408 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
409
410 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
411
412 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
413
414 for (int i = 0; i < count; i++)
415 {
416 target[0] = v[0];
417 target[1] = v[1];
418 target[2] = v[2];
419 target[3] = 0;
420 target += 4;
421 v += 3;
422 }
423 }
424 else if (targetUniform->type == GL_BOOL_VEC3)
425 {
426 int arraySize = targetUniform->arraySize;
427
428 if (arraySize == 1 && count > 1)
429 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
430
431 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
432 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
433
434 for (int i = 0; i < count * 3; ++i)
435 {
436 if (v[i] == 0.0f)
437 {
438 boolParams[i] = GL_FALSE;
439 }
440 else
441 {
442 boolParams[i] = GL_TRUE;
443 }
444 }
445 }
446 else
447 {
448 return false;
449 }
450
451 return true;
452}
453
454bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
455{
456 if (location < 0 || location >= (int)mUniformIndex.size())
457 {
458 return false;
459 }
460
461 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
462 targetUniform->dirty = true;
463
464 if (targetUniform->type == GL_FLOAT_VEC4)
465 {
466 int arraySize = targetUniform->arraySize;
467
468 if (arraySize == 1 && count > 1)
469 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
470
471 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
472
473 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
474 v, 4 * sizeof(GLfloat) * count);
475 }
476 else if (targetUniform->type == GL_BOOL_VEC4)
477 {
478 int arraySize = targetUniform->arraySize;
479
480 if (arraySize == 1 && count > 1)
481 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
482
483 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
484 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
485
486 for (int i = 0; i < count * 4; ++i)
487 {
488 if (v[i] == 0.0f)
489 {
490 boolParams[i] = GL_FALSE;
491 }
492 else
493 {
494 boolParams[i] = GL_TRUE;
495 }
496 }
497 }
498 else
499 {
500 return false;
501 }
502
503 return true;
504}
505
506template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
507void transposeMatrix(T *target, const GLfloat *value)
508{
509 int copyWidth = std::min(targetWidth, srcWidth);
510 int copyHeight = std::min(targetHeight, srcHeight);
511
512 for (int x = 0; x < copyWidth; x++)
513 {
514 for (int y = 0; y < copyHeight; y++)
515 {
516 target[x * targetWidth + y] = (T)value[y * srcWidth + x];
517 }
518 }
519 // clear unfilled right side
520 for (int y = 0; y < copyHeight; y++)
521 {
522 for (int x = srcWidth; x < targetWidth; x++)
523 {
524 target[y * targetWidth + x] = (T)0;
525 }
526 }
527 // clear unfilled bottom.
528 for (int y = srcHeight; y < targetHeight; y++)
529 {
530 for (int x = 0; x < targetWidth; x++)
531 {
532 target[y * targetWidth + x] = (T)0;
533 }
534 }
535}
536
537bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
538{
539 if (location < 0 || location >= (int)mUniformIndex.size())
540 {
541 return false;
542 }
543
544 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
545 targetUniform->dirty = true;
546
547 if (targetUniform->type != GL_FLOAT_MAT2)
548 {
549 return false;
550 }
551
552 int arraySize = targetUniform->arraySize;
553
554 if (arraySize == 1 && count > 1)
555 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
556
557 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
558
559 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
560 for (int i = 0; i < count; i++)
561 {
562 transposeMatrix<GLfloat,4,2,2,2>(target, value);
563 target += 8;
564 value += 4;
565 }
566
567 return true;
568}
569
570bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
571{
572 if (location < 0 || location >= (int)mUniformIndex.size())
573 {
574 return false;
575 }
576
577 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
578 targetUniform->dirty = true;
579
580 if (targetUniform->type != GL_FLOAT_MAT3)
581 {
582 return false;
583 }
584
585 int arraySize = targetUniform->arraySize;
586
587 if (arraySize == 1 && count > 1)
588 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
589
590 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
591
592 GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
593 for (int i = 0; i < count; i++)
594 {
595 transposeMatrix<GLfloat,4,3,3,3>(target, value);
596 target += 12;
597 value += 9;
598 }
599
600 return true;
601}
602
603
604bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
605{
606 if (location < 0 || location >= (int)mUniformIndex.size())
607 {
608 return false;
609 }
610
611 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
612 targetUniform->dirty = true;
613
614 if (targetUniform->type != GL_FLOAT_MAT4)
615 {
616 return false;
617 }
618
619 int arraySize = targetUniform->arraySize;
620
621 if (arraySize == 1 && count > 1)
622 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
623
624 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
625
626 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
627 for (int i = 0; i < count; i++)
628 {
629 transposeMatrix<GLfloat,4,4,4,4>(target, value);
630 target += 16;
631 value += 16;
632 }
633
634 return true;
635}
636
637bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
638{
639 if (location < 0 || location >= (int)mUniformIndex.size())
640 {
641 return false;
642 }
643
644 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
645 targetUniform->dirty = true;
646
647 if (targetUniform->type == GL_INT ||
648 targetUniform->type == GL_SAMPLER_2D ||
649 targetUniform->type == GL_SAMPLER_CUBE)
650 {
651 int arraySize = targetUniform->arraySize;
652
653 if (arraySize == 1 && count > 1)
654 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
655
656 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
657
658 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
659 v, sizeof(GLint) * count);
660 }
661 else if (targetUniform->type == GL_BOOL)
662 {
663 int arraySize = targetUniform->arraySize;
664
665 if (arraySize == 1 && count > 1)
666 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
667
668 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
669 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
670
671 for (int i = 0; i < count; ++i)
672 {
673 if (v[i] == 0)
674 {
675 boolParams[i] = GL_FALSE;
676 }
677 else
678 {
679 boolParams[i] = GL_TRUE;
680 }
681 }
682 }
683 else
684 {
685 return false;
686 }
687
688 return true;
689}
690
691bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
692{
693 if (location < 0 || location >= (int)mUniformIndex.size())
694 {
695 return false;
696 }
697
698 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
699 targetUniform->dirty = true;
700
701 if (targetUniform->type == GL_INT_VEC2)
702 {
703 int arraySize = targetUniform->arraySize;
704
705 if (arraySize == 1 && count > 1)
706 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
707
708 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
709
710 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
711 v, 2 * sizeof(GLint) * count);
712 }
713 else if (targetUniform->type == GL_BOOL_VEC2)
714 {
715 int arraySize = targetUniform->arraySize;
716
717 if (arraySize == 1 && count > 1)
718 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
719
720 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
721 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
722
723 for (int i = 0; i < count * 2; ++i)
724 {
725 if (v[i] == 0)
726 {
727 boolParams[i] = GL_FALSE;
728 }
729 else
730 {
731 boolParams[i] = GL_TRUE;
732 }
733 }
734 }
735 else
736 {
737 return false;
738 }
739
740 return true;
741}
742
743bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
744{
745 if (location < 0 || location >= (int)mUniformIndex.size())
746 {
747 return false;
748 }
749
750 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
751 targetUniform->dirty = true;
752
753 if (targetUniform->type == GL_INT_VEC3)
754 {
755 int arraySize = targetUniform->arraySize;
756
757 if (arraySize == 1 && count > 1)
758 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
759
760 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
761
762 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
763 v, 3 * sizeof(GLint) * count);
764 }
765 else if (targetUniform->type == GL_BOOL_VEC3)
766 {
767 int arraySize = targetUniform->arraySize;
768
769 if (arraySize == 1 && count > 1)
770 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
771
772 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
773 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
774
775 for (int i = 0; i < count * 3; ++i)
776 {
777 if (v[i] == 0)
778 {
779 boolParams[i] = GL_FALSE;
780 }
781 else
782 {
783 boolParams[i] = GL_TRUE;
784 }
785 }
786 }
787 else
788 {
789 return false;
790 }
791
792 return true;
793}
794
795bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
796{
797 if (location < 0 || location >= (int)mUniformIndex.size())
798 {
799 return false;
800 }
801
802 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
803 targetUniform->dirty = true;
804
805 if (targetUniform->type == GL_INT_VEC4)
806 {
807 int arraySize = targetUniform->arraySize;
808
809 if (arraySize == 1 && count > 1)
810 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
811
812 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
813
814 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
815 v, 4 * sizeof(GLint) * count);
816 }
817 else if (targetUniform->type == GL_BOOL_VEC4)
818 {
819 int arraySize = targetUniform->arraySize;
820
821 if (arraySize == 1 && count > 1)
822 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
823
824 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
825 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
826
827 for (int i = 0; i < count * 4; ++i)
828 {
829 if (v[i] == 0)
830 {
831 boolParams[i] = GL_FALSE;
832 }
833 else
834 {
835 boolParams[i] = GL_TRUE;
836 }
837 }
838 }
839 else
840 {
841 return false;
842 }
843
844 return true;
845}
846
847bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
848{
849 if (location < 0 || location >= (int)mUniformIndex.size())
850 {
851 return false;
852 }
853
854 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
855
856 // sized queries -- ensure the provided buffer is large enough
857 if (bufSize)
858 {
859 int requiredBytes = UniformExternalSize(targetUniform->type);
860 if (*bufSize < requiredBytes)
861 {
862 return false;
863 }
864 }
865
866 switch (targetUniform->type)
867 {
868 case GL_FLOAT_MAT2:
869 transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
870 break;
871 case GL_FLOAT_MAT3:
872 transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
873 break;
874 case GL_FLOAT_MAT4:
875 transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
876 break;
877 default:
878 {
879 unsigned int count = UniformExternalComponentCount(targetUniform->type);
880 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
881
882 switch (UniformComponentType(targetUniform->type))
883 {
884 case GL_BOOL:
885 {
886 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount;
887
888 for (unsigned int i = 0; i < count; ++i)
889 {
890 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
891 }
892 }
893 break;
894 case GL_FLOAT:
895 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat),
896 count * sizeof(GLfloat));
897 break;
898 case GL_INT:
899 {
900 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount;
901
902 for (unsigned int i = 0; i < count; ++i)
903 {
904 params[i] = (float)intParams[i];
905 }
906 }
907 break;
908 default: UNREACHABLE();
909 }
910 }
911 }
912
913 return true;
914}
915
916bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
917{
918 if (location < 0 || location >= (int)mUniformIndex.size())
919 {
920 return false;
921 }
922
923 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
924
925 // sized queries -- ensure the provided buffer is large enough
926 if (bufSize)
927 {
928 int requiredBytes = UniformExternalSize(targetUniform->type);
929 if (*bufSize < requiredBytes)
930 {
931 return false;
932 }
933 }
934
935 switch (targetUniform->type)
936 {
937 case GL_FLOAT_MAT2:
938 {
939 transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
940 }
941 break;
942 case GL_FLOAT_MAT3:
943 {
944 transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
945 }
946 break;
947 case GL_FLOAT_MAT4:
948 {
949 transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
950 }
951 break;
952 default:
953 {
954 unsigned int count = UniformExternalComponentCount(targetUniform->type);
955 unsigned int internalCount = UniformInternalComponentCount(targetUniform->type);
956
957 switch (UniformComponentType(targetUniform->type))
958 {
959 case GL_BOOL:
960 {
961 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount;
962
963 for (unsigned int i = 0; i < count; ++i)
964 {
965 params[i] = (GLint)boolParams[i];
966 }
967 }
968 break;
969 case GL_FLOAT:
970 {
971 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount;
972
973 for (unsigned int i = 0; i < count; ++i)
974 {
975 params[i] = (GLint)floatParams[i];
976 }
977 }
978 break;
979 case GL_INT:
980 memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint),
981 count * sizeof(GLint));
982 break;
983 default: UNREACHABLE();
984 }
985 }
986 }
987
988 return true;
989}
990
991void ProgramBinary::dirtyAllUniforms()
992{
993 unsigned int numUniforms = mUniforms.size();
994 for (unsigned int index = 0; index < numUniforms; index++)
995 {
996 mUniforms[index]->dirty = true;
997 }
998}
999
1000// Applies all the uniforms set for this program object to the Direct3D 9 device
1001void ProgramBinary::applyUniforms()
1002{
1003 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) {
1004 Uniform *targetUniform = *ub;
1005
1006 if (targetUniform->dirty)
1007 {
1008 int arraySize = targetUniform->arraySize;
1009 GLfloat *f = (GLfloat*)targetUniform->data;
1010 GLint *i = (GLint*)targetUniform->data;
1011 GLboolean *b = (GLboolean*)targetUniform->data;
1012
1013 switch (targetUniform->type)
1014 {
1015 case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break;
1016 case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break;
1017 case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break;
1018 case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break;
1019 case GL_FLOAT:
1020 case GL_FLOAT_VEC2:
1021 case GL_FLOAT_VEC3:
1022 case GL_FLOAT_VEC4:
1023 case GL_FLOAT_MAT2:
1024 case GL_FLOAT_MAT3:
1025 case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break;
1026 case GL_SAMPLER_2D:
1027 case GL_SAMPLER_CUBE:
1028 case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break;
1029 case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break;
1030 case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break;
1031 case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break;
1032 default:
1033 UNREACHABLE();
1034 }
1035
1036 targetUniform->dirty = false;
1037 }
1038 }
1039}
1040
1041// Compiles the HLSL code of the attached shaders into executable binaries
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001042ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001043{
1044 if (!hlsl)
1045 {
1046 return NULL;
1047 }
1048
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001049 DWORD result = NOERROR;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001050 UINT flags = 0;
1051 std::string sourceText;
1052 if (perfActive())
1053 {
1054 flags |= D3DCOMPILE_DEBUG;
1055#ifdef NDEBUG
1056 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1057#else
1058 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
1059#endif
1060
1061 std::string sourcePath = getTempPath();
1062 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
1063 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
1064 }
1065 else
1066 {
1067 flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
1068 sourceText = hlsl;
1069 }
1070
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001071 // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
1072 // Try the default flags first and if compilation fails, try some alternatives.
1073 const static UINT extraFlags[] =
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001074 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001075 0,
1076 D3DCOMPILE_AVOID_FLOW_CONTROL,
1077 D3DCOMPILE_PREFER_FLOW_CONTROL
1078 };
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001079
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001080 const static char * const extraFlagNames[] =
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001081 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001082 "default",
1083 "avoid flow control",
1084 "prefer flow control"
1085 };
1086
1087 for (int i = 0; i < sizeof(extraFlags) / sizeof(UINT); ++i)
1088 {
1089 ID3D10Blob *errorMessage = NULL;
1090 ID3D10Blob *binary = NULL;
1091 result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
1092
1093 if (errorMessage)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001094 {
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001095 const char *message = (const char*)errorMessage->GetBufferPointer();
1096
1097 infoLog.appendSanitized(message);
1098 TRACE("\n%s", hlsl);
1099 TRACE("\n%s", message);
1100
1101 errorMessage->Release();
1102 errorMessage = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001103 }
1104
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001105 if (SUCCEEDED(result))
1106 {
1107 D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize());
1108 if (table->error())
1109 {
1110 delete table;
1111 binary->Release();
1112 return NULL;
1113 }
1114
1115 *constantTable = table;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00001116
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001117 return binary;
1118 }
1119 else
1120 {
1121 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1122 {
1123 return error(GL_OUT_OF_MEMORY, (ID3D10Blob*) NULL);
1124 }
1125
1126 infoLog.append("Warning: D3D shader compilation failed with ");
1127 infoLog.append(extraFlagNames[i]);
1128 infoLog.append(" flags.");
1129 if (i + 1 < sizeof(extraFlagNames) / sizeof(char*))
1130 {
1131 infoLog.append(" Retrying with ");
1132 infoLog.append(extraFlagNames[i + 1]);
1133 infoLog.append(".\n");
1134 }
1135 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001136 }
1137
apatrick@chromium.org637ca472012-10-04 18:12:56 +00001138 return NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001139}
1140
1141// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
1142// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001143int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001144{
1145 Context *context = getContext();
1146 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1147
1148 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1149 {
1150 int n = VariableRowCount(varying->type) * varying->size;
1151 int m = VariableColumnCount(varying->type);
1152 bool success = false;
1153
1154 if (m == 2 || m == 3 || m == 4)
1155 {
1156 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
1157 {
1158 bool available = true;
1159
1160 for (int y = 0; y < n && available; y++)
1161 {
1162 for (int x = 0; x < m && available; x++)
1163 {
1164 if (packing[r + y][x])
1165 {
1166 available = false;
1167 }
1168 }
1169 }
1170
1171 if (available)
1172 {
1173 varying->reg = r;
1174 varying->col = 0;
1175
1176 for (int y = 0; y < n; y++)
1177 {
1178 for (int x = 0; x < m; x++)
1179 {
1180 packing[r + y][x] = &*varying;
1181 }
1182 }
1183
1184 success = true;
1185 }
1186 }
1187
1188 if (!success && m == 2)
1189 {
1190 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
1191 {
1192 bool available = true;
1193
1194 for (int y = 0; y < n && available; y++)
1195 {
1196 for (int x = 2; x < 4 && available; x++)
1197 {
1198 if (packing[r + y][x])
1199 {
1200 available = false;
1201 }
1202 }
1203 }
1204
1205 if (available)
1206 {
1207 varying->reg = r;
1208 varying->col = 2;
1209
1210 for (int y = 0; y < n; y++)
1211 {
1212 for (int x = 2; x < 4; x++)
1213 {
1214 packing[r + y][x] = &*varying;
1215 }
1216 }
1217
1218 success = true;
1219 }
1220 }
1221 }
1222 }
1223 else if (m == 1)
1224 {
1225 int space[4] = {0};
1226
1227 for (int y = 0; y < maxVaryingVectors; y++)
1228 {
1229 for (int x = 0; x < 4; x++)
1230 {
1231 space[x] += packing[y][x] ? 0 : 1;
1232 }
1233 }
1234
1235 int column = 0;
1236
1237 for (int x = 0; x < 4; x++)
1238 {
1239 if (space[x] >= n && space[x] < space[column])
1240 {
1241 column = x;
1242 }
1243 }
1244
1245 if (space[column] >= n)
1246 {
1247 for (int r = 0; r < maxVaryingVectors; r++)
1248 {
1249 if (!packing[r][column])
1250 {
1251 varying->reg = r;
1252
1253 for (int y = r; y < r + n; y++)
1254 {
1255 packing[y][column] = &*varying;
1256 }
1257
1258 break;
1259 }
1260 }
1261
1262 varying->col = column;
1263
1264 success = true;
1265 }
1266 }
1267 else UNREACHABLE();
1268
1269 if (!success)
1270 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001271 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001272
1273 return -1;
1274 }
1275 }
1276
1277 // Return the number of used registers
1278 int registers = 0;
1279
1280 for (int r = 0; r < maxVaryingVectors; r++)
1281 {
1282 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1283 {
1284 registers++;
1285 }
1286 }
1287
1288 return registers;
1289}
1290
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001291bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001292{
1293 if (pixelHLSL.empty() || vertexHLSL.empty())
1294 {
1295 return false;
1296 }
1297
1298 // Reset the varying register assignments
1299 for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++)
1300 {
1301 fragVar->reg = -1;
1302 fragVar->col = -1;
1303 }
1304
1305 for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++)
1306 {
1307 vtxVar->reg = -1;
1308 vtxVar->col = -1;
1309 }
1310
1311 // Map the varyings to the register file
1312 const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001313 int registers = packVaryings(infoLog, packing, fragmentShader);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001314
1315 if (registers < 0)
1316 {
1317 return false;
1318 }
1319
1320 // Write the HLSL input/output declarations
1321 Context *context = getContext();
1322 const bool sm3 = context->supportsShaderModel3();
1323 const int maxVaryingVectors = context->getMaximumVaryingVectors();
1324
1325 if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
1326 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001327 infoLog.append("No varying registers left to support gl_FragCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001328
1329 return false;
1330 }
1331
1332 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1333 {
1334 bool matched = false;
1335
1336 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1337 {
1338 if (output->name == input->name)
1339 {
1340 if (output->type != input->type || output->size != input->size)
1341 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001342 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 +00001343
1344 return false;
1345 }
1346
1347 output->reg = input->reg;
1348 output->col = input->col;
1349
1350 matched = true;
1351 break;
1352 }
1353 }
1354
1355 if (!matched)
1356 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001357 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358
1359 return false;
1360 }
1361 }
1362
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001363 mUsesPointSize = vertexShader->mUsesPointSize;
1364 std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001365
1366 vertexHLSL += "struct VS_INPUT\n"
1367 "{\n";
1368
1369 int semanticIndex = 0;
1370 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1371 {
1372 switch (attribute->type)
1373 {
1374 case GL_FLOAT: vertexHLSL += " float "; break;
1375 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1376 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1377 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1378 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1379 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1380 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1381 default: UNREACHABLE();
1382 }
1383
1384 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1385
1386 semanticIndex += VariableRowCount(attribute->type);
1387 }
1388
1389 vertexHLSL += "};\n"
1390 "\n"
1391 "struct VS_OUTPUT\n"
1392 "{\n"
1393 " float4 gl_Position : POSITION;\n";
1394
1395 for (int r = 0; r < registers; r++)
1396 {
1397 int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
1398
1399 vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
1400 }
1401
1402 if (fragmentShader->mUsesFragCoord)
1403 {
1404 vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1405 }
1406
1407 if (vertexShader->mUsesPointSize && sm3)
1408 {
1409 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1410 }
1411
1412 vertexHLSL += "};\n"
1413 "\n"
1414 "VS_OUTPUT main(VS_INPUT input)\n"
1415 "{\n";
1416
1417 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1418 {
1419 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1420
1421 if (VariableRowCount(attribute->type) > 1) // Matrix
1422 {
1423 vertexHLSL += "transpose";
1424 }
1425
1426 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1427 }
1428
1429 vertexHLSL += "\n"
1430 " gl_main();\n"
1431 "\n"
1432 " VS_OUTPUT output;\n"
1433 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001434 " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001435 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1436 " output.gl_Position.w = gl_Position.w;\n";
1437
1438 if (vertexShader->mUsesPointSize && sm3)
1439 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001440 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001441 }
1442
1443 if (fragmentShader->mUsesFragCoord)
1444 {
1445 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1446 }
1447
1448 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1449 {
1450 if (varying->reg >= 0)
1451 {
1452 for (int i = 0; i < varying->size; i++)
1453 {
1454 int rows = VariableRowCount(varying->type);
1455
1456 for (int j = 0; j < rows; j++)
1457 {
1458 int r = varying->reg + i * rows + j;
1459 vertexHLSL += " output.v" + str(r);
1460
1461 bool sharedRegister = false; // Register used by multiple varyings
1462
1463 for (int x = 0; x < 4; x++)
1464 {
1465 if (packing[r][x] && packing[r][x] != packing[r][0])
1466 {
1467 sharedRegister = true;
1468 break;
1469 }
1470 }
1471
1472 if(sharedRegister)
1473 {
1474 vertexHLSL += ".";
1475
1476 for (int x = 0; x < 4; x++)
1477 {
1478 if (packing[r][x] == &*varying)
1479 {
1480 switch(x)
1481 {
1482 case 0: vertexHLSL += "x"; break;
1483 case 1: vertexHLSL += "y"; break;
1484 case 2: vertexHLSL += "z"; break;
1485 case 3: vertexHLSL += "w"; break;
1486 }
1487 }
1488 }
1489 }
1490
1491 vertexHLSL += " = " + varying->name;
1492
1493 if (varying->array)
1494 {
1495 vertexHLSL += "[" + str(i) + "]";
1496 }
1497
1498 if (rows > 1)
1499 {
1500 vertexHLSL += "[" + str(j) + "]";
1501 }
1502
1503 vertexHLSL += ";\n";
1504 }
1505 }
1506 }
1507 }
1508
1509 vertexHLSL += "\n"
1510 " return output;\n"
1511 "}\n";
1512
1513 pixelHLSL += "struct PS_INPUT\n"
1514 "{\n";
1515
1516 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1517 {
1518 if (varying->reg >= 0)
1519 {
1520 for (int i = 0; i < varying->size; i++)
1521 {
1522 int rows = VariableRowCount(varying->type);
1523 for (int j = 0; j < rows; j++)
1524 {
1525 std::string n = str(varying->reg + i * rows + j);
1526 pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
1527 }
1528 }
1529 }
1530 else UNREACHABLE();
1531 }
1532
1533 if (fragmentShader->mUsesFragCoord)
1534 {
1535 pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
1536 if (sm3) {
1537 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1538 }
1539 }
1540
1541 if (fragmentShader->mUsesPointCoord && sm3)
1542 {
1543 pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
1544 }
1545
1546 if (fragmentShader->mUsesFrontFacing)
1547 {
1548 pixelHLSL += " float vFace : VFACE;\n";
1549 }
1550
1551 pixelHLSL += "};\n"
1552 "\n"
1553 "struct PS_OUTPUT\n"
1554 "{\n"
1555 " float4 gl_Color[1] : COLOR;\n"
1556 "};\n"
1557 "\n"
1558 "PS_OUTPUT main(PS_INPUT input)\n"
1559 "{\n";
1560
1561 if (fragmentShader->mUsesFragCoord)
1562 {
1563 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1564
1565 if (sm3)
1566 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001567 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001568 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001569 }
1570 else
1571 {
1572 // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget()
1573 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001574 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001575 }
1576
1577 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
1578 " gl_FragCoord.w = rhw;\n";
1579 }
1580
1581 if (fragmentShader->mUsesPointCoord && sm3)
1582 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001583 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1584 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001585 }
1586
1587 if (fragmentShader->mUsesFrontFacing)
1588 {
1589 pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
1590 }
1591
1592 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1593 {
1594 if (varying->reg >= 0)
1595 {
1596 for (int i = 0; i < varying->size; i++)
1597 {
1598 int rows = VariableRowCount(varying->type);
1599 for (int j = 0; j < rows; j++)
1600 {
1601 std::string n = str(varying->reg + i * rows + j);
1602 pixelHLSL += " " + varying->name;
1603
1604 if (varying->array)
1605 {
1606 pixelHLSL += "[" + str(i) + "]";
1607 }
1608
1609 if (rows > 1)
1610 {
1611 pixelHLSL += "[" + str(j) + "]";
1612 }
1613
1614 pixelHLSL += " = input.v" + n + ";\n";
1615 }
1616 }
1617 }
1618 else UNREACHABLE();
1619 }
1620
1621 pixelHLSL += "\n"
1622 " gl_main();\n"
1623 "\n"
1624 " PS_OUTPUT output;\n"
1625 " output.gl_Color[0] = gl_Color[0];\n"
1626 "\n"
1627 " return output;\n"
1628 "}\n";
1629
1630 return true;
1631}
1632
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001633bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1634{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636
1637 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001638 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001639 if (format != GL_PROGRAM_BINARY_ANGLE)
1640 {
1641 infoLog.append("Invalid program binary format.");
1642 return false;
1643 }
1644
1645 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001646 stream.read(&version);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001647 if (version != BUILD_REVISION)
1648 {
1649 infoLog.append("Invalid program binary version.");
1650 return false;
1651 }
1652
1653 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1654 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001657 stream.read(&name);
1658 mLinkedAttribute[i].name = name;
1659 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660 }
1661
1662 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1663 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 stream.read(&mSamplersPS[i].active);
1665 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001666
1667 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001668 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001669 mSamplersPS[i].textureType = (TextureType) textureType;
1670 }
1671
1672 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1673 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001674 stream.read(&mSamplersVS[i].active);
1675 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001676
1677 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001678 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 mSamplersVS[i].textureType = (TextureType) textureType;
1680 }
1681
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001682 stream.read(&mUsedVertexSamplerRange);
1683 stream.read(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001684
1685 unsigned int size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001686 stream.read(&size);
1687 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 {
1689 infoLog.append("Invalid program binary.");
1690 return false;
1691 }
1692
1693 mUniforms.resize(size);
1694 for (unsigned int i = 0; i < size; ++i)
1695 {
1696 GLenum type;
1697 std::string _name;
1698 unsigned int arraySize;
1699
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001700 stream.read(&type);
1701 stream.read(&_name);
1702 stream.read(&arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001703
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001704 mUniforms[i] = new Uniform(type, _name, arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 stream.read(&mUniforms[i]->ps.float4Index);
1707 stream.read(&mUniforms[i]->ps.samplerIndex);
1708 stream.read(&mUniforms[i]->ps.boolIndex);
1709 stream.read(&mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001710
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001711 stream.read(&mUniforms[i]->vs.float4Index);
1712 stream.read(&mUniforms[i]->vs.samplerIndex);
1713 stream.read(&mUniforms[i]->vs.boolIndex);
1714 stream.read(&mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001715 }
1716
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001717 stream.read(&size);
1718 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001719 {
1720 infoLog.append("Invalid program binary.");
1721 return false;
1722 }
1723
1724 mUniformIndex.resize(size);
1725 for (unsigned int i = 0; i < size; ++i)
1726 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001727 stream.read(&mUniformIndex[i].name);
1728 stream.read(&mUniformIndex[i].element);
1729 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001730 }
1731
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001732 stream.read(&mDxDepthRangeLocation);
1733 stream.read(&mDxDepthLocation);
1734 stream.read(&mDxCoordLocation);
1735 stream.read(&mDxHalfPixelSizeLocation);
1736 stream.read(&mDxFrontCCWLocation);
1737 stream.read(&mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001738
1739 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001740 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741
1742 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001743 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001744
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001745 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746
1747 const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
1748 ptr += sizeof(GUID);
1749
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001750 GUID identifier = mRenderer->getAdapterIdentifier();
1751 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752 {
1753 infoLog.append("Invalid program binary.");
1754 return false;
1755 }
1756
1757 const char *pixelShaderFunction = ptr;
1758 ptr += pixelShaderSize;
1759
1760 const char *vertexShaderFunction = ptr;
1761 ptr += vertexShaderSize;
1762
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001763 mPixelExecutable = mRenderer->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001764 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001765 {
1766 infoLog.append("Could not create pixel shader.");
1767 return false;
1768 }
1769
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001770 mVertexExecutable = mRenderer->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001771 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772 {
1773 infoLog.append("Could not create vertex shader.");
1774 mPixelExecutable->Release();
1775 mPixelExecutable = NULL;
1776 return false;
1777 }
1778
1779 return true;
1780}
1781
1782bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1783{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001784 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001785
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001786 stream.write(GL_PROGRAM_BINARY_ANGLE);
1787 stream.write(BUILD_REVISION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788
1789 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1790 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.write(mLinkedAttribute[i].type);
1792 stream.write(mLinkedAttribute[i].name);
1793 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794 }
1795
1796 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1797 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001798 stream.write(mSamplersPS[i].active);
1799 stream.write(mSamplersPS[i].logicalTextureUnit);
1800 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001801 }
1802
1803 for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
1804 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001805 stream.write(mSamplersVS[i].active);
1806 stream.write(mSamplersVS[i].logicalTextureUnit);
1807 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808 }
1809
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001810 stream.write(mUsedVertexSamplerRange);
1811 stream.write(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001813 stream.write(mUniforms.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001814 for (unsigned int i = 0; i < mUniforms.size(); ++i)
1815 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001816 stream.write(mUniforms[i]->type);
1817 stream.write(mUniforms[i]->_name);
1818 stream.write(mUniforms[i]->arraySize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001819
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001820 stream.write(mUniforms[i]->ps.float4Index);
1821 stream.write(mUniforms[i]->ps.samplerIndex);
1822 stream.write(mUniforms[i]->ps.boolIndex);
1823 stream.write(mUniforms[i]->ps.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001825 stream.write(mUniforms[i]->vs.float4Index);
1826 stream.write(mUniforms[i]->vs.samplerIndex);
1827 stream.write(mUniforms[i]->vs.boolIndex);
1828 stream.write(mUniforms[i]->vs.registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 }
1830
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001831 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001832 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1833 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001834 stream.write(mUniformIndex[i].name);
1835 stream.write(mUniformIndex[i].element);
1836 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837 }
1838
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001839 stream.write(mDxDepthRangeLocation);
1840 stream.write(mDxDepthLocation);
1841 stream.write(mDxCoordLocation);
1842 stream.write(mDxHalfPixelSizeLocation);
1843 stream.write(mDxFrontCCWLocation);
1844 stream.write(mDxPointsOrLinesLocation);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845
1846 UINT pixelShaderSize;
1847 HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
1848 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001849 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001850
1851 UINT vertexShaderSize;
1852 result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
1853 ASSERT(SUCCEEDED(result));
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001854 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001855
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001856 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001857
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001858 GLsizei streamLength = stream.length();
1859 const void *streamData = stream.data();
1860
1861 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001862 if (totalLength > bufSize)
1863 {
1864 if (length)
1865 {
1866 *length = 0;
1867 }
1868
1869 return false;
1870 }
1871
1872 if (binary)
1873 {
1874 char *ptr = (char*) binary;
1875
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001876 memcpy(ptr, streamData, streamLength);
1877 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001878
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001879 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001880 ptr += sizeof(GUID);
1881
1882 result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
1883 ASSERT(SUCCEEDED(result));
1884 ptr += pixelShaderSize;
1885
1886 result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
1887 ASSERT(SUCCEEDED(result));
1888 ptr += vertexShaderSize;
1889
1890 ASSERT(ptr - totalLength == binary);
1891 }
1892
1893 if (length)
1894 {
1895 *length = totalLength;
1896 }
1897
1898 return true;
1899}
1900
1901GLint ProgramBinary::getLength()
1902{
1903 GLint length;
1904 if (save(NULL, INT_MAX, &length))
1905 {
1906 return length;
1907 }
1908 else
1909 {
1910 return 0;
1911 }
1912}
1913
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001914bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001915{
1916 if (!fragmentShader || !fragmentShader->isCompiled())
1917 {
1918 return false;
1919 }
1920
1921 if (!vertexShader || !vertexShader->isCompiled())
1922 {
1923 return false;
1924 }
1925
1926 std::string pixelHLSL = fragmentShader->getHLSL();
1927 std::string vertexHLSL = vertexShader->getHLSL();
1928
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001929 if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001930 {
1931 return false;
1932 }
1933
1934 Context *context = getContext();
1935 const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
1936 const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
1937
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001938 ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
1939 ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001940
1941 if (vertexBinary && pixelBinary)
1942 {
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001943 mVertexExecutable = mRenderer->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001944 if (!mVertexExecutable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001945 {
1946 return error(GL_OUT_OF_MEMORY, false);
1947 }
1948
daniel@transgaming.come4733d72012-10-31 18:07:01 +00001949 mPixelExecutable = mRenderer->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001950 if (!mPixelExecutable)
1951 {
1952 mVertexExecutable->Release();
1953 mVertexExecutable = NULL;
1954 return error(GL_OUT_OF_MEMORY, false);
1955 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001956
1957 vertexBinary->Release();
1958 pixelBinary->Release();
1959 vertexBinary = NULL;
1960 pixelBinary = NULL;
1961
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001962 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001963 {
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001964 return false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001965 }
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +00001966
1967 if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
1968 {
1969 return false;
1970 }
1971
1972 if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
1973 {
1974 return false;
1975 }
1976
1977 // these uniforms are searched as already-decorated because gl_ and dx_
1978 // are reserved prefixes, and do not receive additional decoration
1979 mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
1980 mDxDepthLocation = getUniformLocation("dx_Depth");
1981 mDxCoordLocation = getUniformLocation("dx_Coord");
1982 mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
1983 mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
1984 mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
1985
1986 context->markDxUniformsDirty();
1987
1988 return true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001989 }
1990
1991 return false;
1992}
1993
1994// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001995bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001996{
1997 unsigned int usedLocations = 0;
1998
1999 // Link attributes that have a binding location
2000 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2001 {
2002 int location = attributeBindings.getAttributeBinding(attribute->name);
2003
2004 if (location != -1) // Set by glBindAttribLocation
2005 {
2006 if (!mLinkedAttribute[location].name.empty())
2007 {
2008 // Multiple active attributes bound to the same location; not an error
2009 }
2010
2011 mLinkedAttribute[location] = *attribute;
2012
2013 int rows = VariableRowCount(attribute->type);
2014
2015 if (rows + location > MAX_VERTEX_ATTRIBS)
2016 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002017 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 +00002018
2019 return false;
2020 }
2021
2022 for (int i = 0; i < rows; i++)
2023 {
2024 usedLocations |= 1 << (location + i);
2025 }
2026 }
2027 }
2028
2029 // Link attributes that don't have a binding location
2030 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
2031 {
2032 int location = attributeBindings.getAttributeBinding(attribute->name);
2033
2034 if (location == -1) // Not set by glBindAttribLocation
2035 {
2036 int rows = VariableRowCount(attribute->type);
2037 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2038
2039 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2040 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002041 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002042
2043 return false; // Fail to link
2044 }
2045
2046 mLinkedAttribute[availableIndex] = *attribute;
2047 }
2048 }
2049
2050 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2051 {
2052 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2053 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2054
2055 for (int r = 0; r < rows; r++)
2056 {
2057 mSemanticIndex[attributeIndex++] = index++;
2058 }
2059 }
2060
2061 return true;
2062}
2063
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002064bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002065{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002066 for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002067 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002068 const D3DConstant *constant = constantTable->getConstant(constantIndex);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002069
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002070 if (!defineUniform(infoLog, shader, constant))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071 {
2072 return false;
2073 }
2074 }
2075
2076 return true;
2077}
2078
2079// Adds the description of a constant found in the binary shader to the list of uniforms
2080// Returns true if succesful (uniform not already defined)
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002081bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002083 if (constant->registerSet == D3DConstant::RS_SAMPLER)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002085 for (unsigned int i = 0; i < constant->registerCount; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002086 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002087 const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str());
2088 const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002089
2090 if (psConstant)
2091 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002092 unsigned int samplerIndex = psConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002093
2094 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2095 {
2096 mSamplersPS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002097 mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002098 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2099 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2100 }
2101 else
2102 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002103 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002104 return false;
2105 }
2106 }
2107
2108 if (vsConstant)
2109 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002110 unsigned int samplerIndex = vsConstant->registerIndex + i;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002111
2112 if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
2113 {
2114 mSamplersVS[samplerIndex].active = true;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002115 mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2117 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2118 }
2119 else
2120 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002121 infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002122 return false;
2123 }
2124 }
2125 }
2126 }
2127
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002128 switch(constant->typeClass)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002129 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002130 case D3DConstant::CLASS_STRUCT:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002131 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002132 for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002133 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002134 for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002135 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002136 const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002137
apatrick@chromium.org85fee292012-09-06 00:43:06 +00002138 std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002139
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002140 if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + "."))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002141 {
2142 return false;
2143 }
2144 }
2145 }
2146
2147 return true;
2148 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002149 case D3DConstant::CLASS_SCALAR:
2150 case D3DConstant::CLASS_VECTOR:
2151 case D3DConstant::CLASS_MATRIX_COLUMNS:
2152 case D3DConstant::CLASS_OBJECT:
2153 return defineUniform(shader, constant, name + constant->name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002154 default:
2155 UNREACHABLE();
2156 return false;
2157 }
2158}
2159
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002160bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002161{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002162 Uniform *uniform = createUniform(constant, _name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002163
2164 if(!uniform)
2165 {
2166 return false;
2167 }
2168
2169 // Check if already defined
2170 GLint location = getUniformLocation(uniform->name);
2171 GLenum type = uniform->type;
2172
2173 if (location >= 0)
2174 {
2175 delete uniform;
2176 uniform = mUniforms[mUniformIndex[location].index];
2177 }
2178
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002179 if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant);
2180 if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002181
2182 if (location >= 0)
2183 {
2184 return uniform->type == type;
2185 }
2186
2187 mUniforms.push_back(uniform);
2188 unsigned int uniformIndex = mUniforms.size() - 1;
2189
2190 for (unsigned int i = 0; i < uniform->arraySize; ++i)
2191 {
2192 mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex));
2193 }
2194
2195 return true;
2196}
2197
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002198Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002199{
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002200 if (constant->rows == 1) // Vectors and scalars
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002201 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002202 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002203 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002204 case D3DConstant::PT_SAMPLER2D:
2205 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002206 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002207 case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002208 default: UNREACHABLE();
2209 }
2210 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002211 case D3DConstant::PT_SAMPLERCUBE:
2212 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002213 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002214 case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002215 default: UNREACHABLE();
2216 }
2217 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002218 case D3DConstant::PT_BOOL:
2219 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002220 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002221 case 1: return new Uniform(GL_BOOL, _name, constant->elements);
2222 case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements);
2223 case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements);
2224 case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002225 default: UNREACHABLE();
2226 }
2227 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002228 case D3DConstant::PT_INT:
2229 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002230 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002231 case 1: return new Uniform(GL_INT, _name, constant->elements);
2232 case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements);
2233 case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements);
2234 case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002235 default: UNREACHABLE();
2236 }
2237 break;
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002238 case D3DConstant::PT_FLOAT:
2239 switch (constant->columns)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002240 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002241 case 1: return new Uniform(GL_FLOAT, _name, constant->elements);
2242 case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements);
2243 case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements);
2244 case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002245 default: UNREACHABLE();
2246 }
2247 break;
2248 default:
2249 UNREACHABLE();
2250 }
2251 }
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002252 else if (constant->rows == constant->columns) // Square matrices
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002253 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002254 switch (constant->type)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002255 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002256 case D3DConstant::PT_FLOAT:
2257 switch (constant->rows)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002258 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002259 case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements);
2260 case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements);
2261 case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002262 default: UNREACHABLE();
2263 }
2264 break;
2265 default: UNREACHABLE();
2266 }
2267 }
2268 else UNREACHABLE();
2269
2270 return 0;
2271}
2272
2273// This method needs to match OutputHLSL::decorate
2274std::string ProgramBinary::decorateAttribute(const std::string &name)
2275{
2276 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2277 {
2278 return "_" + name;
2279 }
2280
2281 return name;
2282}
2283
2284std::string ProgramBinary::undecorateUniform(const std::string &_name)
2285{
2286 std::string name = _name;
2287
2288 // Remove any structure field decoration
2289 size_t pos = 0;
2290 while ((pos = name.find("._", pos)) != std::string::npos)
2291 {
2292 name.replace(pos, 2, ".");
2293 }
2294
2295 // Remove the leading decoration
2296 if (name[0] == '_')
2297 {
2298 return name.substr(1);
2299 }
2300 else if (name.compare(0, 3, "ar_") == 0)
2301 {
2302 return name.substr(3);
2303 }
2304
2305 return name;
2306}
2307
2308void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
2309{
2310 float vector[D3D9_MAX_FLOAT_CONSTANTS * 4];
2311 BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS];
2312
2313 if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0)
2314 {
2315 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
2316 for (int i = 0; i < count; i++)
2317 {
2318 for (int j = 0; j < 4; j++)
2319 {
2320 if (j < width)
2321 {
2322 vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f;
2323 }
2324 else
2325 {
2326 vector[i * 4 + j] = 0.0f;
2327 }
2328 }
2329 }
2330 }
2331
2332 if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0)
2333 {
2334 int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0;
2335 int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0;
2336 int copyCount = std::min(count * width, std::max(psCount, vsCount));
2337 ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS);
2338 for (int i = 0; i < copyCount; i++)
2339 {
2340 boolVector[i] = v[i] != GL_FALSE;
2341 }
2342 }
2343
2344 if (targetUniform->ps.float4Index >= 0)
2345 {
2346 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount);
2347 }
2348
2349 if (targetUniform->ps.boolIndex >= 0)
2350 {
2351 mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount);
2352 }
2353
2354 if (targetUniform->vs.float4Index >= 0)
2355 {
2356 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount);
2357 }
2358
2359 if (targetUniform->vs.boolIndex >= 0)
2360 {
2361 mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount);
2362 }
2363}
2364
2365bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
2366{
2367 if (targetUniform->ps.registerCount)
2368 {
2369 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount);
2370 }
2371
2372 if (targetUniform->vs.registerCount)
2373 {
2374 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount);
2375 }
2376
2377 return true;
2378}
2379
2380bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2381{
2382 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002383 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002384
2385 for (int i = 0; i < count; i++)
2386 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002387 vector[i] = Vector4((float)v[i], 0, 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388 }
2389
2390 if (targetUniform->ps.registerCount)
2391 {
2392 if (targetUniform->ps.samplerIndex >= 0)
2393 {
2394 unsigned int firstIndex = targetUniform->ps.samplerIndex;
2395
2396 for (int i = 0; i < count; i++)
2397 {
2398 unsigned int samplerIndex = firstIndex + i;
2399
2400 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2401 {
2402 ASSERT(mSamplersPS[samplerIndex].active);
2403 mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
2404 }
2405 }
2406 }
2407 else
2408 {
2409 ASSERT(targetUniform->ps.float4Index >= 0);
2410 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount);
2411 }
2412 }
2413
2414 if (targetUniform->vs.registerCount)
2415 {
2416 if (targetUniform->vs.samplerIndex >= 0)
2417 {
2418 unsigned int firstIndex = targetUniform->vs.samplerIndex;
2419
2420 for (int i = 0; i < count; i++)
2421 {
2422 unsigned int samplerIndex = firstIndex + i;
2423
2424 if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
2425 {
2426 ASSERT(mSamplersVS[samplerIndex].active);
2427 mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
2428 }
2429 }
2430 }
2431 else
2432 {
2433 ASSERT(targetUniform->vs.float4Index >= 0);
2434 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2435 }
2436 }
2437
2438 return true;
2439}
2440
2441bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2442{
2443 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002444 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002445
2446 for (int i = 0; i < count; i++)
2447 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002448 vector[i] = Vector4((float)v[0], (float)v[1], 0, 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002449
2450 v += 2;
2451 }
2452
2453 applyUniformniv(targetUniform, count, vector);
2454
2455 return true;
2456}
2457
2458bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2459{
2460 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002461 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002462
2463 for (int i = 0; i < count; i++)
2464 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002465 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002466
2467 v += 3;
2468 }
2469
2470 applyUniformniv(targetUniform, count, vector);
2471
2472 return true;
2473}
2474
2475bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v)
2476{
2477 ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS);
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002478 Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002479
2480 for (int i = 0; i < count; i++)
2481 {
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002482 vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002483
2484 v += 4;
2485 }
2486
2487 applyUniformniv(targetUniform, count, vector);
2488
2489 return true;
2490}
2491
apatrick@chromium.org60dafe82012-09-05 22:26:10 +00002492void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002493{
2494 if (targetUniform->ps.registerCount)
2495 {
2496 ASSERT(targetUniform->ps.float4Index >= 0);
2497 mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount);
2498 }
2499
2500 if (targetUniform->vs.registerCount)
2501 {
2502 ASSERT(targetUniform->vs.float4Index >= 0);
2503 mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount);
2504 }
2505}
2506
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002507bool ProgramBinary::isValidated() const
2508{
2509 return mValidated;
2510}
2511
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002512void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2513{
2514 // Skip over inactive attributes
2515 unsigned int activeAttribute = 0;
2516 unsigned int attribute;
2517 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2518 {
2519 if (mLinkedAttribute[attribute].name.empty())
2520 {
2521 continue;
2522 }
2523
2524 if (activeAttribute == index)
2525 {
2526 break;
2527 }
2528
2529 activeAttribute++;
2530 }
2531
2532 if (bufsize > 0)
2533 {
2534 const char *string = mLinkedAttribute[attribute].name.c_str();
2535
2536 strncpy(name, string, bufsize);
2537 name[bufsize - 1] = '\0';
2538
2539 if (length)
2540 {
2541 *length = strlen(name);
2542 }
2543 }
2544
2545 *size = 1; // Always a single 'type' instance
2546
2547 *type = mLinkedAttribute[attribute].type;
2548}
2549
2550GLint ProgramBinary::getActiveAttributeCount()
2551{
2552 int count = 0;
2553
2554 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2555 {
2556 if (!mLinkedAttribute[attributeIndex].name.empty())
2557 {
2558 count++;
2559 }
2560 }
2561
2562 return count;
2563}
2564
2565GLint ProgramBinary::getActiveAttributeMaxLength()
2566{
2567 int maxLength = 0;
2568
2569 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2570 {
2571 if (!mLinkedAttribute[attributeIndex].name.empty())
2572 {
2573 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2574 }
2575 }
2576
2577 return maxLength;
2578}
2579
2580void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2581{
2582 // Skip over internal uniforms
2583 unsigned int activeUniform = 0;
2584 unsigned int uniform;
2585 for (uniform = 0; uniform < mUniforms.size(); uniform++)
2586 {
2587 if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0)
2588 {
2589 continue;
2590 }
2591
2592 if (activeUniform == index)
2593 {
2594 break;
2595 }
2596
2597 activeUniform++;
2598 }
2599
2600 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2601
2602 if (bufsize > 0)
2603 {
2604 std::string string = mUniforms[uniform]->name;
2605
2606 if (mUniforms[uniform]->isArray())
2607 {
2608 string += "[0]";
2609 }
2610
2611 strncpy(name, string.c_str(), bufsize);
2612 name[bufsize - 1] = '\0';
2613
2614 if (length)
2615 {
2616 *length = strlen(name);
2617 }
2618 }
2619
2620 *size = mUniforms[uniform]->arraySize;
2621
2622 *type = mUniforms[uniform]->type;
2623}
2624
2625GLint ProgramBinary::getActiveUniformCount()
2626{
2627 int count = 0;
2628
2629 unsigned int numUniforms = mUniforms.size();
2630 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2631 {
2632 if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2633 {
2634 count++;
2635 }
2636 }
2637
2638 return count;
2639}
2640
2641GLint ProgramBinary::getActiveUniformMaxLength()
2642{
2643 int maxLength = 0;
2644
2645 unsigned int numUniforms = mUniforms.size();
2646 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2647 {
2648 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0)
2649 {
2650 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2651 if (mUniforms[uniformIndex]->isArray())
2652 {
2653 length += 3; // Counting in "[0]".
2654 }
2655 maxLength = std::max(length, maxLength);
2656 }
2657 }
2658
2659 return maxLength;
2660}
2661
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002662void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002663{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002665 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002666 {
2667 mValidated = false;
2668 }
2669 else
2670 {
2671 mValidated = true;
2672 }
2673}
2674
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002675bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002676{
2677 // if any two active samplers in a program are of different types, but refer to the same
2678 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2679 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2680
2681 const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
2682 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
2683
2684 for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
2685 {
2686 textureUnitType[i] = TEXTURE_UNKNOWN;
2687 }
2688
2689 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2690 {
2691 if (mSamplersPS[i].active)
2692 {
2693 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2694
2695 if (unit >= maxCombinedTextureImageUnits)
2696 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002697 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002698 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002699 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002700 }
2701
2702 return false;
2703 }
2704
2705 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2706 {
2707 if (mSamplersPS[i].textureType != textureUnitType[unit])
2708 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002709 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002710 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002711 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002712 }
2713
2714 return false;
2715 }
2716 }
2717 else
2718 {
2719 textureUnitType[unit] = mSamplersPS[i].textureType;
2720 }
2721 }
2722 }
2723
2724 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2725 {
2726 if (mSamplersVS[i].active)
2727 {
2728 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2729
2730 if (unit >= maxCombinedTextureImageUnits)
2731 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002732 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002733 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002734 infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002735 }
2736
2737 return false;
2738 }
2739
2740 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2741 {
2742 if (mSamplersVS[i].textureType != textureUnitType[unit])
2743 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002744 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002745 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002746 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002747 }
2748
2749 return false;
2750 }
2751 }
2752 else
2753 {
2754 textureUnitType[unit] = mSamplersVS[i].textureType;
2755 }
2756 }
2757 }
2758
2759 return true;
2760}
2761
2762GLint ProgramBinary::getDxDepthRangeLocation() const
2763{
2764 return mDxDepthRangeLocation;
2765}
2766
2767GLint ProgramBinary::getDxDepthLocation() const
2768{
2769 return mDxDepthLocation;
2770}
2771
2772GLint ProgramBinary::getDxCoordLocation() const
2773{
2774 return mDxCoordLocation;
2775}
2776
2777GLint ProgramBinary::getDxHalfPixelSizeLocation() const
2778{
2779 return mDxHalfPixelSizeLocation;
2780}
2781
2782GLint ProgramBinary::getDxFrontCCWLocation() const
2783{
2784 return mDxFrontCCWLocation;
2785}
2786
2787GLint ProgramBinary::getDxPointsOrLinesLocation() const
2788{
2789 return mDxPointsOrLinesLocation;
2790}
2791
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002792ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2793{
2794}
2795
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002796}