OSDN Git Service

Implement a Radiance prototype.
[android-x86/external-swiftshader.git] / src / Radiance / libRAD / Program.cpp
1 // SwiftShader Software Renderer\r
2 //\r
3 // Copyright(c) 2005-2013 TransGaming Inc.\r
4 //\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,\r
6 // transcribed, stored in a retrieval system, translated into any human or computer\r
7 // language by any means, or disclosed to third parties without the explicit written\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express\r
9 // or implied, including but not limited to any patent rights, are granted to you.\r
10 //\r
11 \r
12 // Program.cpp: Implements the Program class. Implements GL program objects\r
13 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.\r
14 \r
15 #include "Program.h"\r
16 \r
17 #include "main.h"\r
18 #include "Shader.h"\r
19 #include "utilities.h"\r
20 #include "common/debug.h"\r
21 #include "Shader/PixelShader.hpp"\r
22 #include "Shader/VertexShader.hpp"\r
23 \r
24 #include <string>\r
25 #include <stdlib.h>\r
26 \r
27 namespace es2\r
28 {\r
29         unsigned int Program::currentSerial = 1;\r
30 \r
31         std::string str(int i)\r
32         {\r
33                 char buffer[20];\r
34                 sprintf(buffer, "%d", i);\r
35                 return buffer;\r
36         }\r
37 \r
38         Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize) : type(type), precision(precision), name(name), arraySize(arraySize)\r
39         {\r
40                 int bytes = UniformTypeSize(type) * size();\r
41                 data = new unsigned char[bytes];\r
42                 memset(data, 0, bytes);\r
43                 dirty = true;\r
44 \r
45                 psRegisterIndex = -1;\r
46                 vsRegisterIndex = -1;\r
47         }\r
48 \r
49         Uniform::~Uniform()\r
50         {\r
51                 delete[] data;\r
52         }\r
53 \r
54         bool Uniform::isArray() const\r
55         {\r
56                 return arraySize >= 1;\r
57         }\r
58 \r
59         int Uniform::size() const\r
60         {\r
61                 return arraySize > 0 ? arraySize : 1;\r
62         }\r
63 \r
64         int Uniform::registerCount() const\r
65         {\r
66                 return size() * VariableRowCount(type);\r
67         }\r
68 \r
69         UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)\r
70         {\r
71         }\r
72 \r
73         Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())\r
74         {\r
75                 device = getDevice();\r
76 \r
77                 fragmentShader = 0;\r
78                 vertexShader = 0;\r
79                 pixelBinary = 0;\r
80                 vertexBinary = 0;\r
81 \r
82                 infoLog = 0;\r
83                 validated = false;\r
84 \r
85                 unlink();\r
86 \r
87                 orphaned = false;\r
88                 referenceCount = 0;\r
89         }\r
90 \r
91         Program::~Program()\r
92         {\r
93                 unlink();\r
94 \r
95                 if(vertexShader)\r
96                 {\r
97                         vertexShader->release();\r
98                 }\r
99 \r
100                 if(fragmentShader)\r
101                 {\r
102                         fragmentShader->release();\r
103                 }\r
104         }\r
105 \r
106         bool Program::attachShader(Shader *shader)\r
107         {\r
108                 if(shader->getType() == GL_VERTEX_SHADER)\r
109                 {\r
110                         if(vertexShader)\r
111                         {\r
112                                 return false;\r
113                         }\r
114 \r
115                         vertexShader = (VertexShader*)shader;\r
116                         vertexShader->addRef();\r
117                 }\r
118                 else if(shader->getType() == GL_FRAGMENT_SHADER)\r
119                 {\r
120                         if(fragmentShader)\r
121                         {\r
122                                 return false;\r
123                         }\r
124 \r
125                         fragmentShader = (FragmentShader*)shader;\r
126                         fragmentShader->addRef();\r
127                 }\r
128                 else UNREACHABLE();\r
129 \r
130                 return true;\r
131         }\r
132 \r
133         bool Program::detachShader(Shader *shader)\r
134         {\r
135                 if(shader->getType() == GL_VERTEX_SHADER)\r
136                 {\r
137                         if(vertexShader != shader)\r
138                         {\r
139                                 return false;\r
140                         }\r
141 \r
142                         vertexShader->release();\r
143                         vertexShader = 0;\r
144                 }\r
145                 else if(shader->getType() == GL_FRAGMENT_SHADER)\r
146                 {\r
147                         if(fragmentShader != shader)\r
148                         {\r
149                                 return false;\r
150                         }\r
151 \r
152                         fragmentShader->release();\r
153                         fragmentShader = 0;\r
154                 }\r
155                 else UNREACHABLE();\r
156 \r
157                 return true;\r
158         }\r
159 \r
160         int Program::getAttachedShadersCount() const\r
161         {\r
162                 return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);\r
163         }\r
164 \r
165         sw::PixelShader *Program::getPixelShader()\r
166         {\r
167                 return pixelBinary;\r
168         }\r
169 \r
170         sw::VertexShader *Program::getVertexShader()\r
171         {\r
172                 return vertexBinary;\r
173         }\r
174 \r
175         void Program::bindAttributeLocation(GLuint index, const char *name)\r
176         {\r
177                 if(index < MAX_VERTEX_ATTRIBS)\r
178                 {\r
179                         for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)\r
180                         {\r
181                                 attributeBinding[i].erase(name);\r
182                         }\r
183 \r
184                         attributeBinding[index].insert(name);\r
185                 }\r
186         }\r
187 \r
188         GLuint Program::getAttributeLocation(const char *name)\r
189         {\r
190                 if(name)\r
191                 {\r
192                         for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)\r
193                         {\r
194                                 if(linkedAttribute[index].name == std::string(name))\r
195                                 {\r
196                                         return index;\r
197                                 }\r
198                         }\r
199                 }\r
200 \r
201                 return -1;\r
202         }\r
203 \r
204         int Program::getAttributeStream(int attributeIndex)\r
205         {\r
206                 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);\r
207     \r
208                 return attributeStream[attributeIndex];\r
209         }\r
210 \r
211         // Returns the index of the texture image unit (0-19) corresponding to a sampler index (0-15 for the pixel shader and 0-3 for the vertex shader)\r
212         GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)\r
213         {\r
214                 GLuint logicalTextureUnit = -1;\r
215 \r
216                 switch(type)\r
217                 {\r
218                 case sw::SAMPLER_PIXEL:\r
219                         ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));\r
220 \r
221                         if(samplersPS[samplerIndex].active)\r
222                         {\r
223                                 logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;\r
224                         }\r
225                         break;\r
226                 case sw::SAMPLER_VERTEX:\r
227                         ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));\r
228 \r
229                         if(samplersVS[samplerIndex].active)\r
230                         {\r
231                                 logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;\r
232                         }\r
233                         break;\r
234                 default: UNREACHABLE();\r
235                 }\r
236 \r
237                 if(logicalTextureUnit >= 0 && logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
238                 {\r
239                         return logicalTextureUnit;\r
240                 }\r
241 \r
242                 return -1;\r
243         }\r
244 \r
245         // Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)\r
246         TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)\r
247         {\r
248                 switch(type)\r
249                 {\r
250                 case sw::SAMPLER_PIXEL:\r
251                         ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));\r
252                         ASSERT(samplersPS[samplerIndex].active);\r
253                         return samplersPS[samplerIndex].textureType;\r
254                 case sw::SAMPLER_VERTEX:\r
255                         ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));\r
256                         ASSERT(samplersVS[samplerIndex].active);\r
257                         return samplersVS[samplerIndex].textureType;\r
258                 default: UNREACHABLE();\r
259                 }\r
260 \r
261                 return TEXTURE_2D;\r
262         }\r
263 \r
264         GLint Program::getUniformLocation(std::string name)\r
265         {\r
266                 int subscript = 0;\r
267 \r
268                 // Strip any trailing array operator and retrieve the subscript\r
269                 size_t open = name.find_last_of('[');\r
270                 size_t close = name.find_last_of(']');\r
271                 if(open != std::string::npos && close == name.length() - 1)\r
272                 {\r
273                         subscript = atoi(name.substr(open + 1).c_str());\r
274                         name.erase(open);\r
275                 }\r
276 \r
277                 unsigned int numUniforms = uniformIndex.size();\r
278                 for(unsigned int location = 0; location < numUniforms; location++)\r
279                 {\r
280                         if(uniformIndex[location].name == name &&\r
281                            uniformIndex[location].element == subscript)\r
282                         {\r
283                                 return location;\r
284                         }\r
285                 }\r
286 \r
287                 return -1;\r
288         }\r
289 \r
290         bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)\r
291         {\r
292                 if(location < 0 || location >= (int)uniformIndex.size())\r
293                 {\r
294                         return false;\r
295                 }\r
296 \r
297                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
298                 targetUniform->dirty = true;\r
299 \r
300                 int size = targetUniform->size();\r
301 \r
302                 if(size == 1 && count > 1)\r
303                 {\r
304                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
305                 }\r
306         \r
307                 count = std::min(size - (int)uniformIndex[location].element, count);\r
308 \r
309                 if(targetUniform->type == GL_FLOAT)\r
310                 {\r
311                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat),\r
312                                    v, sizeof(GLfloat) * count);\r
313                 }\r
314                 else if(targetUniform->type == GL_BOOL)\r
315                 {\r
316                         GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element;\r
317 \r
318                         for(int i = 0; i < count; i++)\r
319                         {\r
320                                 if(v[i] == 0.0f)\r
321                                 {\r
322                                         boolParams[i] = GL_FALSE;\r
323                                 }\r
324                                 else\r
325                                 {\r
326                                         boolParams[i] = GL_TRUE;\r
327                                 }\r
328                         }\r
329                 }\r
330                 else\r
331                 {\r
332                         return false;\r
333                 }\r
334 \r
335                 return true;\r
336         }\r
337 \r
338         bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)\r
339         {\r
340                 if(location < 0 || location >= (int)uniformIndex.size())\r
341                 {\r
342                         return false;\r
343                 }\r
344 \r
345                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
346                 targetUniform->dirty = true;\r
347 \r
348                 int size = targetUniform->size();\r
349 \r
350                 if(size == 1 && count > 1)\r
351                 {\r
352                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
353                 }\r
354         \r
355                 count = std::min(size - (int)uniformIndex[location].element, count);\r
356 \r
357                 if(targetUniform->type == GL_FLOAT_VEC2)\r
358                 {\r
359                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 2,\r
360                                    v, 2 * sizeof(GLfloat) * count);\r
361                 }\r
362                 else if(targetUniform->type == GL_BOOL_VEC2)\r
363                 {\r
364                         GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 2;\r
365 \r
366                         for(int i = 0; i < count * 2; i++)\r
367                         {\r
368                                 if(v[i] == 0.0f)\r
369                                 {\r
370                                         boolParams[i] = GL_FALSE;\r
371                                 }\r
372                                 else\r
373                                 {\r
374                                         boolParams[i] = GL_TRUE;\r
375                                 }\r
376                         }\r
377                 }\r
378                 else \r
379                 {\r
380                         return false;\r
381                 }\r
382 \r
383                 return true;\r
384         }\r
385 \r
386         bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)\r
387         {\r
388                 if(location < 0 || location >= (int)uniformIndex.size())\r
389                 {\r
390                         return false;\r
391                 }\r
392 \r
393                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
394                 targetUniform->dirty = true;\r
395 \r
396                 int size = targetUniform->size();\r
397 \r
398                 if(size == 1 && count > 1)\r
399                 {\r
400                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
401                 }\r
402         \r
403                 count = std::min(size - (int)uniformIndex[location].element, count);\r
404 \r
405                 if(targetUniform->type == GL_FLOAT_VEC3)\r
406                 {\r
407                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 3,\r
408                                    v, 3 * sizeof(GLfloat) * count);\r
409                 }\r
410                 else if(targetUniform->type == GL_BOOL_VEC3)\r
411                 {\r
412                         GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 3;\r
413 \r
414                         for(int i = 0; i < count * 3; i++)\r
415                         {\r
416                                 if(v[i] == 0.0f)\r
417                                 {\r
418                                         boolParams[i] = GL_FALSE;\r
419                                 }\r
420                                 else\r
421                                 {\r
422                                         boolParams[i] = GL_TRUE;\r
423                                 }\r
424                         }\r
425                 }\r
426                 else \r
427                 {\r
428                         return false;\r
429                 }\r
430 \r
431                 return true;\r
432         }\r
433 \r
434         bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)\r
435         {\r
436                 if(location < 0 || location >= (int)uniformIndex.size())\r
437                 {\r
438                         return false;\r
439                 }\r
440 \r
441                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
442                 targetUniform->dirty = true;\r
443 \r
444                 int size = targetUniform->size();\r
445 \r
446                 if(size == 1 && count > 1)\r
447                 {\r
448                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
449                 }\r
450         \r
451                 count = std::min(size - (int)uniformIndex[location].element, count);\r
452 \r
453                 if(targetUniform->type == GL_FLOAT_VEC4)\r
454                 {\r
455                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,\r
456                                    v, 4 * sizeof(GLfloat) * count);\r
457                 }\r
458                 else if(targetUniform->type == GL_BOOL_VEC4)\r
459                 {\r
460                         GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 4;\r
461 \r
462                         for(int i = 0; i < count * 4; i++)\r
463                         {\r
464                                 if(v[i] == 0.0f)\r
465                                 {\r
466                                         boolParams[i] = GL_FALSE;\r
467                                 }\r
468                                 else\r
469                                 {\r
470                                         boolParams[i] = GL_TRUE;\r
471                                 }\r
472                         }\r
473                 }\r
474                 else \r
475                 {\r
476                         return false;\r
477                 }\r
478 \r
479                 return true;\r
480         }\r
481 \r
482         bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)\r
483         {\r
484                 if(location < 0 || location >= (int)uniformIndex.size())\r
485                 {\r
486                         return false;\r
487                 }\r
488 \r
489                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
490                 targetUniform->dirty = true;\r
491 \r
492                 if(targetUniform->type != GL_FLOAT_MAT2)\r
493                 {\r
494                         return false;\r
495                 }\r
496 \r
497                 int size = targetUniform->size();\r
498 \r
499                 if(size == 1 && count > 1)\r
500                 {\r
501                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
502                 }\r
503 \r
504                 count = std::min(size - (int)uniformIndex[location].element, count);\r
505 \r
506                 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,\r
507                            value, 4 * sizeof(GLfloat) * count);\r
508 \r
509                 return true;\r
510         }\r
511 \r
512         bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)\r
513         {\r
514                 if(location < 0 || location >= (int)uniformIndex.size())\r
515                 {\r
516                         return false;\r
517                 }\r
518 \r
519                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
520                 targetUniform->dirty = true;\r
521 \r
522                 if(targetUniform->type != GL_FLOAT_MAT3)\r
523                 {\r
524                         return false;\r
525                 }\r
526 \r
527                 int size = targetUniform->size();\r
528 \r
529                 if(size == 1 && count > 1)\r
530                 {\r
531                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
532                 }\r
533 \r
534                 count = std::min(size - (int)uniformIndex[location].element, count);\r
535 \r
536                 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 9,\r
537                            value, 9 * sizeof(GLfloat) * count);\r
538 \r
539                 return true;\r
540         }\r
541 \r
542         bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)\r
543         {\r
544                 if(location < 0 || location >= (int)uniformIndex.size())\r
545                 {\r
546                         return false;\r
547                 }\r
548 \r
549                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
550                 targetUniform->dirty = true;\r
551 \r
552                 if(targetUniform->type != GL_FLOAT_MAT4)\r
553                 {\r
554                         return false;\r
555                 }\r
556 \r
557                 int size = targetUniform->size();\r
558 \r
559                 if(size == 1 && count > 1)\r
560                 {\r
561                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
562                 }\r
563 \r
564                 count = std::min(size - (int)uniformIndex[location].element, count);\r
565 \r
566                 memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 16,\r
567                            value, 16 * sizeof(GLfloat) * count);\r
568 \r
569                 return true;\r
570         }\r
571 \r
572         bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)\r
573         {\r
574                 if(location < 0 || location >= (int)uniformIndex.size())\r
575                 {\r
576                         return false;\r
577                 }\r
578 \r
579                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
580                 targetUniform->dirty = true;\r
581 \r
582                 int size = targetUniform->size();\r
583 \r
584                 if(size == 1 && count > 1)\r
585                 {\r
586                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
587                 }\r
588         \r
589                 count = std::min(size - (int)uniformIndex[location].element, count);\r
590 \r
591                 if(targetUniform->type == GL_INT ||\r
592                    targetUniform->type == GL_SAMPLER_2D ||\r
593                    targetUniform->type == GL_SAMPLER_CUBE ||\r
594            targetUniform->type == GL_SAMPLER_EXTERNAL_OES)\r
595                 {\r
596                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),\r
597                                    v, sizeof(GLint) * count);\r
598                 }\r
599                 else if(targetUniform->type == GL_BOOL)\r
600                 {\r
601                         GLboolean *boolParams = new GLboolean[count];\r
602 \r
603                         for(int i = 0; i < count; i++)\r
604                         {\r
605                                 if(v[i] == 0)\r
606                                 {\r
607                                         boolParams[i] = GL_FALSE;\r
608                                 }\r
609                                 else\r
610                                 {\r
611                                         boolParams[i] = GL_TRUE;\r
612                                 }\r
613                         }\r
614 \r
615                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),\r
616                                    boolParams, sizeof(GLboolean) * count);\r
617 \r
618                         delete[] boolParams;\r
619                 }\r
620                 else\r
621                 {\r
622                         return false;\r
623                 }\r
624 \r
625                 return true;\r
626         }\r
627 \r
628         bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)\r
629         {\r
630                 if(location < 0 || location >= (int)uniformIndex.size())\r
631                 {\r
632                         return false;\r
633                 }\r
634 \r
635                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
636                 targetUniform->dirty = true;\r
637 \r
638                 int size = targetUniform->size();\r
639 \r
640                 if(size == 1 && count > 1)\r
641                 {\r
642                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
643                 }\r
644         \r
645                 count = std::min(size - (int)uniformIndex[location].element, count);\r
646 \r
647                 if(targetUniform->type == GL_INT_VEC2)\r
648                 {\r
649                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 2,\r
650                                    v, 2 * sizeof(GLint) * count);\r
651                 }\r
652                 else if(targetUniform->type == GL_BOOL_VEC2)\r
653                 {\r
654                         GLboolean *boolParams = new GLboolean[count * 2];\r
655 \r
656                         for(int i = 0; i < count * 2; i++)\r
657                         {\r
658                                 if(v[i] == 0)\r
659                                 {\r
660                                         boolParams[i] = GL_FALSE;\r
661                                 }\r
662                                 else\r
663                                 {\r
664                                         boolParams[i] = GL_TRUE;\r
665                                 }\r
666                         }\r
667 \r
668                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 2,\r
669                                    boolParams, 2 * sizeof(GLboolean) * count);\r
670 \r
671                         delete[] boolParams;\r
672                 }\r
673                 else\r
674                 {\r
675                         return false;\r
676                 }\r
677 \r
678                 return true;\r
679         }\r
680 \r
681         bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)\r
682         {\r
683                 if(location < 0 || location >= (int)uniformIndex.size())\r
684                 {\r
685                         return false;\r
686                 }\r
687 \r
688                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
689                 targetUniform->dirty = true;\r
690 \r
691                 int size = targetUniform->size();\r
692 \r
693                 if(size == 1 && count > 1)\r
694                 {\r
695                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
696                 }\r
697         \r
698                 count = std::min(size - (int)uniformIndex[location].element, count);\r
699 \r
700                 if(targetUniform->type == GL_INT_VEC3)\r
701                 {\r
702                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 3,\r
703                                    v, 3 * sizeof(GLint) * count);\r
704                 }\r
705                 else if(targetUniform->type == GL_BOOL_VEC3)\r
706                 {\r
707                         GLboolean *boolParams = new GLboolean[count * 3];\r
708 \r
709                         for(int i = 0; i < count * 3; i++)\r
710                         {\r
711                                 if(v[i] == 0)\r
712                                 {\r
713                                         boolParams[i] = GL_FALSE;\r
714                                 }\r
715                                 else\r
716                                 {\r
717                                         boolParams[i] = GL_TRUE;\r
718                                 }\r
719                         }\r
720 \r
721                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 3,\r
722                                    boolParams, 3 * sizeof(GLboolean) * count);\r
723 \r
724                         delete[] boolParams;\r
725                 }\r
726                 else\r
727                 {\r
728                         return false;\r
729                 }\r
730 \r
731                 return true;\r
732         }\r
733 \r
734         bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)\r
735         {\r
736                 if(location < 0 || location >= (int)uniformIndex.size())\r
737                 {\r
738                         return false;\r
739                 }\r
740 \r
741                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
742                 targetUniform->dirty = true;\r
743 \r
744                 int size = targetUniform->size();\r
745 \r
746                 if(size == 1 && count > 1)\r
747                 {\r
748                         return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
749                 }\r
750         \r
751                 count = std::min(size - (int)uniformIndex[location].element, count);\r
752 \r
753                 if(targetUniform->type == GL_INT_VEC4)\r
754                 {\r
755                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 4,\r
756                                    v, 4 * sizeof(GLint) * count);\r
757                 }\r
758                 else if(targetUniform->type == GL_BOOL_VEC4)\r
759                 {\r
760                         GLboolean *boolParams = new GLboolean[count * 4];\r
761 \r
762                         for(int i = 0; i < count * 4; i++)\r
763                         {\r
764                                 if(v[i] == 0)\r
765                                 {\r
766                                         boolParams[i] = GL_FALSE;\r
767                                 }\r
768                                 else\r
769                                 {\r
770                                         boolParams[i] = GL_TRUE;\r
771                                 }\r
772                         }\r
773 \r
774                         memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 4,\r
775                                    boolParams, 4 * sizeof(GLboolean) * count);\r
776 \r
777                         delete[] boolParams;\r
778                 }\r
779                 else\r
780                 {\r
781                         return false;\r
782                 }\r
783 \r
784                 return true;\r
785         }\r
786 \r
787         bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)\r
788         {\r
789                 if(location < 0 || location >= (int)uniformIndex.size())\r
790                 {\r
791                         return false;\r
792                 }\r
793 \r
794                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
795                 unsigned int count = UniformComponentCount(targetUniform->type);\r
796 \r
797                 // Sized query - ensure the provided buffer is large enough\r
798                 if(bufSize && *bufSize < count * sizeof(GLfloat))\r
799                 {\r
800                         return false;\r
801                 }\r
802 \r
803                 switch (UniformComponentType(targetUniform->type))\r
804                 {\r
805                   case GL_BOOL:\r
806                         {\r
807                                 GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;\r
808 \r
809                                 for(unsigned int i = 0; i < count; i++)\r
810                                 {\r
811                                         params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;\r
812                                 }\r
813                         }\r
814                         break;\r
815                   case GL_FLOAT:\r
816                         memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),\r
817                                    count * sizeof(GLfloat));\r
818                         break;\r
819                   case GL_INT:\r
820                         {\r
821                                 GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;\r
822 \r
823                                 for(unsigned int i = 0; i < count; i++)\r
824                                 {\r
825                                         params[i] = (float)intParams[i];\r
826                                 }\r
827                         }\r
828                         break;\r
829                   default: UNREACHABLE();\r
830                 }\r
831 \r
832                 return true;\r
833         }\r
834 \r
835         bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)\r
836         {\r
837                 if(location < 0 || location >= (int)uniformIndex.size())\r
838                 {\r
839                         return false;\r
840                 }\r
841 \r
842                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
843                 unsigned int count = UniformComponentCount(targetUniform->type);\r
844 \r
845                 // Sized query - ensure the provided buffer is large enough\r
846                 if(bufSize && *bufSize < count * sizeof(GLint))\r
847                 {\r
848                         return false;\r
849                 }\r
850 \r
851                 switch (UniformComponentType(targetUniform->type))\r
852                 {\r
853                   case GL_BOOL:\r
854                         {\r
855                                 GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;\r
856 \r
857                                 for(unsigned int i = 0; i < count; i++)\r
858                                 {\r
859                                         params[i] = (GLint)boolParams[i];\r
860                                 }\r
861                         }\r
862                         break;\r
863                   case GL_FLOAT:\r
864                         {\r
865                                 GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;\r
866 \r
867                                 for(unsigned int i = 0; i < count; i++)\r
868                                 {\r
869                                         params[i] = (GLint)floatParams[i];\r
870                                 }\r
871                         }\r
872                         break;\r
873                   case GL_INT:\r
874                         memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),\r
875                                    count * sizeof(GLint));\r
876                         break;\r
877                   default: UNREACHABLE();\r
878                 }\r
879 \r
880                 return true;\r
881         }\r
882 \r
883         void Program::dirtyAllUniforms()\r
884         {\r
885                 unsigned int numUniforms = uniforms.size();\r
886                 for(unsigned int index = 0; index < numUniforms; index++)\r
887                 {\r
888                         uniforms[index]->dirty = true;\r
889                 }\r
890         }\r
891 \r
892         // Applies all the uniforms set for this program object to the device\r
893         void Program::applyUniforms()\r
894         {\r
895                 unsigned int numUniforms = uniformIndex.size();\r
896                 for(unsigned int location = 0; location < numUniforms; location++)\r
897                 {\r
898                         if(uniformIndex[location].element != 0)\r
899                         {\r
900                                 continue;\r
901                         }\r
902 \r
903                         Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
904 \r
905                         if(targetUniform->dirty)\r
906                         {\r
907                                 int size = targetUniform->size();\r
908                                 GLfloat *f = (GLfloat*)targetUniform->data;\r
909                                 GLint *i = (GLint*)targetUniform->data;\r
910                                 GLboolean *b = (GLboolean*)targetUniform->data;\r
911 \r
912                                 switch(targetUniform->type)\r
913                                 {\r
914                                   case GL_BOOL:       applyUniform1bv(location, size, b);       break;\r
915                                   case GL_BOOL_VEC2:  applyUniform2bv(location, size, b);       break;\r
916                                   case GL_BOOL_VEC3:  applyUniform3bv(location, size, b);       break;\r
917                                   case GL_BOOL_VEC4:  applyUniform4bv(location, size, b);       break;\r
918                                   case GL_FLOAT:      applyUniform1fv(location, size, f);       break;\r
919                                   case GL_FLOAT_VEC2: applyUniform2fv(location, size, f);       break;\r
920                                   case GL_FLOAT_VEC3: applyUniform3fv(location, size, f);       break;\r
921                                   case GL_FLOAT_VEC4: applyUniform4fv(location, size, f);       break;\r
922                                   case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, size, f); break;\r
923                                   case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, size, f); break;\r
924                                   case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, size, f); break;\r
925                                   case GL_SAMPLER_2D:\r
926                                   case GL_SAMPLER_CUBE:\r
927                   case GL_SAMPLER_EXTERNAL_OES:\r
928                                   case GL_INT:        applyUniform1iv(location, size, i);       break;\r
929                                   case GL_INT_VEC2:   applyUniform2iv(location, size, i);       break;\r
930                                   case GL_INT_VEC3:   applyUniform3iv(location, size, i);       break;\r
931                                   case GL_INT_VEC4:   applyUniform4iv(location, size, i);       break;\r
932                                   default:\r
933                                         UNREACHABLE();\r
934                                 }\r
935 \r
936                                 targetUniform->dirty = false;\r
937                         }\r
938                 }\r
939         }\r
940 \r
941         // Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111\r
942         // Returns the number of used varying registers, or -1 if unsuccesful\r
943         int Program::packVaryings(const Varying *packing[][4])\r
944         {\r
945                 for(VaryingList::iterator varying = fragmentShader->varyings.begin(); varying != fragmentShader->varyings.end(); varying++)\r
946                 {\r
947                         int n = VariableRowCount(varying->type) * varying->size();\r
948                         int m = VariableColumnCount(varying->type);\r
949                         bool success = false;\r
950 \r
951                         if(m == 2 || m == 3 || m == 4)\r
952                         {\r
953                                 for(int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)\r
954                                 {\r
955                                         bool available = true;\r
956 \r
957                                         for(int y = 0; y < n && available; y++)\r
958                                         {\r
959                                                 for(int x = 0; x < m && available; x++)\r
960                                                 {\r
961                                                         if(packing[r + y][x])\r
962                                                         {\r
963                                                                 available = false;\r
964                                                         }\r
965                                                 }\r
966                                         }\r
967 \r
968                                         if(available)\r
969                                         {\r
970                                                 varying->reg = r;\r
971                                                 varying->col = 0;\r
972 \r
973                                                 for(int y = 0; y < n; y++)\r
974                                                 {\r
975                                                         for(int x = 0; x < m; x++)\r
976                                                         {\r
977                                                                 packing[r + y][x] = &*varying;\r
978                                                         }\r
979                                                 }\r
980 \r
981                                                 success = true;\r
982                                         }\r
983                                 }\r
984 \r
985                                 if(!success && m == 2)\r
986                                 {\r
987                                         for(int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)\r
988                                         {\r
989                                                 bool available = true;\r
990 \r
991                                                 for(int y = 0; y < n && available; y++)\r
992                                                 {\r
993                                                         for(int x = 2; x < 4 && available; x++)\r
994                                                         {\r
995                                                                 if(packing[r + y][x])\r
996                                                                 {\r
997                                                                         available = false;\r
998                                                                 }\r
999                                                         }\r
1000                                                 }\r
1001 \r
1002                                                 if(available)\r
1003                                                 {\r
1004                                                         varying->reg = r;\r
1005                                                         varying->col = 2;\r
1006 \r
1007                                                         for(int y = 0; y < n; y++)\r
1008                                                         {\r
1009                                                                 for(int x = 2; x < 4; x++)\r
1010                                                                 {\r
1011                                                                         packing[r + y][x] = &*varying;\r
1012                                                                 }\r
1013                                                         }\r
1014 \r
1015                                                         success = true;\r
1016                                                 }\r
1017                                         }\r
1018                                 }\r
1019                         }\r
1020                         else if(m == 1)\r
1021                         {\r
1022                                 int space[4] = {0};\r
1023 \r
1024                                 for(int y = 0; y < MAX_VARYING_VECTORS; y++)\r
1025                                 {\r
1026                                         for(int x = 0; x < 4; x++)\r
1027                                         {\r
1028                                                 space[x] += packing[y][x] ? 0 : 1;\r
1029                                         }\r
1030                                 }\r
1031 \r
1032                                 int column = 0;\r
1033 \r
1034                                 for(int x = 0; x < 4; x++)\r
1035                                 {\r
1036                                         if(space[x] >= n && space[x] < space[column])\r
1037                                         {\r
1038                                                 column = x;\r
1039                                         }\r
1040                                 }\r
1041 \r
1042                                 if(space[column] >= n)\r
1043                                 {\r
1044                                         for(int r = 0; r < MAX_VARYING_VECTORS; r++)\r
1045                                         {\r
1046                                                 if(!packing[r][column])\r
1047                                                 {\r
1048                                                         varying->reg = r;\r
1049 \r
1050                                                         for(int y = r; y < r + n; y++)\r
1051                                                         {\r
1052                                                                 packing[y][column] = &*varying;\r
1053                                                         }\r
1054 \r
1055                                                         break;\r
1056                                                 }\r
1057                                         }\r
1058 \r
1059                                         varying->col = column;\r
1060 \r
1061                                         success = true;\r
1062                                 }\r
1063                         }\r
1064                         else UNREACHABLE();\r
1065 \r
1066                         if(!success)\r
1067                         {\r
1068                                 appendToInfoLog("Could not pack varying %s", varying->name.c_str());\r
1069 \r
1070                                 return -1;\r
1071                         }\r
1072                 }\r
1073 \r
1074                 // Return the number of used registers\r
1075                 int registers = 0;\r
1076 \r
1077                 for(int r = 0; r < MAX_VARYING_VECTORS; r++)\r
1078                 {\r
1079                         if(packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])\r
1080                         {\r
1081                                 registers++;\r
1082                         }\r
1083                 }\r
1084 \r
1085                 return registers;\r
1086         }\r
1087 \r
1088         bool Program::linkVaryings()\r
1089         {\r
1090                 for(VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); input++)\r
1091                 {\r
1092                         bool matched = false;\r
1093 \r
1094                         for(VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); output++)\r
1095                         {\r
1096                                 if(output->name == input->name)\r
1097                                 {\r
1098                                         if(output->type != input->type || output->size() != input->size())\r
1099                                         {\r
1100                                                 appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());\r
1101 \r
1102                                                 return false;\r
1103                                         }\r
1104 \r
1105                                         matched = true;\r
1106                                         break;\r
1107                                 }\r
1108                         }\r
1109 \r
1110                         if(!matched)\r
1111                         {\r
1112                                 appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());\r
1113 \r
1114                                 return false;\r
1115                         }\r
1116                 }\r
1117 \r
1118                 VaryingList &psVaryings = fragmentShader->varyings;\r
1119                 VaryingList &vsVaryings = vertexShader->varyings;\r
1120 \r
1121                 for(VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); output++)\r
1122                 {\r
1123                         for(VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); input++)\r
1124                         {\r
1125                                 if(output->name == input->name)\r
1126                                 {\r
1127                                         int in = input->reg;\r
1128                                         int out = output->reg;\r
1129                                         int components = VariableColumnCount(output->type);\r
1130                                         int registers = VariableRowCount(output->type) * output->size();\r
1131 \r
1132                                         ASSERT(in >= 0);\r
1133 \r
1134                                         if(in + registers > MAX_VARYING_VECTORS)\r
1135                                         {\r
1136                                                 appendToInfoLog("Too many varyings");\r
1137                                                 return false;\r
1138                                         }\r
1139 \r
1140                                         if(out >= 0)\r
1141                                         {\r
1142                                                 if(out + registers > MAX_VARYING_VECTORS)\r
1143                                                 {\r
1144                                                         appendToInfoLog("Too many varyings");\r
1145                                                         return false;\r
1146                                                 }\r
1147 \r
1148                                                 for(int i = 0; i < registers; i++)\r
1149                                                 {\r
1150                                                         if(components >= 1) vertexBinary->output[out + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
1151                                                         if(components >= 2) vertexBinary->output[out + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
1152                                                         if(components >= 3) vertexBinary->output[out + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
1153                                                         if(components >= 4) vertexBinary->output[out + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
1154                                                 }\r
1155                                         }\r
1156                                         else   // Vertex varying is declared but not written to\r
1157                                         {\r
1158                                                 for(int i = 0; i < registers; i++)\r
1159                                                 {\r
1160                                                         if(components >= 1) pixelBinary->semantic[in + i][0] = sw::Shader::Semantic();\r
1161                                                         if(components >= 2) pixelBinary->semantic[in + i][1] = sw::Shader::Semantic();\r
1162                                                         if(components >= 3) pixelBinary->semantic[in + i][2] = sw::Shader::Semantic();\r
1163                                                         if(components >= 4) pixelBinary->semantic[in + i][3] = sw::Shader::Semantic();                                  \r
1164                                                 }\r
1165                                         }\r
1166 \r
1167                                         break;\r
1168                                 }\r
1169                         }\r
1170                 }\r
1171 \r
1172                 return true;\r
1173         }\r
1174 \r
1175         // Links the code of the vertex and pixel shader by matching up their varyings,\r
1176         // compiling them into binaries, determining the attribute mappings, and collecting\r
1177         // a list of uniforms\r
1178         void Program::link()\r
1179         {\r
1180                 unlink();\r
1181 \r
1182                 if(!fragmentShader || !fragmentShader->isCompiled())\r
1183                 {\r
1184                         return;\r
1185                 }\r
1186 \r
1187                 if(!vertexShader || !vertexShader->isCompiled())\r
1188                 {\r
1189                         return;\r
1190                 }\r
1191 \r
1192                 vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());\r
1193                 pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());\r
1194                         \r
1195                 if(!linkVaryings())\r
1196                 {\r
1197                         return;\r
1198                 }\r
1199 \r
1200                 if(!linkAttributes())\r
1201                 {\r
1202                         return;\r
1203                 }\r
1204 \r
1205                 if(!linkUniforms(fragmentShader))\r
1206                 {\r
1207                         return;\r
1208                 }\r
1209 \r
1210                 if(!linkUniforms(vertexShader))\r
1211                 {\r
1212                         return;\r
1213                 }\r
1214 \r
1215                 linked = true;   // Success\r
1216         }\r
1217 \r
1218         // Determines the mapping between GL attributes and vertex stream usage indices\r
1219         bool Program::linkAttributes()\r
1220         {\r
1221                 unsigned int usedLocations = 0;\r
1222 \r
1223                 // Link attributes that have a binding location\r
1224                 for(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)\r
1225                 {\r
1226                         int location = getAttributeBinding(attribute->name);\r
1227 \r
1228                         if(location != -1)   // Set by glBindAttribLocation\r
1229                         {\r
1230                                 if(!linkedAttribute[location].name.empty())\r
1231                                 {\r
1232                                         // Multiple active attributes bound to the same location; not an error\r
1233                                 }\r
1234 \r
1235                                 linkedAttribute[location] = *attribute;\r
1236 \r
1237                                 int rows = VariableRowCount(attribute->type);\r
1238 \r
1239                                 if(rows + location > MAX_VERTEX_ATTRIBS)\r
1240                                 {\r
1241                                         appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);\r
1242                                         return false;\r
1243                                 }\r
1244 \r
1245                                 for(int i = 0; i < rows; i++)\r
1246                                 {\r
1247                                         usedLocations |= 1 << (location + i);\r
1248                                 }\r
1249                         }\r
1250                 }\r
1251 \r
1252                 // Link attributes that don't have a binding location\r
1253                 for(sh::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)\r
1254                 {\r
1255                         int location = getAttributeBinding(attribute->name);\r
1256 \r
1257                         if(location == -1)   // Not set by glBindAttribLocation\r
1258                         {\r
1259                                 int rows = VariableRowCount(attribute->type);\r
1260                                 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);\r
1261 \r
1262                                 if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)\r
1263                                 {\r
1264                                         appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());\r
1265                                         return false;   // Fail to link\r
1266                                 }\r
1267 \r
1268                                 linkedAttribute[availableIndex] = *attribute;\r
1269                         }\r
1270                 }\r
1271 \r
1272                 for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )\r
1273                 {\r
1274                         int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);\r
1275                         int rows = std::max(VariableRowCount(linkedAttribute[attributeIndex].type), 1);\r
1276 \r
1277                         for(int r = 0; r < rows; r++)\r
1278                         {\r
1279                                 attributeStream[attributeIndex++] = index++;\r
1280                         }\r
1281                 }\r
1282 \r
1283                 return true;\r
1284         }\r
1285 \r
1286         int Program::getAttributeBinding(const std::string &name)\r
1287         {\r
1288                 for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)\r
1289                 {\r
1290                         if(attributeBinding[location].find(name) != attributeBinding[location].end())\r
1291                         {\r
1292                                 return location;\r
1293                         }\r
1294                 }\r
1295 \r
1296                 return -1;\r
1297         }\r
1298 \r
1299         bool Program::linkUniforms(Shader *shader)\r
1300         {\r
1301                 const sh::ActiveUniforms &activeUniforms = shader->activeUniforms;\r
1302 \r
1303                 for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)\r
1304                 {\r
1305                         const sh::Uniform &uniform = activeUniforms[uniformIndex];\r
1306 \r
1307                         if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex))\r
1308                         {\r
1309                                 return false;\r
1310                         }\r
1311                 }\r
1312 \r
1313                 return true;\r
1314         }\r
1315 \r
1316         bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)\r
1317         {\r
1318                 if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES)\r
1319             {\r
1320                         int index = registerIndex;\r
1321                         \r
1322                         do\r
1323                         {\r
1324                                 if(shader == GL_VERTEX_SHADER)\r
1325                                 {\r
1326                                         if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)\r
1327                                         {\r
1328                                                 samplersVS[index].active = true;\r
1329                                                 samplersVS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;\r
1330                                                 samplersVS[index].logicalTextureUnit = 0;\r
1331                                         }\r
1332                                         else\r
1333                                         {\r
1334                                            appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);\r
1335                                            return false;\r
1336                                         }\r
1337                                 }\r
1338                                 else if(shader == GL_FRAGMENT_SHADER)\r
1339                                 {\r
1340                                         if(index < MAX_TEXTURE_IMAGE_UNITS)\r
1341                                         {\r
1342                                                 samplersPS[index].active = true;\r
1343                                                 samplersPS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;\r
1344                                                 samplersPS[index].logicalTextureUnit = 0;\r
1345                                         }\r
1346                                         else\r
1347                                         {\r
1348                                                 appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);\r
1349                                                 return false;\r
1350                                         }\r
1351                                 }\r
1352                                 else UNREACHABLE();\r
1353 \r
1354                                 index++;\r
1355                         }\r
1356                         while(index < registerIndex + arraySize);\r
1357             }\r
1358 \r
1359                 Uniform *uniform = 0;\r
1360                 GLint location = getUniformLocation(name);\r
1361 \r
1362                 if(location >= 0)   // Previously defined, types must match\r
1363                 {\r
1364                         uniform = uniforms[uniformIndex[location].index];\r
1365 \r
1366                         if(uniform->type != type)\r
1367                         {\r
1368                                 appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());\r
1369                                 return false;\r
1370                         }\r
1371 \r
1372                         if(uniform->precision != precision)\r
1373                         {\r
1374                                 appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());\r
1375                                 return false;\r
1376                         }\r
1377                 }\r
1378                 else\r
1379                 {\r
1380                         uniform = new Uniform(type, precision, name, arraySize);\r
1381                 }\r
1382 \r
1383                 if(!uniform)\r
1384                 {\r
1385                         return false;\r
1386                 }\r
1387 \r
1388                 if(shader == GL_VERTEX_SHADER)\r
1389                 {\r
1390                         uniform->vsRegisterIndex = registerIndex;\r
1391                 }\r
1392                 else if(shader == GL_FRAGMENT_SHADER)\r
1393                 {\r
1394                         uniform->psRegisterIndex = registerIndex;\r
1395                 }\r
1396                 else UNREACHABLE();\r
1397 \r
1398                 if(location == -1)   // Not previously defined\r
1399                 {\r
1400                         uniforms.push_back(uniform);\r
1401                         unsigned int index = uniforms.size() - 1;\r
1402 \r
1403                         for(unsigned int i = 0; i < uniform->size(); i++)\r
1404                         {\r
1405                                 uniformIndex.push_back(UniformLocation(name, i, index));\r
1406                         }\r
1407                 }\r
1408 \r
1409                 if(shader == GL_VERTEX_SHADER)\r
1410                 {\r
1411                         if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)\r
1412                         {\r
1413                                 appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);\r
1414                                 return false;\r
1415                         }\r
1416                 }\r
1417                 else if(shader == GL_FRAGMENT_SHADER)\r
1418                 {\r
1419                         if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)\r
1420                         {\r
1421                                 appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);\r
1422                                 return false;\r
1423                         }\r
1424                 }\r
1425                 else UNREACHABLE();\r
1426 \r
1427                 return true;\r
1428         }\r
1429 \r
1430         bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)\r
1431         {\r
1432                 int vector[MAX_UNIFORM_VECTORS][4];\r
1433 \r
1434                 for(int i = 0; i < count; i++)\r
1435                 {\r
1436                         vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1437                         vector[i][1] = 0;\r
1438                         vector[i][2] = 0;\r
1439                         vector[i][3] = 0;\r
1440 \r
1441                         v += 1;\r
1442                 }\r
1443 \r
1444                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1445 \r
1446                 if(targetUniform->psRegisterIndex != -1)\r
1447                 {\r
1448                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1449                 }\r
1450 \r
1451                 if(targetUniform->vsRegisterIndex != -1)\r
1452                 {\r
1453                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1454                 }\r
1455 \r
1456                 return true;\r
1457         }\r
1458 \r
1459         bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)\r
1460         {\r
1461                 int vector[MAX_UNIFORM_VECTORS][4];\r
1462 \r
1463                 for(int i = 0; i < count; i++)\r
1464                 {\r
1465                         vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1466                         vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1467                         vector[i][2] = 0;\r
1468                         vector[i][3] = 0;\r
1469 \r
1470                         v += 2;\r
1471                 }\r
1472 \r
1473                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1474 \r
1475                 if(targetUniform->psRegisterIndex != -1)\r
1476                 {\r
1477                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1478                 }\r
1479 \r
1480                 if(targetUniform->vsRegisterIndex != -1)\r
1481                 {\r
1482                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1483                 }\r
1484 \r
1485                 return true;\r
1486         }\r
1487 \r
1488         bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)\r
1489         {\r
1490                 int vector[MAX_UNIFORM_VECTORS][4];\r
1491 \r
1492                 for(int i = 0; i < count; i++)\r
1493                 {\r
1494                         vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1495                         vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1496                         vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1497                         vector[i][3] = 0;\r
1498 \r
1499                         v += 3;\r
1500                 }\r
1501 \r
1502                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1503 \r
1504                 if(targetUniform->psRegisterIndex != -1)\r
1505                 {\r
1506                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1507                 }\r
1508 \r
1509                 if(targetUniform->vsRegisterIndex != -1)\r
1510                 {\r
1511                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1512                 }\r
1513 \r
1514                 return true;\r
1515         }\r
1516 \r
1517         bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)\r
1518         {\r
1519                 int vector[MAX_UNIFORM_VECTORS][4];\r
1520 \r
1521                 for(int i = 0; i < count; i++)\r
1522                 {\r
1523                         vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1524                         vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1525                         vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1526                         vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
1527 \r
1528                         v += 4;\r
1529                 }\r
1530 \r
1531                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1532 \r
1533                 if(targetUniform->psRegisterIndex != -1)\r
1534                 {\r
1535                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1536                 }\r
1537 \r
1538                 if(targetUniform->vsRegisterIndex != -1)\r
1539                 {\r
1540                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1541                 }\r
1542 \r
1543                 return true;\r
1544         }\r
1545 \r
1546         bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)\r
1547         {\r
1548                 float vector[MAX_UNIFORM_VECTORS][4];\r
1549 \r
1550                 for(int i = 0; i < count; i++)\r
1551                 {\r
1552                         vector[i][0] = v[0];\r
1553                         vector[i][1] = 0;\r
1554                         vector[i][2] = 0;\r
1555                         vector[i][3] = 0;\r
1556 \r
1557                         v += 1;\r
1558                 }\r
1559 \r
1560                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1561 \r
1562                 if(targetUniform->psRegisterIndex != -1)\r
1563                 {\r
1564                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1565                 }\r
1566 \r
1567                 if(targetUniform->vsRegisterIndex != -1)\r
1568                 {\r
1569                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1570                 }\r
1571 \r
1572                 return true;\r
1573         }\r
1574 \r
1575         bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)\r
1576         {\r
1577                 float vector[MAX_UNIFORM_VECTORS][4];\r
1578 \r
1579                 for(int i = 0; i < count; i++)\r
1580                 {\r
1581                         vector[i][0] = v[0];\r
1582                         vector[i][1] = v[1];\r
1583                         vector[i][2] = 0;\r
1584                         vector[i][3] = 0;\r
1585 \r
1586                         v += 2;\r
1587                 }\r
1588 \r
1589                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1590 \r
1591                 if(targetUniform->psRegisterIndex != -1)\r
1592                 {\r
1593                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1594                 }\r
1595 \r
1596                 if(targetUniform->vsRegisterIndex != -1)\r
1597                 {\r
1598                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1599                 }\r
1600 \r
1601                 return true;\r
1602         }\r
1603 \r
1604         bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)\r
1605         {\r
1606                 float vector[MAX_UNIFORM_VECTORS][4];\r
1607 \r
1608                 for(int i = 0; i < count; i++)\r
1609                 {\r
1610                         vector[i][0] = v[0];\r
1611                         vector[i][1] = v[1];\r
1612                         vector[i][2] = v[2];\r
1613                         vector[i][3] = 0;\r
1614 \r
1615                         v += 3;\r
1616                 }\r
1617 \r
1618                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1619 \r
1620                 if(targetUniform->psRegisterIndex != -1)\r
1621                 {\r
1622                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1623                 }\r
1624 \r
1625                 if(targetUniform->vsRegisterIndex != -1)\r
1626                 {\r
1627                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1628                 }\r
1629 \r
1630                 return true;\r
1631         }\r
1632 \r
1633         bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)\r
1634         {\r
1635                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1636 \r
1637                 if(targetUniform->psRegisterIndex != -1)\r
1638                 {\r
1639                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)v, targetUniform->registerCount());\r
1640                 }\r
1641 \r
1642                 if(targetUniform->vsRegisterIndex != -1)\r
1643                 {\r
1644                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)v, targetUniform->registerCount());\r
1645                 }\r
1646 \r
1647                 return true;\r
1648         }\r
1649 \r
1650         bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)\r
1651         {\r
1652                 float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];\r
1653 \r
1654                 for(int i = 0; i < count; i++)\r
1655                 {\r
1656                         matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = 0; matrix[i][0][3] = 0;\r
1657                         matrix[i][1][0] = value[2];     matrix[i][1][1] = value[3];     matrix[i][1][2] = 0; matrix[i][1][3] = 0;\r
1658 \r
1659                         value += 4;\r
1660                 }\r
1661 \r
1662                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1663 \r
1664                 if(targetUniform->psRegisterIndex != -1)\r
1665                 {\r
1666                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
1667                 }\r
1668 \r
1669                 if(targetUniform->vsRegisterIndex != -1)\r
1670                 {\r
1671                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
1672                 }\r
1673 \r
1674                 return true;\r
1675         }\r
1676 \r
1677         bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)\r
1678         {\r
1679                 float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];\r
1680 \r
1681                 for(int i = 0; i < count; i++)\r
1682                 {\r
1683                         matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2];     matrix[i][0][3] = 0;\r
1684                         matrix[i][1][0] = value[3];     matrix[i][1][1] = value[4];     matrix[i][1][2] = value[5];     matrix[i][1][3] = 0;\r
1685                         matrix[i][2][0] = value[6];     matrix[i][2][1] = value[7];     matrix[i][2][2] = value[8];     matrix[i][2][3] = 0;\r
1686 \r
1687                         value += 9;\r
1688                 }\r
1689 \r
1690                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1691 \r
1692                 if(targetUniform->psRegisterIndex != -1)\r
1693                 {\r
1694                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
1695                 }\r
1696 \r
1697                 if(targetUniform->vsRegisterIndex != -1)\r
1698                 {       \r
1699                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
1700                 }\r
1701 \r
1702                 return true;\r
1703         }\r
1704 \r
1705         bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)\r
1706         {\r
1707                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1708         \r
1709                 if(targetUniform->psRegisterIndex != -1)\r
1710                 {\r
1711                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)value, targetUniform->registerCount());\r
1712                 }\r
1713 \r
1714                 if(targetUniform->vsRegisterIndex != -1)\r
1715                 {\r
1716                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)value, targetUniform->registerCount());\r
1717                 }\r
1718 \r
1719                 return true;\r
1720         }\r
1721 \r
1722         bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)\r
1723         {\r
1724                 float vector[MAX_UNIFORM_VECTORS][4];\r
1725 \r
1726                 for(int i = 0; i < count; i++)\r
1727                 {\r
1728                         vector[i][0] = (float)v[i];\r
1729                         vector[i][1] = 0;\r
1730                         vector[i][2] = 0;\r
1731                         vector[i][3] = 0;\r
1732                 }\r
1733 \r
1734                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1735 \r
1736                 if(targetUniform->psRegisterIndex != -1)\r
1737                 {\r
1738             if(targetUniform->type == GL_SAMPLER_2D ||\r
1739                targetUniform->type == GL_SAMPLER_CUBE ||\r
1740                targetUniform->type == GL_SAMPLER_EXTERNAL_OES)\r
1741                         {\r
1742                                 for(int i = 0; i < count; i++)\r
1743                                 {\r
1744                                         unsigned int samplerIndex = targetUniform->psRegisterIndex + i;\r
1745 \r
1746                                         if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)\r
1747                                         {\r
1748                                                 ASSERT(samplersPS[samplerIndex].active);\r
1749                                                 samplersPS[samplerIndex].logicalTextureUnit = v[i];\r
1750                                         }\r
1751                                 }\r
1752                         }\r
1753                         else\r
1754                         {\r
1755                                 device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1756                         }\r
1757                 }\r
1758 \r
1759                 if(targetUniform->vsRegisterIndex != -1)\r
1760                 {\r
1761                         if(targetUniform->type == GL_SAMPLER_2D ||\r
1762                targetUniform->type == GL_SAMPLER_CUBE ||\r
1763                targetUniform->type == GL_SAMPLER_EXTERNAL_OES)\r
1764                         {\r
1765                                 for(int i = 0; i < count; i++)\r
1766                                 {\r
1767                                         unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;\r
1768 \r
1769                                         if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)\r
1770                                         {\r
1771                                                 ASSERT(samplersVS[samplerIndex].active);\r
1772                                                 samplersVS[samplerIndex].logicalTextureUnit = v[i];\r
1773                                         }\r
1774                                 }\r
1775                         }\r
1776                         else\r
1777                         {\r
1778                                 device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1779                         }\r
1780                 }\r
1781 \r
1782                 return true;\r
1783         }\r
1784 \r
1785         bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)\r
1786         {\r
1787                 float vector[MAX_UNIFORM_VECTORS][4];\r
1788 \r
1789                 for(int i = 0; i < count; i++)\r
1790                 {\r
1791                         vector[i][0] = (float)v[0];\r
1792                         vector[i][1] = (float)v[1];\r
1793                         vector[i][2] = 0;\r
1794                         vector[i][3] = 0;\r
1795 \r
1796                         v += 2;\r
1797                 }\r
1798 \r
1799                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1800 \r
1801                 if(targetUniform->psRegisterIndex != -1)\r
1802                 {\r
1803                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1804                 }\r
1805 \r
1806                 if(targetUniform->vsRegisterIndex != -1)\r
1807                 {\r
1808                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1809                 }\r
1810 \r
1811                 return true;\r
1812         }\r
1813 \r
1814         bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)\r
1815         {\r
1816                 float vector[MAX_UNIFORM_VECTORS][4];\r
1817 \r
1818                 for(int i = 0; i < count; i++)\r
1819                 {\r
1820                         vector[i][0] = (float)v[0];\r
1821                         vector[i][1] = (float)v[1];\r
1822                         vector[i][2] = (float)v[2];\r
1823                         vector[i][3] = 0;\r
1824 \r
1825                         v += 3;\r
1826                 }\r
1827 \r
1828                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1829 \r
1830                 if(targetUniform->psRegisterIndex != -1)\r
1831                 {\r
1832                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1833                 }\r
1834 \r
1835                 if(targetUniform->vsRegisterIndex != -1)\r
1836                 {\r
1837                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1838                 }\r
1839 \r
1840                 return true;\r
1841         }\r
1842 \r
1843         bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)\r
1844         {\r
1845                 float vector[MAX_UNIFORM_VECTORS][4];\r
1846 \r
1847                 for(int i = 0; i < count; i++)\r
1848                 {\r
1849                         vector[i][0] = (float)v[0];\r
1850                         vector[i][1] = (float)v[1];\r
1851                         vector[i][2] = (float)v[2];\r
1852                         vector[i][3] = (float)v[3];\r
1853 \r
1854                         v += 4;\r
1855                 }\r
1856 \r
1857                 Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
1858 \r
1859                 if(targetUniform->psRegisterIndex != -1)\r
1860                 {\r
1861                         device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1862                 }\r
1863 \r
1864                 if(targetUniform->vsRegisterIndex != -1)\r
1865                 {\r
1866                         device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
1867                 }\r
1868 \r
1869                 return true;\r
1870         }\r
1871 \r
1872         void Program::appendToInfoLog(const char *format, ...)\r
1873         {\r
1874                 if(!format)\r
1875                 {\r
1876                         return;\r
1877                 }\r
1878 \r
1879                 char info[1024];\r
1880 \r
1881                 va_list vararg;\r
1882                 va_start(vararg, format);\r
1883                 vsnprintf(info, sizeof(info), format, vararg);\r
1884                 va_end(vararg);\r
1885 \r
1886                 size_t infoLength = strlen(info);\r
1887 \r
1888                 if(!infoLog)\r
1889                 {\r
1890                         infoLog = new char[infoLength + 2];\r
1891                         strcpy(infoLog, info);\r
1892                         strcpy(infoLog + infoLength, "\n");\r
1893                 }\r
1894                 else\r
1895                 {\r
1896                         size_t logLength = strlen(infoLog);\r
1897                         char *newLog = new char[logLength + infoLength + 2];\r
1898                         strcpy(newLog, infoLog);\r
1899                         strcpy(newLog + logLength, info);\r
1900                         strcpy(newLog + logLength + infoLength, "\n");\r
1901 \r
1902                         delete[] infoLog;\r
1903                         infoLog = newLog;\r
1904                 }\r
1905         }\r
1906 \r
1907         void Program::resetInfoLog()\r
1908         {\r
1909                 if(infoLog)\r
1910                 {\r
1911                         delete[] infoLog;\r
1912                         infoLog = 0;\r
1913                 }\r
1914         }\r
1915 \r
1916         // Returns the program object to an unlinked state, before re-linking, or at destruction\r
1917         void Program::unlink()\r
1918         {\r
1919                 delete vertexBinary;\r
1920                 vertexBinary = 0;\r
1921                 delete pixelBinary;\r
1922                 pixelBinary = 0;\r
1923 \r
1924                 for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)\r
1925                 {\r
1926                         linkedAttribute[index].name.clear();\r
1927                         attributeStream[index] = -1;\r
1928                 }\r
1929 \r
1930                 for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)\r
1931                 {\r
1932                         samplersPS[index].active = false;\r
1933                 }\r
1934 \r
1935                 for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)\r
1936                 {\r
1937                         samplersVS[index].active = false;\r
1938                 }\r
1939 \r
1940                 while(!uniforms.empty())\r
1941                 {\r
1942                         delete uniforms.back();\r
1943                         uniforms.pop_back();\r
1944                 }\r
1945 \r
1946                 uniformIndex.clear();\r
1947 \r
1948                 delete[] infoLog;\r
1949                 infoLog = 0;\r
1950 \r
1951                 linked = false;\r
1952         }\r
1953 \r
1954         bool Program::isLinked()\r
1955         {\r
1956                 return linked;\r
1957         }\r
1958 \r
1959         bool Program::isValidated() const \r
1960         {\r
1961                 return validated;\r
1962         }\r
1963 \r
1964         void Program::release()\r
1965         {\r
1966                 referenceCount--;\r
1967 \r
1968                 if(referenceCount == 0 && orphaned)\r
1969                 {\r
1970                         resourceManager->deleteProgram(handle);\r
1971                 }\r
1972         }\r
1973 \r
1974         void Program::addRef()\r
1975         {\r
1976                 referenceCount++;\r
1977         }\r
1978 \r
1979         unsigned int Program::getRefCount() const\r
1980         {\r
1981                 return referenceCount;\r
1982         }\r
1983 \r
1984         unsigned int Program::getSerial() const\r
1985         {\r
1986                 return serial;\r
1987         }\r
1988 \r
1989         unsigned int Program::issueSerial()\r
1990         {\r
1991                 return currentSerial++;\r
1992         }\r
1993 \r
1994         int Program::getInfoLogLength() const\r
1995         {\r
1996                 if(!infoLog)\r
1997                 {\r
1998                         return 0;\r
1999                 }\r
2000                 else\r
2001                 {\r
2002                    return strlen(infoLog) + 1;\r
2003                 }\r
2004         }\r
2005 \r
2006         void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)\r
2007         {\r
2008                 int index = 0;\r
2009 \r
2010                 if(bufSize > 0)\r
2011                 {\r
2012                         if(infoLog)\r
2013                         {\r
2014                                 index = std::min(bufSize - 1, (int)strlen(infoLog));\r
2015                                 memcpy(buffer, infoLog, index);\r
2016                         }\r
2017 \r
2018                         buffer[index] = '\0';\r
2019                 }\r
2020 \r
2021                 if(length)\r
2022                 {\r
2023                         *length = index;\r
2024                 }\r
2025         }\r
2026 \r
2027         void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)\r
2028         {\r
2029                 int total = 0;\r
2030 \r
2031                 if(vertexShader)\r
2032                 {\r
2033                         if(total < maxCount)\r
2034                         {\r
2035                                 shaders[total] = vertexShader->getHandle();\r
2036                         }\r
2037 \r
2038                         total++;\r
2039                 }\r
2040 \r
2041                 if(fragmentShader)\r
2042                 {\r
2043                         if(total < maxCount)\r
2044                         {\r
2045                                 shaders[total] = fragmentShader->getHandle();\r
2046                         }\r
2047 \r
2048                         total++;\r
2049                 }\r
2050 \r
2051                 if(count)\r
2052                 {\r
2053                         *count = total;\r
2054                 }\r
2055         }\r
2056 \r
2057         void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const\r
2058         {\r
2059                 // Skip over inactive attributes\r
2060                 unsigned int activeAttribute = 0;\r
2061                 unsigned int attribute;\r
2062                 for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)\r
2063                 {\r
2064                         if(linkedAttribute[attribute].name.empty())\r
2065                         {\r
2066                                 continue;\r
2067                         }\r
2068 \r
2069                         if(activeAttribute == index)\r
2070                         {\r
2071                                 break;\r
2072                         }\r
2073 \r
2074                         activeAttribute++;\r
2075                 }\r
2076 \r
2077                 if(bufsize > 0)\r
2078                 {\r
2079                         const char *string = linkedAttribute[attribute].name.c_str();\r
2080 \r
2081                         strncpy(name, string, bufsize);\r
2082                         name[bufsize - 1] = '\0';\r
2083 \r
2084                         if(length)\r
2085                         {\r
2086                                 *length = strlen(name);\r
2087                         }\r
2088                 }\r
2089 \r
2090                 *size = 1;   // Always a single 'type' instance\r
2091 \r
2092                 *type = linkedAttribute[attribute].type;\r
2093         }\r
2094 \r
2095         GLint Program::getActiveAttributeCount() const\r
2096         {\r
2097                 int count = 0;\r
2098 \r
2099                 for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)\r
2100                 {\r
2101                         if(!linkedAttribute[attributeIndex].name.empty())\r
2102                         {\r
2103                                 count++;\r
2104                         }\r
2105                 }\r
2106 \r
2107                 return count;\r
2108         }\r
2109 \r
2110         GLint Program::getActiveAttributeMaxLength() const\r
2111         {\r
2112                 int maxLength = 0;\r
2113 \r
2114                 for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)\r
2115                 {\r
2116                         if(!linkedAttribute[attributeIndex].name.empty())\r
2117                         {\r
2118                                 maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);\r
2119                         }\r
2120                 }\r
2121 \r
2122                 return maxLength;\r
2123         }\r
2124 \r
2125         void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const\r
2126         {\r
2127                 if(bufsize > 0)\r
2128                 {\r
2129                         std::string string = uniforms[index]->name;\r
2130 \r
2131                         if(uniforms[index]->isArray())\r
2132                         {\r
2133                                 string += "[0]";\r
2134                         }\r
2135 \r
2136                         strncpy(name, string.c_str(), bufsize);\r
2137                         name[bufsize - 1] = '\0';\r
2138 \r
2139                         if(length)\r
2140                         {\r
2141                                 *length = strlen(name);\r
2142                         }\r
2143                 }\r
2144 \r
2145                 *size = uniforms[index]->size();\r
2146 \r
2147                 *type = uniforms[index]->type;\r
2148         }\r
2149 \r
2150         GLint Program::getActiveUniformCount() const\r
2151         {\r
2152                 return uniforms.size();\r
2153         }\r
2154 \r
2155         GLint Program::getActiveUniformMaxLength() const\r
2156         {\r
2157                 int maxLength = 0;\r
2158 \r
2159                 unsigned int numUniforms = uniforms.size();\r
2160                 for(unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)\r
2161                 {\r
2162                         if(!uniforms[uniformIndex]->name.empty())\r
2163                         {\r
2164                                 int length = (int)(uniforms[uniformIndex]->name.length() + 1);\r
2165                                 if(uniforms[uniformIndex]->isArray())\r
2166                                 {\r
2167                                         length += 3;  // Counting in "[0]".\r
2168                                 }\r
2169                                 maxLength = std::max(length, maxLength);\r
2170                         }\r
2171                 }\r
2172 \r
2173                 return maxLength;\r
2174         }\r
2175 \r
2176         void Program::flagForDeletion()\r
2177         {\r
2178                 orphaned = true;\r
2179         }\r
2180 \r
2181         bool Program::isFlaggedForDeletion() const\r
2182         {\r
2183                 return orphaned;\r
2184         }\r
2185 \r
2186         void Program::validate()\r
2187         {\r
2188                 resetInfoLog();\r
2189 \r
2190                 if(!isLinked()) \r
2191                 {\r
2192                         appendToInfoLog("Program has not been successfully linked.");\r
2193                         validated = false;\r
2194                 }\r
2195                 else\r
2196                 {\r
2197                         applyUniforms();\r
2198                         if(!validateSamplers(true))\r
2199                         {\r
2200                                 validated = false;\r
2201                         }\r
2202                         else\r
2203                         {\r
2204                                 validated = true;\r
2205                         }\r
2206                 }\r
2207         }\r
2208 \r
2209         bool Program::validateSamplers(bool logErrors)\r
2210         {\r
2211                 // if any two active samplers in a program are of different types, but refer to the same\r
2212                 // texture image unit, and this is the current program, then ValidateProgram will fail, and\r
2213                 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.\r
2214 \r
2215                 TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];\r
2216 \r
2217                 for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)\r
2218                 {\r
2219                         textureUnitType[i] = TEXTURE_UNKNOWN;\r
2220                 }\r
2221 \r
2222                 for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)\r
2223                 {\r
2224                         if(samplersPS[i].active)\r
2225                         {\r
2226                                 unsigned int unit = samplersPS[i].logicalTextureUnit;\r
2227             \r
2228                                 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
2229                                 {\r
2230                                         if(logErrors)\r
2231                                         {\r
2232                                                 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);\r
2233                                         }\r
2234 \r
2235                                         return false;\r
2236                                 }\r
2237 \r
2238                                 if(textureUnitType[unit] != TEXTURE_UNKNOWN)\r
2239                                 {\r
2240                                         if(samplersPS[i].textureType != textureUnitType[unit])\r
2241                                         {\r
2242                                                 if(logErrors)\r
2243                                                 {\r
2244                                                         appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);\r
2245                                                 }\r
2246 \r
2247                                                 return false;\r
2248                                         }\r
2249                                 }\r
2250                                 else\r
2251                                 {\r
2252                                         textureUnitType[unit] = samplersPS[i].textureType;\r
2253                                 }\r
2254                         }\r
2255                 }\r
2256 \r
2257                 for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)\r
2258                 {\r
2259                         if(samplersVS[i].active)\r
2260                         {\r
2261                                 unsigned int unit = samplersVS[i].logicalTextureUnit;\r
2262             \r
2263                                 if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
2264                                 {\r
2265                                         if(logErrors)\r
2266                                         {\r
2267                                                 appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);\r
2268                                         }\r
2269 \r
2270                                         return false;\r
2271                                 }\r
2272 \r
2273                                 if(textureUnitType[unit] != TEXTURE_UNKNOWN)\r
2274                                 {\r
2275                                         if(samplersVS[i].textureType != textureUnitType[unit])\r
2276                                         {\r
2277                                                 if(logErrors)\r
2278                                                 {\r
2279                                                         appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);\r
2280                                                 }\r
2281 \r
2282                                                 return false;\r
2283                                         }\r
2284                                 }\r
2285                                 else\r
2286                                 {\r
2287                                         textureUnitType[unit] = samplersVS[i].textureType;\r
2288                                 }\r
2289                         }\r
2290                 }\r
2291 \r
2292                 return true;\r
2293         }\r
2294 }\r