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
18namespace gl
19{
20unsigned int Program::mCurrentSerial = 1;
21
22std::string str(int i)
23{
24    char buffer[20];
25    sprintf(buffer, "%d", i);
26    return buffer;
27}
28
29Uniform::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
38Uniform::~Uniform()
39{
40    delete[] data;
41}
42
43UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
44    : name(name), element(element), index(index)
45{
46}
47
48Program::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
68Program::~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
83bool 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
110bool 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
139int Program::getAttachedShadersCount() const
140{
141    return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
142}
143
144IDirect3DPixelShader9 *Program::getPixelShader()
145{
146    return mPixelExecutable;
147}
148
149IDirect3DVertexShader9 *Program::getVertexShader()
150{
151    return mVertexExecutable;
152}
153
154void 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
167GLuint 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
183int 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
195GLint 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
214SamplerType 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
222bool 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
233void 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
242GLint 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
269bool 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
326bool 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
384bool 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
441bool 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
498bool 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
526bool 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
554bool 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
582bool 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
641bool 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
698bool 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
755bool 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
812bool 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
855bool 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
898void 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
907void 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
916void 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
964ID3DXBuffer *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
1000int 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
1148bool 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
1473void 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
1552bool 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
1621int 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
1634bool 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)
1658bool 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
1710bool 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
1748Uniform *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
1824std::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
1836std::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
1848bool 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
1882bool 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
1916bool 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
1951bool 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
1987bool 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
2009bool 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
2042bool 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
2075bool 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
2097bool 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
2133bool 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
2169bool 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
2205bool 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
2258bool 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
2291bool 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
2324bool 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
2357void 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
2390void 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
2400void 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
2477bool Program::isLinked()
2478{
2479    return mLinked;
2480}
2481
2482bool Program::isValidated() const
2483{
2484    return mValidated;
2485}
2486
2487void Program::release()
2488{
2489    mRefCount--;
2490
2491    if (mRefCount == 0 && mDeleteStatus)
2492    {
2493        mResourceManager->deleteProgram(mHandle);
2494    }
2495}
2496
2497void Program::addRef()
2498{
2499    mRefCount++;
2500}
2501
2502unsigned int Program::getRefCount() const
2503{
2504    return mRefCount;
2505}
2506
2507unsigned int Program::getSerial() const
2508{
2509    return mSerial;
2510}
2511
2512unsigned int Program::issueSerial()
2513{
2514    return mCurrentSerial++;
2515}
2516
2517int Program::getInfoLogLength() const
2518{
2519    if (!mInfoLog)
2520    {
2521        return 0;
2522    }
2523    else
2524    {
2525       return strlen(mInfoLog) + 1;
2526    }
2527}
2528
2529void 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
2553void 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
2583void 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
2621GLint 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
2636GLint 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
2651void 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
2696GLint 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
2712GLint 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
2728void Program::flagForDeletion()
2729{
2730    mDeleteStatus = true;
2731}
2732
2733bool Program::isFlaggedForDeletion() const
2734{
2735    return mDeleteStatus;
2736}
2737
2738void 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
2762bool 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
2787void 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
2800GLint Program::getDxDepthRangeLocation() const
2801{
2802    return mDxDepthRangeLocation;
2803}
2804
2805GLint Program::getDxDepthLocation() const
2806{
2807    return mDxDepthLocation;
2808}
2809
2810GLint Program::getDxViewportLocation() const
2811{
2812    return mDxViewportLocation;
2813}
2814
2815GLint Program::getDxHalfPixelSizeLocation() const
2816{
2817    return mDxHalfPixelSizeLocation;
2818}
2819
2820GLint Program::getDxFrontCCWLocation() const
2821{
2822    return mDxFrontCCWLocation;
2823}
2824
2825GLint Program::getDxPointsOrLinesLocation() const
2826{
2827    return mDxPointsOrLinesLocation;
2828}
2829
2830}
2831