• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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