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