OSDN Git Service

Allow all output to be written to in the vertex shader
[android-x86/external-swiftshader.git] / src / OpenGL / libGLESv2 / Program.cpp
index ddeef88..b2d14f7 100644 (file)
-// SwiftShader Software Renderer\r
-//\r
-// Copyright(c) 2005-2013 TransGaming Inc.\r
-//\r
-// All rights reserved. No part of this software may be copied, distributed, transmitted,\r
-// transcribed, stored in a retrieval system, translated into any human or computer\r
-// language by any means, or disclosed to third parties without the explicit written\r
-// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express\r
-// or implied, including but not limited to any patent rights, are granted to you.\r
-//\r
-\r
-// Program.cpp: Implements the Program class. Implements GL program objects\r
-// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.\r
-\r
-#include "Program.h"\r
-\r
-#include "main.h"\r
-#include "Shader.h"\r
-#include "utilities.h"\r
-#include "common/debug.h"\r
-#include "Shader/PixelShader.hpp"\r
-#include "Shader/VertexShader.hpp"\r
-\r
-#include <string>\r
-#include <stdlib.h>\r
-\r
-namespace es2\r
-{\r
-       unsigned int Program::currentSerial = 1;\r
-\r
-       std::string str(int i)\r
-       {\r
-               char buffer[20];\r
-               sprintf(buffer, "%d", i);\r
-               return buffer;\r
-       }\r
-\r
-       Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize) : type(type), precision(precision), name(name), arraySize(arraySize)\r
-       {\r
-               int bytes = UniformTypeSize(type) * size();\r
-               data = new unsigned char[bytes];\r
-               memset(data, 0, bytes);\r
-               dirty = true;\r
-\r
-               psRegisterIndex = -1;\r
-               vsRegisterIndex = -1;\r
-       }\r
-\r
-       Uniform::~Uniform()\r
-       {\r
-               delete[] data;\r
-       }\r
-\r
-       bool Uniform::isArray() const\r
-       {\r
-               return arraySize >= 1;\r
-       }\r
-\r
-       int Uniform::size() const\r
-       {\r
-               return arraySize > 0 ? arraySize : 1;\r
-       }\r
-\r
-       int Uniform::registerCount() const\r
-       {\r
-               return size() * VariableRowCount(type);\r
-       }\r
-\r
-       UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)\r
-       {\r
-       }\r
-\r
-       Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())\r
-       {\r
-               device = getDevice();\r
-\r
-               fragmentShader = 0;\r
-               vertexShader = 0;\r
-               pixelBinary = 0;\r
-               vertexBinary = 0;\r
-\r
-               infoLog = 0;\r
-               validated = false;\r
-\r
-               unlink();\r
-\r
-               orphaned = false;\r
-               referenceCount = 0;\r
-       }\r
-\r
-       Program::~Program()\r
-       {\r
-               unlink();\r
-\r
-               if(vertexShader)\r
-               {\r
-                       vertexShader->release();\r
-               }\r
-\r
-               if(fragmentShader)\r
-               {\r
-                       fragmentShader->release();\r
-               }\r
-       }\r
-\r
-       bool Program::attachShader(Shader *shader)\r
-       {\r
-               if(shader->getType() == GL_VERTEX_SHADER)\r
-               {\r
-                       if(vertexShader)\r
-                       {\r
-                               return false;\r
-                       }\r
-\r
-                       vertexShader = (VertexShader*)shader;\r
-                       vertexShader->addRef();\r
-               }\r
-               else if(shader->getType() == GL_FRAGMENT_SHADER)\r
-               {\r
-                       if(fragmentShader)\r
-                       {\r
-                               return false;\r
-                       }\r
-\r
-                       fragmentShader = (FragmentShader*)shader;\r
-                       fragmentShader->addRef();\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::detachShader(Shader *shader)\r
-       {\r
-               if(shader->getType() == GL_VERTEX_SHADER)\r
-               {\r
-                       if(vertexShader != shader)\r
-                       {\r
-                               return false;\r
-                       }\r
-\r
-                       vertexShader->release();\r
-                       vertexShader = 0;\r
-               }\r
-               else if(shader->getType() == GL_FRAGMENT_SHADER)\r
-               {\r
-                       if(fragmentShader != shader)\r
-                       {\r
-                               return false;\r
-                       }\r
-\r
-                       fragmentShader->release();\r
-                       fragmentShader = 0;\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               return true;\r
-       }\r
-\r
-       int Program::getAttachedShadersCount() const\r
-       {\r
-               return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);\r
-       }\r
-\r
-       sw::PixelShader *Program::getPixelShader()\r
-       {\r
-               return pixelBinary;\r
-       }\r
-\r
-       sw::VertexShader *Program::getVertexShader()\r
-       {\r
-               return vertexBinary;\r
-       }\r
-\r
-       void Program::bindAttributeLocation(GLuint index, const char *name)\r
-       {\r
-               if(index < MAX_VERTEX_ATTRIBS)\r
-               {\r
-                       for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)\r
-                       {\r
-                               attributeBinding[i].erase(name);\r
-                       }\r
-\r
-                       attributeBinding[index].insert(name);\r
-               }\r
-       }\r
-\r
-       GLuint Program::getAttributeLocation(const char *name)\r
-       {\r
-               if(name)\r
-               {\r
-                       for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)\r
-                       {\r
-                               if(linkedAttribute[index].name == std::string(name))\r
-                               {\r
-                                       return index;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       int Program::getAttributeStream(int attributeIndex)\r
-       {\r
-               ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);\r
-    \r
-               return attributeStream[attributeIndex];\r
-       }\r
-\r
-       // 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
-       GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)\r
-       {\r
-               GLuint logicalTextureUnit = -1;\r
-\r
-               switch(type)\r
-               {\r
-               case sw::SAMPLER_PIXEL:\r
-                       ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));\r
-\r
-                       if(samplersPS[samplerIndex].active)\r
-                       {\r
-                               logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;\r
-                       }\r
-                       break;\r
-               case sw::SAMPLER_VERTEX:\r
-                       ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));\r
-\r
-                       if(samplersVS[samplerIndex].active)\r
-                       {\r
-                               logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;\r
-                       }\r
-                       break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               if(logicalTextureUnit >= 0 && logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
-               {\r
-                       return logicalTextureUnit;\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       // 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
-       TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)\r
-       {\r
-               switch(type)\r
-               {\r
-               case sw::SAMPLER_PIXEL:\r
-                       ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));\r
-                       ASSERT(samplersPS[samplerIndex].active);\r
-                       return samplersPS[samplerIndex].textureType;\r
-               case sw::SAMPLER_VERTEX:\r
-                       ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));\r
-                       ASSERT(samplersVS[samplerIndex].active);\r
-                       return samplersVS[samplerIndex].textureType;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return TEXTURE_2D;\r
-       }\r
-\r
-       GLint Program::getUniformLocation(std::string name)\r
-       {\r
-               int subscript = 0;\r
-\r
-               // Strip any trailing array operator and retrieve the subscript\r
-               size_t open = name.find_last_of('[');\r
-               size_t close = name.find_last_of(']');\r
-               if(open != std::string::npos && close == name.length() - 1)\r
-               {\r
-                       subscript = atoi(name.substr(open + 1).c_str());\r
-                       name.erase(open);\r
-               }\r
-\r
-               unsigned int numUniforms = uniformIndex.size();\r
-               for(unsigned int location = 0; location < numUniforms; location++)\r
-               {\r
-                       if(uniformIndex[location].name == name &&\r
-                          uniformIndex[location].element == subscript)\r
-                       {\r
-                               return location;\r
-                       }\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_FLOAT)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat),\r
-                                  v, sizeof(GLfloat) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL)\r
-               {\r
-                       GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element;\r
-\r
-                       for(int i = 0; i < count; i++)\r
-                       {\r
-                               if(v[i] == 0.0f)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_FLOAT_VEC2)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 2,\r
-                                  v, 2 * sizeof(GLfloat) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC2)\r
-               {\r
-                       GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 2;\r
-\r
-                       for(int i = 0; i < count * 2; i++)\r
-                       {\r
-                               if(v[i] == 0.0f)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-               }\r
-               else \r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_FLOAT_VEC3)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 3,\r
-                                  v, 3 * sizeof(GLfloat) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC3)\r
-               {\r
-                       GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 3;\r
-\r
-                       for(int i = 0; i < count * 3; i++)\r
-                       {\r
-                               if(v[i] == 0.0f)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-               }\r
-               else \r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_FLOAT_VEC4)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,\r
-                                  v, 4 * sizeof(GLfloat) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC4)\r
-               {\r
-                       GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * 4;\r
-\r
-                       for(int i = 0; i < count * 4; i++)\r
-                       {\r
-                               if(v[i] == 0.0f)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-               }\r
-               else \r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               if(targetUniform->type != GL_FLOAT_MAT2)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-\r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 4,\r
-                          value, 4 * sizeof(GLfloat) * count);\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               if(targetUniform->type != GL_FLOAT_MAT3)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-\r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 9,\r
-                          value, 9 * sizeof(GLfloat) * count);\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               if(targetUniform->type != GL_FLOAT_MAT4)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-\r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * 16,\r
-                          value, 16 * sizeof(GLfloat) * count);\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_INT ||\r
-                  targetUniform->type == GL_SAMPLER_2D ||\r
-                  targetUniform->type == GL_SAMPLER_CUBE ||\r
-           targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||\r
-                  targetUniform->type == GL_SAMPLER_3D_OES)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),\r
-                                  v, sizeof(GLint) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL)\r
-               {\r
-                       GLboolean *boolParams = new GLboolean[count];\r
-\r
-                       for(int i = 0; i < count; i++)\r
-                       {\r
-                               if(v[i] == 0)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),\r
-                                  boolParams, sizeof(GLboolean) * count);\r
-\r
-                       delete[] boolParams;\r
-               }\r
-               else\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_INT_VEC2)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 2,\r
-                                  v, 2 * sizeof(GLint) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC2)\r
-               {\r
-                       GLboolean *boolParams = new GLboolean[count * 2];\r
-\r
-                       for(int i = 0; i < count * 2; i++)\r
-                       {\r
-                               if(v[i] == 0)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 2,\r
-                                  boolParams, 2 * sizeof(GLboolean) * count);\r
-\r
-                       delete[] boolParams;\r
-               }\r
-               else\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_INT_VEC3)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 3,\r
-                                  v, 3 * sizeof(GLint) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC3)\r
-               {\r
-                       GLboolean *boolParams = new GLboolean[count * 3];\r
-\r
-                       for(int i = 0; i < count * 3; i++)\r
-                       {\r
-                               if(v[i] == 0)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 3,\r
-                                  boolParams, 3 * sizeof(GLboolean) * count);\r
-\r
-                       delete[] boolParams;\r
-               }\r
-               else\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               targetUniform->dirty = true;\r
-\r
-               int size = targetUniform->size();\r
-\r
-               if(size == 1 && count > 1)\r
-               {\r
-                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION\r
-               }\r
-       \r
-               count = std::min(size - (int)uniformIndex[location].element, count);\r
-\r
-               if(targetUniform->type == GL_INT_VEC4)\r
-               {\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint) * 4,\r
-                                  v, 4 * sizeof(GLint) * count);\r
-               }\r
-               else if(targetUniform->type == GL_BOOL_VEC4)\r
-               {\r
-                       GLboolean *boolParams = new GLboolean[count * 4];\r
-\r
-                       for(int i = 0; i < count * 4; i++)\r
-                       {\r
-                               if(v[i] == 0)\r
-                               {\r
-                                       boolParams[i] = GL_FALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       boolParams[i] = GL_TRUE;\r
-                               }\r
-                       }\r
-\r
-                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean) * 4,\r
-                                  boolParams, 4 * sizeof(GLboolean) * count);\r
-\r
-                       delete[] boolParams;\r
-               }\r
-               else\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               unsigned int count = UniformComponentCount(targetUniform->type);\r
-\r
-               // Sized query - ensure the provided buffer is large enough\r
-               if(bufSize && *bufSize < count * sizeof(GLfloat))\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               switch (UniformComponentType(targetUniform->type))\r
-               {\r
-                 case GL_BOOL:\r
-                       {\r
-                               GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;\r
-\r
-                               for(unsigned int i = 0; i < count; i++)\r
-                               {\r
-                                       params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;\r
-                               }\r
-                       }\r
-                       break;\r
-                 case GL_FLOAT:\r
-                       memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),\r
-                                  count * sizeof(GLfloat));\r
-                       break;\r
-                 case GL_INT:\r
-                       {\r
-                               GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;\r
-\r
-                               for(unsigned int i = 0; i < count; i++)\r
-                               {\r
-                                       params[i] = (float)intParams[i];\r
-                               }\r
-                       }\r
-                       break;\r
-                 default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)\r
-       {\r
-               if(location < 0 || location >= (int)uniformIndex.size())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-               unsigned int count = UniformComponentCount(targetUniform->type);\r
-\r
-               // Sized query - ensure the provided buffer is large enough\r
-               if(bufSize && *bufSize < count * sizeof(GLint))\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               switch (UniformComponentType(targetUniform->type))\r
-               {\r
-                 case GL_BOOL:\r
-                       {\r
-                               GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;\r
-\r
-                               for(unsigned int i = 0; i < count; i++)\r
-                               {\r
-                                       params[i] = (GLint)boolParams[i];\r
-                               }\r
-                       }\r
-                       break;\r
-                 case GL_FLOAT:\r
-                       {\r
-                               GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;\r
-\r
-                               for(unsigned int i = 0; i < count; i++)\r
-                               {\r
-                                       params[i] = (GLint)floatParams[i];\r
-                               }\r
-                       }\r
-                       break;\r
-                 case GL_INT:\r
-                       memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),\r
-                                  count * sizeof(GLint));\r
-                       break;\r
-                 default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       void Program::dirtyAllUniforms()\r
-       {\r
-               unsigned int numUniforms = uniforms.size();\r
-               for(unsigned int index = 0; index < numUniforms; index++)\r
-               {\r
-                       uniforms[index]->dirty = true;\r
-               }\r
-       }\r
-\r
-       // Applies all the uniforms set for this program object to the device\r
-       void Program::applyUniforms()\r
-       {\r
-               unsigned int numUniforms = uniformIndex.size();\r
-               for(unsigned int location = 0; location < numUniforms; location++)\r
-               {\r
-                       if(uniformIndex[location].element != 0)\r
-                       {\r
-                               continue;\r
-                       }\r
-\r
-                       Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-                       if(targetUniform->dirty)\r
-                       {\r
-                               int size = targetUniform->size();\r
-                               GLfloat *f = (GLfloat*)targetUniform->data;\r
-                               GLint *i = (GLint*)targetUniform->data;\r
-                               GLboolean *b = (GLboolean*)targetUniform->data;\r
-\r
-                               switch(targetUniform->type)\r
-                               {\r
-                                 case GL_BOOL:       applyUniform1bv(location, size, b);       break;\r
-                                 case GL_BOOL_VEC2:  applyUniform2bv(location, size, b);       break;\r
-                                 case GL_BOOL_VEC3:  applyUniform3bv(location, size, b);       break;\r
-                                 case GL_BOOL_VEC4:  applyUniform4bv(location, size, b);       break;\r
-                                 case GL_FLOAT:      applyUniform1fv(location, size, f);       break;\r
-                                 case GL_FLOAT_VEC2: applyUniform2fv(location, size, f);       break;\r
-                                 case GL_FLOAT_VEC3: applyUniform3fv(location, size, f);       break;\r
-                                 case GL_FLOAT_VEC4: applyUniform4fv(location, size, f);       break;\r
-                                 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, size, f); break;\r
-                                 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, size, f); break;\r
-                                 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, size, f); break;\r
-                                 case GL_SAMPLER_2D:\r
-                                 case GL_SAMPLER_CUBE:\r
-                                 case GL_SAMPLER_EXTERNAL_OES:\r
-                                 case GL_SAMPLER_3D_OES:\r
-                                 case GL_INT:        applyUniform1iv(location, size, i);       break;\r
-                                 case GL_INT_VEC2:   applyUniform2iv(location, size, i);       break;\r
-                                 case GL_INT_VEC3:   applyUniform3iv(location, size, i);       break;\r
-                                 case GL_INT_VEC4:   applyUniform4iv(location, size, i);       break;\r
-                                 default:\r
-                                       UNREACHABLE();\r
-                               }\r
-\r
-                               targetUniform->dirty = false;\r
-                       }\r
-               }\r
-       }\r
-\r
-       // 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
-       // Returns the number of used varying registers, or -1 if unsuccesful\r
-       int Program::packVaryings(const glsl::Varying *packing[][4])\r
-       {\r
-               for(glsl::VaryingList::iterator varying = fragmentShader->varyings.begin(); varying != fragmentShader->varyings.end(); varying++)\r
-               {\r
-                       int n = VariableRowCount(varying->type) * varying->size();\r
-                       int m = VariableColumnCount(varying->type);\r
-                       bool success = false;\r
-\r
-                       if(m == 2 || m == 3 || m == 4)\r
-                       {\r
-                               for(int r = 0; r <= MAX_VARYING_VECTORS - n && !success; r++)\r
-                               {\r
-                                       bool available = true;\r
-\r
-                                       for(int y = 0; y < n && available; y++)\r
-                                       {\r
-                                               for(int x = 0; x < m && available; x++)\r
-                                               {\r
-                                                       if(packing[r + y][x])\r
-                                                       {\r
-                                                               available = false;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-\r
-                                       if(available)\r
-                                       {\r
-                                               varying->reg = r;\r
-                                               varying->col = 0;\r
-\r
-                                               for(int y = 0; y < n; y++)\r
-                                               {\r
-                                                       for(int x = 0; x < m; x++)\r
-                                                       {\r
-                                                               packing[r + y][x] = &*varying;\r
-                                                       }\r
-                                               }\r
-\r
-                                               success = true;\r
-                                       }\r
-                               }\r
-\r
-                               if(!success && m == 2)\r
-                               {\r
-                                       for(int r = MAX_VARYING_VECTORS - n; r >= 0 && !success; r--)\r
-                                       {\r
-                                               bool available = true;\r
-\r
-                                               for(int y = 0; y < n && available; y++)\r
-                                               {\r
-                                                       for(int x = 2; x < 4 && available; x++)\r
-                                                       {\r
-                                                               if(packing[r + y][x])\r
-                                                               {\r
-                                                                       available = false;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-\r
-                                               if(available)\r
-                                               {\r
-                                                       varying->reg = r;\r
-                                                       varying->col = 2;\r
-\r
-                                                       for(int y = 0; y < n; y++)\r
-                                                       {\r
-                                                               for(int x = 2; x < 4; x++)\r
-                                                               {\r
-                                                                       packing[r + y][x] = &*varying;\r
-                                                               }\r
-                                                       }\r
-\r
-                                                       success = true;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       else if(m == 1)\r
-                       {\r
-                               int space[4] = {0};\r
-\r
-                               for(int y = 0; y < MAX_VARYING_VECTORS; y++)\r
-                               {\r
-                                       for(int x = 0; x < 4; x++)\r
-                                       {\r
-                                               space[x] += packing[y][x] ? 0 : 1;\r
-                                       }\r
-                               }\r
-\r
-                               int column = 0;\r
-\r
-                               for(int x = 0; x < 4; x++)\r
-                               {\r
-                                       if(space[x] >= n && space[x] < space[column])\r
-                                       {\r
-                                               column = x;\r
-                                       }\r
-                               }\r
-\r
-                               if(space[column] >= n)\r
-                               {\r
-                                       for(int r = 0; r < MAX_VARYING_VECTORS; r++)\r
-                                       {\r
-                                               if(!packing[r][column])\r
-                                               {\r
-                                                       varying->reg = r;\r
-\r
-                                                       for(int y = r; y < r + n; y++)\r
-                                                       {\r
-                                                               packing[y][column] = &*varying;\r
-                                                       }\r
-\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-\r
-                                       varying->col = column;\r
-\r
-                                       success = true;\r
-                               }\r
-                       }\r
-                       else UNREACHABLE();\r
-\r
-                       if(!success)\r
-                       {\r
-                               appendToInfoLog("Could not pack varying %s", varying->name.c_str());\r
-\r
-                               return -1;\r
-                       }\r
-               }\r
-\r
-               // Return the number of used registers\r
-               int registers = 0;\r
-\r
-               for(int r = 0; r < MAX_VARYING_VECTORS; r++)\r
-               {\r
-                       if(packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])\r
-                       {\r
-                               registers++;\r
-                       }\r
-               }\r
-\r
-               return registers;\r
-       }\r
-\r
-       bool Program::linkVaryings()\r
-       {\r
-               for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); input++)\r
-               {\r
-                       bool matched = false;\r
-\r
-                       for(glsl::VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); output++)\r
-                       {\r
-                               if(output->name == input->name)\r
-                               {\r
-                                       if(output->type != input->type || output->size() != input->size())\r
-                                       {\r
-                                               appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());\r
-\r
-                                               return false;\r
-                                       }\r
-\r
-                                       matched = true;\r
-                                       break;\r
-                               }\r
-                       }\r
-\r
-                       if(!matched)\r
-                       {\r
-                               appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());\r
-\r
-                               return false;\r
-                       }\r
-               }\r
-\r
-               glsl::VaryingList &psVaryings = fragmentShader->varyings;\r
-               glsl::VaryingList &vsVaryings = vertexShader->varyings;\r
-\r
-               for(glsl::VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); output++)\r
-               {\r
-                       for(glsl::VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); input++)\r
-                       {\r
-                               if(output->name == input->name)\r
-                               {\r
-                                       int in = input->reg;\r
-                                       int out = output->reg;\r
-                                       int components = VariableColumnCount(output->type);\r
-                                       int registers = VariableRowCount(output->type) * output->size();\r
-\r
-                                       ASSERT(in >= 0);\r
-\r
-                                       if(in + registers > MAX_VARYING_VECTORS)\r
-                                       {\r
-                                               appendToInfoLog("Too many varyings");\r
-                                               return false;\r
-                                       }\r
-\r
-                                       if(out >= 0)\r
-                                       {\r
-                                               if(out + registers > MAX_VARYING_VECTORS)\r
-                                               {\r
-                                                       appendToInfoLog("Too many varyings");\r
-                                                       return false;\r
-                                               }\r
-\r
-                                               for(int i = 0; i < registers; i++)\r
-                                               {\r
-                                                       if(components >= 1) vertexBinary->output[out + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
-                                                       if(components >= 2) vertexBinary->output[out + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
-                                                       if(components >= 3) vertexBinary->output[out + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
-                                                       if(components >= 4) vertexBinary->output[out + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i);\r
-                                               }\r
-                                       }\r
-                                       else   // Vertex varying is declared but not written to\r
-                                       {\r
-                                               for(int i = 0; i < registers; i++)\r
-                                               {\r
-                                                       if(components >= 1) pixelBinary->semantic[in + i][0] = sw::Shader::Semantic();\r
-                                                       if(components >= 2) pixelBinary->semantic[in + i][1] = sw::Shader::Semantic();\r
-                                                       if(components >= 3) pixelBinary->semantic[in + i][2] = sw::Shader::Semantic();\r
-                                                       if(components >= 4) pixelBinary->semantic[in + i][3] = sw::Shader::Semantic();                                  \r
-                                               }\r
-                                       }\r
-\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       // Links the code of the vertex and pixel shader by matching up their varyings,\r
-       // compiling them into binaries, determining the attribute mappings, and collecting\r
-       // a list of uniforms\r
-       void Program::link()\r
-       {\r
-               unlink();\r
-\r
-               if(!fragmentShader || !fragmentShader->isCompiled())\r
-               {\r
-                       return;\r
-               }\r
-\r
-               if(!vertexShader || !vertexShader->isCompiled())\r
-               {\r
-                       return;\r
-               }\r
-\r
-               vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());\r
-               pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());\r
-                       \r
-               if(!linkVaryings())\r
-               {\r
-                       return;\r
-               }\r
-\r
-               if(!linkAttributes())\r
-               {\r
-                       return;\r
-               }\r
-\r
-               if(!linkUniforms(fragmentShader))\r
-               {\r
-                       return;\r
-               }\r
-\r
-               if(!linkUniforms(vertexShader))\r
-               {\r
-                       return;\r
-               }\r
-\r
-               linked = true;   // Success\r
-       }\r
-\r
-       // Determines the mapping between GL attributes and vertex stream usage indices\r
-       bool Program::linkAttributes()\r
-       {\r
-               unsigned int usedLocations = 0;\r
-\r
-               // Link attributes that have a binding location\r
-               for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)\r
-               {\r
-                       int location = getAttributeBinding(attribute->name);\r
-\r
-                       if(location != -1)   // Set by glBindAttribLocation\r
-                       {\r
-                               if(!linkedAttribute[location].name.empty())\r
-                               {\r
-                                       // Multiple active attributes bound to the same location; not an error\r
-                               }\r
-\r
-                               linkedAttribute[location] = *attribute;\r
-\r
-                               int rows = VariableRowCount(attribute->type);\r
-\r
-                               if(rows + location > MAX_VERTEX_ATTRIBS)\r
-                               {\r
-                                       appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);\r
-                                       return false;\r
-                               }\r
-\r
-                               for(int i = 0; i < rows; i++)\r
-                               {\r
-                                       usedLocations |= 1 << (location + i);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // Link attributes that don't have a binding location\r
-               for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); attribute++)\r
-               {\r
-                       int location = getAttributeBinding(attribute->name);\r
-\r
-                       if(location == -1)   // Not set by glBindAttribLocation\r
-                       {\r
-                               int rows = VariableRowCount(attribute->type);\r
-                               int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);\r
-\r
-                               if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)\r
-                               {\r
-                                       appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());\r
-                                       return false;   // Fail to link\r
-                               }\r
-\r
-                               linkedAttribute[availableIndex] = *attribute;\r
-                       }\r
-               }\r
-\r
-               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )\r
-               {\r
-                       int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);\r
-                       int rows = std::max(VariableRowCount(linkedAttribute[attributeIndex].type), 1);\r
-\r
-                       for(int r = 0; r < rows; r++)\r
-                       {\r
-                               attributeStream[attributeIndex++] = index++;\r
-                       }\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       int Program::getAttributeBinding(const std::string &name)\r
-       {\r
-               for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)\r
-               {\r
-                       if(attributeBinding[location].find(name) != attributeBinding[location].end())\r
-                       {\r
-                               return location;\r
-                       }\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       bool Program::linkUniforms(Shader *shader)\r
-       {\r
-               const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;\r
-\r
-               for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)\r
-               {\r
-                       const glsl::Uniform &uniform = activeUniforms[uniformIndex];\r
-\r
-                       if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex))\r
-                       {\r
-                               return false;\r
-                       }\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)\r
-       {\r
-               if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_3D_OES)\r
-           {\r
-                       int index = registerIndex;\r
-                       \r
-                       do\r
-                       {\r
-                               if(shader == GL_VERTEX_SHADER)\r
-                               {\r
-                                       if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)\r
-                                       {\r
-                                               samplersVS[index].active = true;\r
-                                               switch(type) {\r
-                                               case GL_SAMPLER_CUBE:\r
-                                                       samplersVS[index].textureType = TEXTURE_CUBE;\r
-                                                       break;\r
-                                               case GL_SAMPLER_3D_OES:\r
-                                                       samplersVS[index].textureType = TEXTURE_3D;\r
-                                                       break;\r
-                                               default:\r
-                                                       samplersVS[index].textureType = TEXTURE_2D;\r
-                                                       break;\r
-                                               }\r
-                                               samplersVS[index].logicalTextureUnit = 0;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                          appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);\r
-                                          return false;\r
-                                       }\r
-                               }\r
-                               else if(shader == GL_FRAGMENT_SHADER)\r
-                               {\r
-                                       if(index < MAX_TEXTURE_IMAGE_UNITS)\r
-                                       {\r
-                                               samplersPS[index].active = true;\r
-                                               switch(type) {\r
-                                               case GL_SAMPLER_CUBE:\r
-                                                       samplersPS[index].textureType = TEXTURE_CUBE;\r
-                                                       break;\r
-                                               case GL_SAMPLER_3D_OES:\r
-                                                       samplersPS[index].textureType = TEXTURE_3D;\r
-                                                       break;\r
-                                               default:\r
-                                                       samplersPS[index].textureType = TEXTURE_2D;\r
-                                                       break;\r
-                                               }\r
-                                               samplersPS[index].logicalTextureUnit = 0;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);\r
-                                               return false;\r
-                                       }\r
-                               }\r
-                               else UNREACHABLE();\r
-\r
-                               index++;\r
-                       }\r
-                       while(index < registerIndex + arraySize);\r
-           }\r
-\r
-               Uniform *uniform = 0;\r
-               GLint location = getUniformLocation(name);\r
-\r
-               if(location >= 0)   // Previously defined, types must match\r
-               {\r
-                       uniform = uniforms[uniformIndex[location].index];\r
-\r
-                       if(uniform->type != type)\r
-                       {\r
-                               appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());\r
-                               return false;\r
-                       }\r
-\r
-                       if(uniform->precision != precision)\r
-                       {\r
-                               appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());\r
-                               return false;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       uniform = new Uniform(type, precision, name, arraySize);\r
-               }\r
-\r
-               if(!uniform)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               if(shader == GL_VERTEX_SHADER)\r
-               {\r
-                       uniform->vsRegisterIndex = registerIndex;\r
-               }\r
-               else if(shader == GL_FRAGMENT_SHADER)\r
-               {\r
-                       uniform->psRegisterIndex = registerIndex;\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               if(location == -1)   // Not previously defined\r
-               {\r
-                       uniforms.push_back(uniform);\r
-                       unsigned int index = uniforms.size() - 1;\r
-\r
-                       for(unsigned int i = 0; i < uniform->size(); i++)\r
-                       {\r
-                               uniformIndex.push_back(UniformLocation(name, i, index));\r
-                       }\r
-               }\r
-\r
-               if(shader == GL_VERTEX_SHADER)\r
-               {\r
-                       if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)\r
-                       {\r
-                               appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);\r
-                               return false;\r
-                       }\r
-               }\r
-               else if(shader == GL_FRAGMENT_SHADER)\r
-               {\r
-                       if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)\r
-                       {\r
-                               appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);\r
-                               return false;\r
-                       }\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)\r
-       {\r
-               int vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][1] = 0;\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 1;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)\r
-       {\r
-               int vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 2;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)\r
-       {\r
-               int vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 3;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)\r
-       {\r
-               int vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-                       vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);\r
-\r
-                       v += 4;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = v[0];\r
-                       vector[i][1] = 0;\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 1;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = v[0];\r
-                       vector[i][1] = v[1];\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 2;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = v[0];\r
-                       vector[i][1] = v[1];\r
-                       vector[i][2] = v[2];\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 3;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)\r
-       {\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)v, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)v, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = 0; matrix[i][0][3] = 0;\r
-                       matrix[i][1][0] = value[2];     matrix[i][1][1] = value[3];     matrix[i][1][2] = 0; matrix[i][1][3] = 0;\r
-\r
-                       value += 4;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2];     matrix[i][0][3] = 0;\r
-                       matrix[i][1][0] = value[3];     matrix[i][1][1] = value[4];     matrix[i][1][2] = value[5];     matrix[i][1][3] = 0;\r
-                       matrix[i][2][0] = value[6];     matrix[i][2][1] = value[7];     matrix[i][2][2] = value[8];     matrix[i][2][3] = 0;\r
-\r
-                       value += 9;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {       \r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)matrix, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)\r
-       {\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-       \r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)value, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)value, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (float)v[i];\r
-                       vector[i][1] = 0;\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-            if(targetUniform->type == GL_SAMPLER_2D ||\r
-               targetUniform->type == GL_SAMPLER_CUBE ||\r
-                          targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||\r
-                          targetUniform->type == GL_SAMPLER_3D_OES)\r
-                       {\r
-                               for(int i = 0; i < count; i++)\r
-                               {\r
-                                       unsigned int samplerIndex = targetUniform->psRegisterIndex + i;\r
-\r
-                                       if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)\r
-                                       {\r
-                                               ASSERT(samplersPS[samplerIndex].active);\r
-                                               samplersPS[samplerIndex].logicalTextureUnit = v[i];\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-                       }\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       if(targetUniform->type == GL_SAMPLER_2D ||\r
-               targetUniform->type == GL_SAMPLER_CUBE ||\r
-                          targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||\r
-                          targetUniform->type == GL_SAMPLER_3D_OES)\r
-                       {\r
-                               for(int i = 0; i < count; i++)\r
-                               {\r
-                                       unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;\r
-\r
-                                       if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)\r
-                                       {\r
-                                               ASSERT(samplersVS[samplerIndex].active);\r
-                                               samplersVS[samplerIndex].logicalTextureUnit = v[i];\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-                       }\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (float)v[0];\r
-                       vector[i][1] = (float)v[1];\r
-                       vector[i][2] = 0;\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 2;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (float)v[0];\r
-                       vector[i][1] = (float)v[1];\r
-                       vector[i][2] = (float)v[2];\r
-                       vector[i][3] = 0;\r
-\r
-                       v += 3;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)\r
-       {\r
-               float vector[MAX_UNIFORM_VECTORS][4];\r
-\r
-               for(int i = 0; i < count; i++)\r
-               {\r
-                       vector[i][0] = (float)v[0];\r
-                       vector[i][1] = (float)v[1];\r
-                       vector[i][2] = (float)v[2];\r
-                       vector[i][3] = (float)v[3];\r
-\r
-                       v += 4;\r
-               }\r
-\r
-               Uniform *targetUniform = uniforms[uniformIndex[location].index];\r
-\r
-               if(targetUniform->psRegisterIndex != -1)\r
-               {\r
-                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               if(targetUniform->vsRegisterIndex != -1)\r
-               {\r
-                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, (float*)vector, targetUniform->registerCount());\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       void Program::appendToInfoLog(const char *format, ...)\r
-       {\r
-               if(!format)\r
-               {\r
-                       return;\r
-               }\r
-\r
-               char info[1024];\r
-\r
-               va_list vararg;\r
-               va_start(vararg, format);\r
-               vsnprintf(info, sizeof(info), format, vararg);\r
-               va_end(vararg);\r
-\r
-               size_t infoLength = strlen(info);\r
-\r
-               if(!infoLog)\r
-               {\r
-                       infoLog = new char[infoLength + 2];\r
-                       strcpy(infoLog, info);\r
-                       strcpy(infoLog + infoLength, "\n");\r
-               }\r
-               else\r
-               {\r
-                       size_t logLength = strlen(infoLog);\r
-                       char *newLog = new char[logLength + infoLength + 2];\r
-                       strcpy(newLog, infoLog);\r
-                       strcpy(newLog + logLength, info);\r
-                       strcpy(newLog + logLength + infoLength, "\n");\r
-\r
-                       delete[] infoLog;\r
-                       infoLog = newLog;\r
-               }\r
-       }\r
-\r
-       void Program::resetInfoLog()\r
-       {\r
-               if(infoLog)\r
-               {\r
-                       delete[] infoLog;\r
-                       infoLog = 0;\r
-               }\r
-       }\r
-\r
-       // Returns the program object to an unlinked state, before re-linking, or at destruction\r
-       void Program::unlink()\r
-       {\r
-               delete vertexBinary;\r
-               vertexBinary = 0;\r
-               delete pixelBinary;\r
-               pixelBinary = 0;\r
-\r
-               for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)\r
-               {\r
-                       linkedAttribute[index].name.clear();\r
-                       attributeStream[index] = -1;\r
-               }\r
-\r
-               for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)\r
-               {\r
-                       samplersPS[index].active = false;\r
-               }\r
-\r
-               for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)\r
-               {\r
-                       samplersVS[index].active = false;\r
-               }\r
-\r
-               while(!uniforms.empty())\r
-               {\r
-                       delete uniforms.back();\r
-                       uniforms.pop_back();\r
-               }\r
-\r
-               uniformIndex.clear();\r
-\r
-               delete[] infoLog;\r
-               infoLog = 0;\r
-\r
-               linked = false;\r
-       }\r
-\r
-       bool Program::isLinked()\r
-       {\r
-               return linked;\r
-       }\r
-\r
-       bool Program::isValidated() const \r
-       {\r
-               return validated;\r
-       }\r
-\r
-       void Program::release()\r
-       {\r
-               referenceCount--;\r
-\r
-               if(referenceCount == 0 && orphaned)\r
-               {\r
-                       resourceManager->deleteProgram(handle);\r
-               }\r
-       }\r
-\r
-       void Program::addRef()\r
-       {\r
-               referenceCount++;\r
-       }\r
-\r
-       unsigned int Program::getRefCount() const\r
-       {\r
-               return referenceCount;\r
-       }\r
-\r
-       unsigned int Program::getSerial() const\r
-       {\r
-               return serial;\r
-       }\r
-\r
-       unsigned int Program::issueSerial()\r
-       {\r
-               return currentSerial++;\r
-       }\r
-\r
-       int Program::getInfoLogLength() const\r
-       {\r
-               if(!infoLog)\r
-               {\r
-                       return 0;\r
-               }\r
-               else\r
-               {\r
-                  return strlen(infoLog) + 1;\r
-               }\r
-       }\r
-\r
-       void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)\r
-       {\r
-               int index = 0;\r
-\r
-               if(bufSize > 0)\r
-               {\r
-                       if(infoLog)\r
-                       {\r
-                               index = std::min(bufSize - 1, (int)strlen(infoLog));\r
-                               memcpy(buffer, infoLog, index);\r
-                       }\r
-\r
-                       buffer[index] = '\0';\r
-               }\r
-\r
-               if(length)\r
-               {\r
-                       *length = index;\r
-               }\r
-       }\r
-\r
-       void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)\r
-       {\r
-               int total = 0;\r
-\r
-               if(vertexShader)\r
-               {\r
-                       if(total < maxCount)\r
-                       {\r
-                               shaders[total] = vertexShader->getName();\r
-                       }\r
-\r
-                       total++;\r
-               }\r
-\r
-               if(fragmentShader)\r
-               {\r
-                       if(total < maxCount)\r
-                       {\r
-                               shaders[total] = fragmentShader->getName();\r
-                       }\r
-\r
-                       total++;\r
-               }\r
-\r
-               if(count)\r
-               {\r
-                       *count = total;\r
-               }\r
-       }\r
-\r
-       void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const\r
-       {\r
-               // Skip over inactive attributes\r
-               unsigned int activeAttribute = 0;\r
-               unsigned int attribute;\r
-               for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)\r
-               {\r
-                       if(linkedAttribute[attribute].name.empty())\r
-                       {\r
-                               continue;\r
-                       }\r
-\r
-                       if(activeAttribute == index)\r
-                       {\r
-                               break;\r
-                       }\r
-\r
-                       activeAttribute++;\r
-               }\r
-\r
-               if(bufsize > 0)\r
-               {\r
-                       const char *string = linkedAttribute[attribute].name.c_str();\r
-\r
-                       strncpy(name, string, bufsize);\r
-                       name[bufsize - 1] = '\0';\r
-\r
-                       if(length)\r
-                       {\r
-                               *length = strlen(name);\r
-                       }\r
-               }\r
-\r
-               *size = 1;   // Always a single 'type' instance\r
-\r
-               *type = linkedAttribute[attribute].type;\r
-       }\r
-\r
-       GLint Program::getActiveAttributeCount() const\r
-       {\r
-               int count = 0;\r
-\r
-               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)\r
-               {\r
-                       if(!linkedAttribute[attributeIndex].name.empty())\r
-                       {\r
-                               count++;\r
-                       }\r
-               }\r
-\r
-               return count;\r
-       }\r
-\r
-       GLint Program::getActiveAttributeMaxLength() const\r
-       {\r
-               int maxLength = 0;\r
-\r
-               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)\r
-               {\r
-                       if(!linkedAttribute[attributeIndex].name.empty())\r
-                       {\r
-                               maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);\r
-                       }\r
-               }\r
-\r
-               return maxLength;\r
-       }\r
-\r
-       void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const\r
-       {\r
-               if(bufsize > 0)\r
-               {\r
-                       std::string string = uniforms[index]->name;\r
-\r
-                       if(uniforms[index]->isArray())\r
-                       {\r
-                               string += "[0]";\r
-                       }\r
-\r
-                       strncpy(name, string.c_str(), bufsize);\r
-                       name[bufsize - 1] = '\0';\r
-\r
-                       if(length)\r
-                       {\r
-                               *length = strlen(name);\r
-                       }\r
-               }\r
-\r
-               *size = uniforms[index]->size();\r
-\r
-               *type = uniforms[index]->type;\r
-       }\r
-\r
-       GLint Program::getActiveUniformCount() const\r
-       {\r
-               return uniforms.size();\r
-       }\r
-\r
-       GLint Program::getActiveUniformMaxLength() const\r
-       {\r
-               int maxLength = 0;\r
-\r
-               unsigned int numUniforms = uniforms.size();\r
-               for(unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)\r
-               {\r
-                       if(!uniforms[uniformIndex]->name.empty())\r
-                       {\r
-                               int length = (int)(uniforms[uniformIndex]->name.length() + 1);\r
-                               if(uniforms[uniformIndex]->isArray())\r
-                               {\r
-                                       length += 3;  // Counting in "[0]".\r
-                               }\r
-                               maxLength = std::max(length, maxLength);\r
-                       }\r
-               }\r
-\r
-               return maxLength;\r
-       }\r
-\r
-       void Program::flagForDeletion()\r
-       {\r
-               orphaned = true;\r
-       }\r
-\r
-       bool Program::isFlaggedForDeletion() const\r
-       {\r
-               return orphaned;\r
-       }\r
-\r
-       void Program::validate()\r
-       {\r
-               resetInfoLog();\r
-\r
-               if(!isLinked()) \r
-               {\r
-                       appendToInfoLog("Program has not been successfully linked.");\r
-                       validated = false;\r
-               }\r
-               else\r
-               {\r
-                       applyUniforms();\r
-                       if(!validateSamplers(true))\r
-                       {\r
-                               validated = false;\r
-                       }\r
-                       else\r
-                       {\r
-                               validated = true;\r
-                       }\r
-               }\r
-       }\r
-\r
-       bool Program::validateSamplers(bool logErrors)\r
-       {\r
-               // if any two active samplers in a program are of different types, but refer to the same\r
-               // texture image unit, and this is the current program, then ValidateProgram will fail, and\r
-               // DrawArrays and DrawElements will issue the INVALID_OPERATION error.\r
-\r
-               TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];\r
-\r
-               for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)\r
-               {\r
-                       textureUnitType[i] = TEXTURE_UNKNOWN;\r
-               }\r
-\r
-               for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)\r
-               {\r
-                       if(samplersPS[i].active)\r
-                       {\r
-                               unsigned int unit = samplersPS[i].logicalTextureUnit;\r
-            \r
-                               if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
-                               {\r
-                                       if(logErrors)\r
-                                       {\r
-                                               appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);\r
-                                       }\r
-\r
-                                       return false;\r
-                               }\r
-\r
-                               if(textureUnitType[unit] != TEXTURE_UNKNOWN)\r
-                               {\r
-                                       if(samplersPS[i].textureType != textureUnitType[unit])\r
-                                       {\r
-                                               if(logErrors)\r
-                                               {\r
-                                                       appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);\r
-                                               }\r
-\r
-                                               return false;\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       textureUnitType[unit] = samplersPS[i].textureType;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)\r
-               {\r
-                       if(samplersVS[i].active)\r
-                       {\r
-                               unsigned int unit = samplersVS[i].logicalTextureUnit;\r
-            \r
-                               if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)\r
-                               {\r
-                                       if(logErrors)\r
-                                       {\r
-                                               appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);\r
-                                       }\r
-\r
-                                       return false;\r
-                               }\r
-\r
-                               if(textureUnitType[unit] != TEXTURE_UNKNOWN)\r
-                               {\r
-                                       if(samplersVS[i].textureType != textureUnitType[unit])\r
-                                       {\r
-                                               if(logErrors)\r
-                                               {\r
-                                                       appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);\r
-                                               }\r
-\r
-                                               return false;\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       textureUnitType[unit] = samplersVS[i].textureType;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return true;\r
-       }\r
-}\r
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Program.cpp: Implements the Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#include "Program.h"
+
+#include "main.h"
+#include "Buffer.h"
+#include "Shader.h"
+#include "TransformFeedback.h"
+#include "utilities.h"
+#include "common/debug.h"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+
+#include <string>
+#include <stdlib.h>
+
+namespace es2
+{
+       unsigned int Program::currentSerial = 1;
+
+       std::string str(int i)
+       {
+               char buffer[20];
+               sprintf(buffer, "%d", i);
+               return buffer;
+       }
+
+       Uniform::BlockInfo::BlockInfo(const glsl::Uniform& uniform, int blockIndex)
+       {
+               if(blockIndex >= 0)
+               {
+                       index = blockIndex;
+                       offset = uniform.blockInfo.offset;
+                       arrayStride = uniform.blockInfo.arrayStride;
+                       matrixStride = uniform.blockInfo.matrixStride;
+                       isRowMajorMatrix = uniform.blockInfo.isRowMajorMatrix;
+               }
+               else
+               {
+                       index = -1;
+                       offset = -1;
+                       arrayStride = -1;
+                       matrixStride = -1;
+                       isRowMajorMatrix = false;
+               }
+       }
+
+       Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
+                        const BlockInfo &blockInfo)
+        : type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo)
+       {
+               if(blockInfo.index == -1)
+               {
+                       size_t bytes = UniformTypeSize(type) * size();
+                       data = new unsigned char[bytes];
+                       memset(data, 0, bytes);
+               }
+               else
+               {
+                       data = nullptr;
+               }
+               dirty = true;
+
+               psRegisterIndex = -1;
+               vsRegisterIndex = -1;
+       }
+
+       Uniform::~Uniform()
+       {
+               delete[] data;
+       }
+
+       bool Uniform::isArray() const
+       {
+               return arraySize >= 1;
+       }
+
+       int Uniform::size() const
+       {
+               return arraySize > 0 ? arraySize : 1;
+       }
+
+       int Uniform::registerCount() const
+       {
+               return size() * VariableRegisterCount(type);
+       }
+
+       UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes) :
+               name(name), elementIndex(elementIndex), dataSize(dataSize), memberUniformIndexes(memberUniformIndexes), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)
+       {
+       }
+
+       void UniformBlock::setRegisterIndex(GLenum shader, unsigned int registerIndex)
+       {
+               switch(shader)
+               {
+               case GL_VERTEX_SHADER:
+                       vsRegisterIndex = registerIndex;
+                       break;
+               case GL_FRAGMENT_SHADER:
+                       psRegisterIndex = registerIndex;
+                       break;
+               default:
+                       UNREACHABLE(shader);
+               }
+       }
+
+       bool UniformBlock::isArrayElement() const
+       {
+               return elementIndex != GL_INVALID_INDEX;
+       }
+
+       bool UniformBlock::isReferencedByVertexShader() const
+       {
+               return vsRegisterIndex != GL_INVALID_INDEX;
+       }
+
+       bool UniformBlock::isReferencedByFragmentShader() const
+       {
+               return psRegisterIndex != GL_INVALID_INDEX;
+       }
+
+       UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index)
+       {
+       }
+
+       LinkedVarying::LinkedVarying()
+       {
+       }
+
+       LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, int reg, int col)
+        : name(name), type(type), size(size), reg(reg), col(col)
+       {
+       }
+
+       Program::Program(ResourceManager *manager, GLuint handle) : serial(issueSerial()), resourceManager(manager), handle(handle)
+       {
+               device = getDevice();
+
+               fragmentShader = 0;
+               vertexShader = 0;
+               pixelBinary = 0;
+               vertexBinary = 0;
+
+               transformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS;
+               totalLinkedVaryingsComponents = 0;
+
+               infoLog = 0;
+               validated = false;
+
+               resetUniformBlockBindings();
+               unlink();
+
+               orphaned = false;
+               retrievableBinary = false;
+               referenceCount = 0;
+       }
+
+       Program::~Program()
+       {
+               unlink();
+
+               if(vertexShader)
+               {
+                       vertexShader->release();
+               }
+
+               if(fragmentShader)
+               {
+                       fragmentShader->release();
+               }
+       }
+
+       bool Program::attachShader(Shader *shader)
+       {
+               if(shader->getType() == GL_VERTEX_SHADER)
+               {
+                       if(vertexShader)
+                       {
+                               return false;
+                       }
+
+                       vertexShader = (VertexShader*)shader;
+                       vertexShader->addRef();
+               }
+               else if(shader->getType() == GL_FRAGMENT_SHADER)
+               {
+                       if(fragmentShader)
+                       {
+                               return false;
+                       }
+
+                       fragmentShader = (FragmentShader*)shader;
+                       fragmentShader->addRef();
+               }
+               else UNREACHABLE(shader->getType());
+
+               return true;
+       }
+
+       bool Program::detachShader(Shader *shader)
+       {
+               if(shader->getType() == GL_VERTEX_SHADER)
+               {
+                       if(vertexShader != shader)
+                       {
+                               return false;
+                       }
+
+                       vertexShader->release();
+                       vertexShader = 0;
+               }
+               else if(shader->getType() == GL_FRAGMENT_SHADER)
+               {
+                       if(fragmentShader != shader)
+                       {
+                               return false;
+                       }
+
+                       fragmentShader->release();
+                       fragmentShader = 0;
+               }
+               else UNREACHABLE(shader->getType());
+
+               return true;
+       }
+
+       int Program::getAttachedShadersCount() const
+       {
+               return (vertexShader ? 1 : 0) + (fragmentShader ? 1 : 0);
+       }
+
+       sw::PixelShader *Program::getPixelShader()
+       {
+               return pixelBinary;
+       }
+
+       sw::VertexShader *Program::getVertexShader()
+       {
+               return vertexBinary;
+       }
+
+       void Program::bindAttributeLocation(GLuint index, const char *name)
+       {
+               if(index < MAX_VERTEX_ATTRIBS)
+               {
+                       for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+                       {
+                               attributeBinding[i].erase(name);
+                       }
+
+                       attributeBinding[index].insert(name);
+               }
+       }
+
+       GLint Program::getAttributeLocation(const char *name)
+       {
+               if(name)
+               {
+                       for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+                       {
+                               if(linkedAttribute[index].name == std::string(name))
+                               {
+                                       return index;
+                               }
+                       }
+               }
+
+               return -1;
+       }
+
+       int Program::getAttributeStream(int attributeIndex)
+       {
+               ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
+
+               return attributeStream[attributeIndex];
+       }
+
+       // 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)
+       GLint Program::getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex)
+       {
+               GLint logicalTextureUnit = -1;
+
+               switch(type)
+               {
+               case sw::SAMPLER_PIXEL:
+                       ASSERT(samplerIndex < sizeof(samplersPS) / sizeof(samplersPS[0]));
+
+                       if(samplersPS[samplerIndex].active)
+                       {
+                               logicalTextureUnit = samplersPS[samplerIndex].logicalTextureUnit;
+                       }
+                       break;
+               case sw::SAMPLER_VERTEX:
+                       ASSERT(samplerIndex < sizeof(samplersVS) / sizeof(samplersVS[0]));
+
+                       if(samplersVS[samplerIndex].active)
+                       {
+                               logicalTextureUnit = samplersVS[samplerIndex].logicalTextureUnit;
+                       }
+                       break;
+               default: UNREACHABLE(type);
+               }
+
+               if(logicalTextureUnit < MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+               {
+                       return logicalTextureUnit;
+               }
+
+               return -1;
+       }
+
+       // Returns the texture type for a given sampler type and index (0-15 for the pixel shader and 0-3 for the vertex shader)
+       TextureType Program::getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex)
+       {
+               switch(type)
+               {
+               case sw::SAMPLER_PIXEL:
+                       ASSERT(samplerIndex < sizeof(samplersPS)/sizeof(samplersPS[0]));
+                       ASSERT(samplersPS[samplerIndex].active);
+                       return samplersPS[samplerIndex].textureType;
+               case sw::SAMPLER_VERTEX:
+                       ASSERT(samplerIndex < sizeof(samplersVS)/sizeof(samplersVS[0]));
+                       ASSERT(samplersVS[samplerIndex].active);
+                       return samplersVS[samplerIndex].textureType;
+               default: UNREACHABLE(type);
+               }
+
+               return TEXTURE_2D;
+       }
+
+       GLint Program::getUniformLocation(const std::string &name) const
+       {
+               unsigned int subscript = GL_INVALID_INDEX;
+               std::string baseName = es2::ParseUniformName(name, &subscript);
+
+               size_t numUniforms = uniformIndex.size();
+               for(size_t location = 0; location < numUniforms; location++)
+               {
+                       const int index = uniformIndex[location].index;
+                       const bool isArray = uniforms[index]->isArray();
+
+                       if(uniformIndex[location].name == baseName &&
+                          ((isArray && uniformIndex[location].element == subscript) ||
+                           (subscript == GL_INVALID_INDEX)))
+                       {
+                               return (GLint)location;
+                       }
+               }
+
+               return -1;
+       }
+
+       GLuint Program::getUniformIndex(const std::string &name) const
+       {
+               unsigned int subscript = GL_INVALID_INDEX;
+               std::string baseName = es2::ParseUniformName(name, &subscript);
+
+               // The app is not allowed to specify array indices other than 0 for arrays of basic types
+               if(subscript != 0 && subscript != GL_INVALID_INDEX)
+               {
+                       return GL_INVALID_INDEX;
+               }
+
+               size_t numUniforms = uniforms.size();
+               for(GLuint index = 0; index < numUniforms; index++)
+               {
+                       if(uniforms[index]->name == baseName)
+                       {
+                               if(uniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
+                               {
+                                       return index;
+                               }
+                       }
+               }
+
+               return GL_INVALID_INDEX;
+       }
+
+       void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
+       {
+               ASSERT(uniformBlockIndex < getActiveUniformBlockCount());
+
+               const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
+
+               switch(pname)
+               {
+               case GL_UNIFORM_BLOCK_DATA_SIZE:
+                       *params = static_cast<GLint>(uniformBlock.dataSize);
+                       break;
+               case GL_UNIFORM_BLOCK_NAME_LENGTH:
+                       *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
+                       break;
+               case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+                       *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
+                       break;
+               case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+                       {
+                               for(unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
+                               {
+                                       params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
+                               }
+                       }
+                       break;
+               case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+                       *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
+                       break;
+               case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+                       *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
+                       break;
+               default: UNREACHABLE(pname);
+               }
+       }
+
+       GLuint Program::getUniformBlockIndex(const std::string &name) const
+       {
+               unsigned int subscript = GL_INVALID_INDEX;
+               std::string baseName = es2::ParseUniformName(name, &subscript);
+
+               size_t numUniformBlocks = getActiveUniformBlockCount();
+               for(GLuint blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
+               {
+                       const UniformBlock &uniformBlock = *uniformBlocks[blockIndex];
+                       if(uniformBlock.name == baseName)
+                       {
+                               const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
+                               if(subscript == uniformBlock.elementIndex || arrayElementZero)
+                               {
+                                       return blockIndex;
+                               }
+                       }
+               }
+
+               return GL_INVALID_INDEX;
+       }
+
+       void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+       {
+               uniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
+       }
+
+       GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
+       {
+               return uniformBlockBindings[uniformBlockIndex];
+       }
+
+       void Program::resetUniformBlockBindings()
+       {
+               for(unsigned int blockId = 0; blockId < MAX_UNIFORM_BUFFER_BINDINGS; blockId++)
+               {
+                       uniformBlockBindings[blockId] = 0;
+               }
+       }
+
+       bool Program::setUniformfv(GLint location, GLsizei count, const GLfloat *v, int numElements)
+       {
+               ASSERT(numElements >= 1 && numElements <= 4);
+
+               static GLenum floatType[] = { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 };
+               static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
+
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               int index = numElements - 1;
+               if(targetUniform->type == floatType[index])
+               {
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat)* numElements,
+                                  v, numElements * sizeof(GLfloat)* count);
+               }
+               else if(targetUniform->type == boolType[index])
+               {
+                       GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * numElements;
+
+                       for(int i = 0; i < count * numElements; i++)
+                       {
+                               boolParams[i] = (v[i] == 0.0f) ? GL_FALSE : GL_TRUE;
+                       }
+               }
+               else
+               {
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+       {
+               return setUniformfv(location, count, v, 1);
+       }
+
+       bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               return setUniformfv(location, count, v, 2);
+       }
+
+       bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               return setUniformfv(location, count, v, 3);
+       }
+
+       bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               return setUniformfv(location, count, v, 4);
+       }
+
+       bool Program::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum type)
+       {
+               int numElements;
+               switch(type)
+               {
+               case GL_FLOAT_MAT2:
+                       numElements = 4;
+                       break;
+               case GL_FLOAT_MAT2x3:
+               case GL_FLOAT_MAT3x2:
+                       numElements = 6;
+                       break;
+               case GL_FLOAT_MAT2x4:
+               case GL_FLOAT_MAT4x2:
+                       numElements = 8;
+                       break;
+               case GL_FLOAT_MAT3:
+                       numElements = 9;
+                       break;
+               case GL_FLOAT_MAT3x4:
+               case GL_FLOAT_MAT4x3:
+                       numElements = 12;
+                       break;
+               case GL_FLOAT_MAT4:
+                       numElements = 16;
+                       break;
+               default:
+                       return false;
+               }
+
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               if(targetUniform->type != type)
+               {
+                       return false;
+               }
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               GLfloat* dst = reinterpret_cast<GLfloat*>(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * numElements);
+
+               if(transpose == GL_FALSE)
+               {
+                       memcpy(dst, value, numElements * sizeof(GLfloat) * count);
+               }
+               else
+               {
+                       const int rowSize = VariableRowCount(type);
+                       const int colSize = VariableColumnCount(type);
+                       for(int n = 0; n < count; ++n)
+                       {
+                               for(int i = 0; i < colSize; ++i)
+                               {
+                                       for(int j = 0; j < rowSize; ++j)
+                                       {
+                                               dst[i * rowSize + j] = value[j * colSize + i];
+                                       }
+                               }
+                               dst += numElements;
+                               value += numElements;
+                       }
+               }
+
+
+               return true;
+       }
+
+       bool Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2);
+       }
+
+       bool Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x3);
+       }
+
+       bool Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x4);
+       }
+
+       bool Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3);
+       }
+
+       bool Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x2);
+       }
+
+       bool Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x4);
+       }
+
+       bool Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4);
+       }
+
+       bool Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x2);
+       }
+
+       bool Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+       {
+               return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x3);
+       }
+
+       bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+       {
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               if(targetUniform->type == GL_INT || targetUniform->type == GL_UNSIGNED_INT || IsSamplerUniform(targetUniform->type))
+               {
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
+                                  v, sizeof(GLint) * count);
+               }
+               else if(targetUniform->type == GL_BOOL)
+               {
+                       GLboolean *boolParams = new GLboolean[count];
+
+                       for(int i = 0; i < count; i++)
+                       {
+                               if(v[i] == 0)
+                               {
+                                       boolParams[i] = GL_FALSE;
+                               }
+                               else
+                               {
+                                       boolParams[i] = GL_TRUE;
+                               }
+                       }
+
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
+                                  boolParams, sizeof(GLboolean) * count);
+
+                       delete[] boolParams;
+               }
+               else
+               {
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool Program::setUniformiv(GLint location, GLsizei count, const GLint *v, int numElements)
+       {
+               static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
+               static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
+               static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
+
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               int index = numElements - 1;
+               if(targetUniform->type == intType[index] || targetUniform->type == uintType[index])
+               {
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint)* numElements,
+                                  v, numElements * sizeof(GLint)* count);
+               }
+               else if(targetUniform->type == boolType[index])
+               {
+                       GLboolean *boolParams = new GLboolean[count * numElements];
+
+                       for(int i = 0; i < count * numElements; i++)
+                       {
+                               boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
+                       }
+
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
+                                  boolParams, numElements * sizeof(GLboolean)* count);
+
+                       delete[] boolParams;
+               }
+               else
+               {
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+       {
+               return setUniformiv(location, count, v, 2);
+       }
+
+       bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+       {
+               return setUniformiv(location, count, v, 3);
+       }
+
+       bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+       {
+               return setUniformiv(location, count, v, 4);
+       }
+
+       bool Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               if(targetUniform->type == GL_INT || targetUniform->type == GL_UNSIGNED_INT || IsSamplerUniform(targetUniform->type))
+               {
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint),
+                                  v, sizeof(GLuint)* count);
+               }
+               else if(targetUniform->type == GL_BOOL)
+               {
+                       GLboolean *boolParams = new GLboolean[count];
+
+                       for(int i = 0; i < count; i++)
+                       {
+                               if(v[i] == 0)
+                               {
+                                       boolParams[i] = GL_FALSE;
+                               }
+                               else
+                               {
+                                       boolParams[i] = GL_TRUE;
+                               }
+                       }
+
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean),
+                                  boolParams, sizeof(GLboolean)* count);
+
+                       delete[] boolParams;
+               }
+               else
+               {
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool Program::setUniformuiv(GLint location, GLsizei count, const GLuint *v, int numElements)
+       {
+               static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
+               static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
+               static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
+
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               targetUniform->dirty = true;
+
+               int size = targetUniform->size();
+
+               if(size == 1 && count > 1)
+               {
+                       return false;   // Attempting to write an array to a non-array uniform is an INVALID_OPERATION
+               }
+
+               count = std::min(size - (int)uniformIndex[location].element, count);
+
+               int index = numElements - 1;
+               if(targetUniform->type == uintType[index] || targetUniform->type == intType[index])
+               {
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint)* numElements,
+                                  v, numElements * sizeof(GLuint)* count);
+               }
+               else if(targetUniform->type == boolType[index])
+               {
+                       GLboolean *boolParams = new GLboolean[count * numElements];
+
+                       for(int i = 0; i < count * numElements; i++)
+                       {
+                               boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;
+                       }
+
+                       memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,
+                                  boolParams, numElements * sizeof(GLboolean)* count);
+
+                       delete[] boolParams;
+               }
+               else
+               {
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               return setUniformuiv(location, count, v, 2);
+       }
+
+       bool Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               return setUniformuiv(location, count, v, 3);
+       }
+
+       bool Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               return setUniformuiv(location, count, v, 4);
+       }
+
+       bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
+       {
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               unsigned int count = UniformComponentCount(targetUniform->type);
+
+               // Sized query - ensure the provided buffer is large enough
+               if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLfloat))
+               {
+                       return false;
+               }
+
+               switch(UniformComponentType(targetUniform->type))
+               {
+               case GL_BOOL:
+                       {
+                               GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * count;
+
+                               for(unsigned int i = 0; i < count; i++)
+                               {
+                                       params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
+                               }
+                       }
+                       break;
+               case GL_FLOAT:
+                       memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLfloat),
+                                  count * sizeof(GLfloat));
+                       break;
+               case GL_INT:
+                       {
+                               GLint *intParams = (GLint*)targetUniform->data + uniformIndex[location].element * count;
+
+                               for(unsigned int i = 0; i < count; i++)
+                               {
+                                       params[i] = (float)intParams[i];
+                               }
+                       }
+                       break;
+               case GL_UNSIGNED_INT:
+                       {
+                               GLuint *uintParams = (GLuint*)targetUniform->data + uniformIndex[location].element * count;
+
+                               for(unsigned int i = 0; i < count; i++)
+                               {
+                                       params[i] = (float)uintParams[i];
+                               }
+                       }
+                       break;
+               default: UNREACHABLE(targetUniform->type);
+               }
+
+               return true;
+       }
+
+       bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
+       {
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               unsigned int count = UniformComponentCount(targetUniform->type);
+
+               // Sized query - ensure the provided buffer is large enough
+               if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLint))
+               {
+                       return false;
+               }
+
+               switch(UniformComponentType(targetUniform->type))
+               {
+               case GL_BOOL:
+                       {
+                               GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
+
+                               for(unsigned int i = 0; i < count; i++)
+                               {
+                                       params[i] = (GLint)boolParams[i];
+                               }
+                       }
+                       break;
+               case GL_FLOAT:
+                       {
+                               GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
+
+                               for(unsigned int i = 0; i < count; i++)
+                               {
+                                       params[i] = (GLint)floatParams[i];
+                               }
+                       }
+                       break;
+               case GL_INT:
+               case GL_UNSIGNED_INT:
+                       memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),
+                                  count * sizeof(GLint));
+                       break;
+               default: UNREACHABLE(targetUniform->type);
+               }
+
+               return true;
+       }
+
+       bool Program::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
+       {
+               if(location < 0 || location >= (int)uniformIndex.size())
+               {
+                       return false;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               unsigned int count = UniformComponentCount(targetUniform->type);
+
+               // Sized query - ensure the provided buffer is large enough
+               if(bufSize && static_cast<unsigned int>(*bufSize) < count * sizeof(GLuint))
+               {
+                       return false;
+               }
+
+               switch(UniformComponentType(targetUniform->type))
+               {
+               case GL_BOOL:
+               {
+                       GLboolean *boolParams = targetUniform->data + uniformIndex[location].element * count;
+
+                       for(unsigned int i = 0; i < count; i++)
+                       {
+                               params[i] = (GLuint)boolParams[i];
+                       }
+               }
+                       break;
+               case GL_FLOAT:
+               {
+                       GLfloat *floatParams = (GLfloat*)targetUniform->data + uniformIndex[location].element * count;
+
+                       for(unsigned int i = 0; i < count; i++)
+                       {
+                               params[i] = (GLuint)floatParams[i];
+                       }
+               }
+                       break;
+               case GL_INT:
+               case GL_UNSIGNED_INT:
+                       memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLuint),
+                                  count * sizeof(GLuint));
+                       break;
+               default: UNREACHABLE(targetUniform->type);
+               }
+
+               return true;
+       }
+
+       void Program::dirtyAllUniforms()
+       {
+               size_t numUniforms = uniforms.size();
+               for(size_t index = 0; index < numUniforms; index++)
+               {
+                       uniforms[index]->dirty = true;
+               }
+       }
+
+       // Applies all the uniforms set for this program object to the device
+       void Program::applyUniforms()
+       {
+               GLint numUniforms = static_cast<GLint>(uniformIndex.size());
+               for(GLint location = 0; location < numUniforms; location++)
+               {
+                       if(uniformIndex[location].element != 0)
+                       {
+                               continue;
+                       }
+
+                       Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+                       if(targetUniform->dirty && (targetUniform->blockInfo.index == -1))
+                       {
+                               GLsizei size = targetUniform->size();
+                               GLfloat *f = (GLfloat*)targetUniform->data;
+                               GLint *i = (GLint*)targetUniform->data;
+                               GLuint *ui = (GLuint*)targetUniform->data;
+                               GLboolean *b = (GLboolean*)targetUniform->data;
+
+                               switch(targetUniform->type)
+                               {
+                               case GL_BOOL:       applyUniform1bv(location, size, b);       break;
+                               case GL_BOOL_VEC2:  applyUniform2bv(location, size, b);       break;
+                               case GL_BOOL_VEC3:  applyUniform3bv(location, size, b);       break;
+                               case GL_BOOL_VEC4:  applyUniform4bv(location, size, b);       break;
+                               case GL_FLOAT:      applyUniform1fv(location, size, f);       break;
+                               case GL_FLOAT_VEC2: applyUniform2fv(location, size, f);       break;
+                               case GL_FLOAT_VEC3: applyUniform3fv(location, size, f);       break;
+                               case GL_FLOAT_VEC4: applyUniform4fv(location, size, f);       break;
+                               case GL_FLOAT_MAT2:   applyUniformMatrix2fv(location, size, f);   break;
+                               case GL_FLOAT_MAT2x3: applyUniformMatrix2x3fv(location, size, f); break;
+                               case GL_FLOAT_MAT2x4: applyUniformMatrix2x4fv(location, size, f); break;
+                               case GL_FLOAT_MAT3x2: applyUniformMatrix3x2fv(location, size, f); break;
+                               case GL_FLOAT_MAT3:   applyUniformMatrix3fv(location, size, f);   break;
+                               case GL_FLOAT_MAT3x4: applyUniformMatrix3x4fv(location, size, f); break;
+                               case GL_FLOAT_MAT4x2: applyUniformMatrix4x2fv(location, size, f); break;
+                               case GL_FLOAT_MAT4x3: applyUniformMatrix4x3fv(location, size, f); break;
+                               case GL_FLOAT_MAT4:   applyUniformMatrix4fv(location, size, f);   break;
+                               case GL_SAMPLER_2D:
+                               case GL_SAMPLER_CUBE:
+                               case GL_SAMPLER_EXTERNAL_OES:
+                               case GL_SAMPLER_3D_OES:
+                               case GL_SAMPLER_2D_ARRAY:
+                               case GL_SAMPLER_2D_SHADOW:
+                               case GL_SAMPLER_CUBE_SHADOW:
+                               case GL_SAMPLER_2D_ARRAY_SHADOW:
+                               case GL_INT_SAMPLER_2D:
+                               case GL_UNSIGNED_INT_SAMPLER_2D:
+                               case GL_INT_SAMPLER_CUBE:
+                               case GL_UNSIGNED_INT_SAMPLER_CUBE:
+                               case GL_INT_SAMPLER_3D:
+                               case GL_UNSIGNED_INT_SAMPLER_3D:
+                               case GL_INT_SAMPLER_2D_ARRAY:
+                               case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+                               case GL_INT:        applyUniform1iv(location, size, i);       break;
+                               case GL_INT_VEC2:   applyUniform2iv(location, size, i);       break;
+                               case GL_INT_VEC3:   applyUniform3iv(location, size, i);       break;
+                               case GL_INT_VEC4:   applyUniform4iv(location, size, i);       break;
+                               case GL_UNSIGNED_INT:      applyUniform1uiv(location, size, ui); break;
+                               case GL_UNSIGNED_INT_VEC2: applyUniform2uiv(location, size, ui); break;
+                               case GL_UNSIGNED_INT_VEC3: applyUniform3uiv(location, size, ui); break;
+                               case GL_UNSIGNED_INT_VEC4: applyUniform4uiv(location, size, ui); break;
+                               default:
+                                       UNREACHABLE(targetUniform->type);
+                               }
+
+                               targetUniform->dirty = false;
+                       }
+               }
+       }
+
+       void Program::applyUniformBuffers(BufferBinding* uniformBuffers)
+       {
+               GLint vertexUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
+               GLint fragmentUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
+
+               for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
+               {
+                       vertexUniformBuffers[bufferBindingIndex] = -1;
+               }
+
+               for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
+               {
+                       fragmentUniformBuffers[bufferBindingIndex] = -1;
+               }
+
+               int vertexUniformBufferIndex = 0;
+               int fragmentUniformBufferIndex = 0;
+               for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)
+               {
+                       UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
+
+                       // Unnecessary to apply an unreferenced standard or shared UBO
+                       if(!uniformBlock.isReferencedByVertexShader() && !uniformBlock.isReferencedByFragmentShader())
+                       {
+                               continue;
+                       }
+
+                       GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];
+
+                       if(uniformBlock.isReferencedByVertexShader())
+                       {
+                               vertexUniformBuffers[vertexUniformBufferIndex++] = blockBinding;
+                       }
+
+                       if(uniformBlock.isReferencedByFragmentShader())
+                       {
+                               fragmentUniformBuffers[fragmentUniformBufferIndex++] = blockBinding;
+                       }
+               }
+
+               for(unsigned int bufferBindingIndex = 0; bufferBindingIndex < MAX_UNIFORM_BUFFER_BINDINGS; bufferBindingIndex++)
+               {
+                       int index = vertexUniformBuffers[bufferBindingIndex];
+                       const gl::BindingPointer<Buffer> &buffer = uniformBuffers[index].get();
+
+                       if(buffer)
+                       {
+                               device->VertexProcessor::setUniformBuffer(bufferBindingIndex, (index != -1) ? buffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
+                               index = fragmentUniformBuffers[bufferBindingIndex];
+                               device->PixelProcessor::setUniformBuffer(bufferBindingIndex, (index != -1) ? buffer->getResource() : nullptr, (index != -1) ? uniformBuffers[index].getOffset() : 0);
+                       }
+               }
+       }
+
+       void Program::applyTransformFeedback(TransformFeedback* transformFeedback)
+       {
+               // Make sure the flags will fit in a 64 bit unsigned int variable
+               ASSERT(sw::max<int>(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) <= 64);
+
+               BufferBinding* transformFeedbackBuffers = (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused()) ? transformFeedback->getBuffers() : nullptr;
+
+               uint64_t enableTransformFeedback = 0;
+               if(!transformFeedbackBuffers)
+               {
+                       for(unsigned int index = 0; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
+                       {
+                               device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
+                       }
+                       device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
+                       return;
+               }
+
+               unsigned int maxVaryings = static_cast<unsigned int>(transformFeedbackLinkedVaryings.size());
+               switch(transformFeedbackBufferMode)
+               {
+               case GL_SEPARATE_ATTRIBS:
+               {
+                       maxVaryings = sw::min(maxVaryings, (unsigned int)MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
+                       // Attribs go to separate buffers
+                       for(unsigned int index = 0; index < maxVaryings; ++index)
+                       {
+                               int size = transformFeedbackLinkedVaryings[index].size;
+                               int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
+                               int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
+                               int nbRegs = rowCount > 1 ? colCount * size : size;
+                               int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
+                               int componentStride = rowCount * colCount * size;
+                               int baseOffset = transformFeedback->vertexOffset() * componentStride * sizeof(float);
+                               device->VertexProcessor::setTransformFeedbackBuffer(index,
+                                       transformFeedbackBuffers[index].get()->getResource(),
+                                       transformFeedbackBuffers[index].getOffset() + baseOffset,
+                                       transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
+                                       nbRegs, nbComponentsPerReg, componentStride);
+                               enableTransformFeedback |= 1ULL << index;
+                       }
+               }
+                       break;
+               case GL_INTERLEAVED_ATTRIBS:
+               {
+                       // OpenGL ES 3.0.4 spec, section 2.15.2:
+                       // In INTERLEAVED_ATTRIBS mode, the values of one or more output variables
+                       // written by a vertex shader are written, interleaved, into the buffer object
+                       // bound to the first transform feedback binding point (index = 0).
+                       sw::Resource* resource = transformFeedbackBuffers[0].get()->getResource();
+                       int componentStride = static_cast<int>(totalLinkedVaryingsComponents);
+                       int baseOffset = transformFeedbackBuffers[0].getOffset() + (transformFeedback->vertexOffset() * componentStride * sizeof(float));
+                       maxVaryings = sw::min(maxVaryings, (unsigned int)sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
+                       int totalComponents = 0;
+                       for(unsigned int index = 0; index < maxVaryings; ++index)
+                       {
+                               int size = transformFeedbackLinkedVaryings[index].size;
+                               int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
+                               int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
+                               int nbRegs = rowCount > 1 ? colCount * size : size;
+                               int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
+                               device->VertexProcessor::setTransformFeedbackBuffer(index, resource,
+                                       baseOffset + (totalComponents * sizeof(float)),
+                                       transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
+                                       nbRegs, nbComponentsPerReg, componentStride);
+                               totalComponents += rowCount * colCount * size;
+                               enableTransformFeedback |= 1ULL << index;
+                       }
+               }
+                       break;
+               default:
+                       UNREACHABLE(transformFeedbackBufferMode);
+                       break;
+               }
+
+               // Unset all other transform feedback buffers
+               for(unsigned int index = maxVaryings; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
+               {
+                       device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
+               }
+
+               device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
+       }
+
+       bool Program::linkVaryings()
+       {
+               for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); ++input)
+               {
+                       bool matched = false;
+
+                       for(glsl::VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); ++output)
+                       {
+                               if(output->name == input->name)
+                               {
+                                       if(output->type != input->type || output->size() != input->size())
+                                       {
+                                               appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+
+                                               return false;
+                                       }
+
+                                       matched = true;
+                                       break;
+                               }
+                       }
+
+                       if(!matched)
+                       {
+                               appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
+
+                               return false;
+                       }
+               }
+
+               glsl::VaryingList &psVaryings = fragmentShader->varyings;
+               glsl::VaryingList &vsVaryings = vertexShader->varyings;
+
+               for(glsl::VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); ++output)
+               {
+                       bool matched = false;
+
+                       for(glsl::VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); ++input)
+                       {
+                               if(output->name == input->name)
+                               {
+                                       int in = input->reg;
+                                       int out = output->reg;
+                                       int components = VariableRegisterSize(output->type);
+                                       int registers = VariableRegisterCount(output->type) * output->size();
+
+                                       ASSERT(in >= 0);
+
+                                       if(in + registers > MAX_VARYING_VECTORS)
+                                       {
+                                               appendToInfoLog("Too many varyings");
+                                               return false;
+                                       }
+
+                                       if(out >= 0)
+                                       {
+                                               if(out + registers > MAX_VARYING_VECTORS)
+                                               {
+                                                       appendToInfoLog("Too many varyings");
+                                                       return false;
+                                               }
+
+                                               for(int i = 0; i < registers; i++)
+                                               {
+                                                       vertexBinary->setOutput(out + i, components, sw::Shader::Semantic(sw::Shader::USAGE_COLOR, in + i, pixelBinary->getInput(in + i, 0).flat));
+                                               }
+                                       }
+                                       else   // Vertex varying is declared but not written to
+                                       {
+                                               for(int i = 0; i < registers; i++)
+                                               {
+                                                       pixelBinary->setInput(in + i, components, sw::Shader::Semantic());
+                                               }
+                                       }
+
+                                       matched = true;
+                                       break;
+                               }
+                       }
+
+                       // For openGL ES 3.0, we need to still add the vertex shader outputs for unmatched varyings, for transform feedback.
+                       if(!matched && (egl::getClientVersion() >= 3))
+                       {
+                               int out = output->reg;
+                               int components = VariableRegisterSize(output->type);
+                               int registers = VariableRegisterCount(output->type) * output->size();
+
+                               if(out >= 0)
+                               {
+                                       if(out + registers > MAX_VARYING_VECTORS)
+                                       {
+                                               appendToInfoLog("Too many varyings");
+                                               return false;
+                                       }
+
+                                       for(int i = 0; i < registers; i++)
+                                       {
+                                               vertexBinary->setOutput(out + i, components, sw::Shader::Semantic(sw::Shader::USAGE_COLOR));
+                                       }
+                               }
+                       }
+               }
+
+               return true;
+       }
+
+       bool Program::linkTransformFeedback()
+       {
+               size_t totalComponents = 0;
+               totalLinkedVaryingsComponents = 0;
+
+               std::set<std::string> uniqueNames;
+
+               for(const std::string &indexedTfVaryingName : transformFeedbackVaryings)
+               {
+                       unsigned int subscript = GL_INVALID_INDEX;
+                       std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, &subscript);
+                       bool hasSubscript = (subscript != GL_INVALID_INDEX);
+
+                       if(tfVaryingName.find('[') != std::string::npos)
+                       {
+                               appendToInfoLog("Capture of array sub-elements is undefined and not supported.");
+                               return false;
+                       }
+
+                       bool found = false;
+                       for(const glsl::Varying varying : vertexShader->varyings)
+                       {
+                               if(tfVaryingName == varying.name)
+                               {
+                                       if(uniqueNames.count(indexedTfVaryingName) > 0)
+                                       {
+                                               appendToInfoLog("Two transform feedback varyings specify the same output variable (%s)", indexedTfVaryingName.c_str());
+                                               return false;
+                                       }
+                                       uniqueNames.insert(indexedTfVaryingName);
+
+                                       if(hasSubscript && ((static_cast<int>(subscript)) >= varying.size()))
+                                       {
+                                               appendToInfoLog("Specified transform feedback varying index out of bounds (%s)", indexedTfVaryingName.c_str());
+                                               return false;
+                                       }
+
+                                       int size = hasSubscript ? 1 : varying.size();
+
+                                       int rowCount = VariableRowCount(varying.type);
+                                       int colCount = VariableColumnCount(varying.type);
+                                       int componentCount = rowCount * colCount * size;
+                                       if(transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
+                                          componentCount > sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS)
+                                       {
+                                               appendToInfoLog("Transform feedback varying's %s components (%d) exceed the maximum separate components (%d).",
+                                                               varying.name.c_str(), componentCount, sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
+                                               return false;
+                                       }
+
+                                       totalComponents += componentCount;
+
+                                       int reg = varying.reg;
+                                       if(hasSubscript)
+                                       {
+                                               reg += rowCount > 1 ? colCount * subscript : subscript;
+                                       }
+                                       int col = varying.col;
+                                       if(tfVaryingName == "gl_PointSize")
+                                       {
+                                               // Point size is stored in the y element of the vector, not the x element
+                                               col = 1; // FIXME: varying.col could already contain this information
+                                       }
+                                       transformFeedbackLinkedVaryings.push_back(LinkedVarying(varying.name, varying.type, size, reg, col));
+
+                                       found = true;
+                                       break;
+                               }
+                       }
+
+                       if(!found)
+                       {
+                               appendToInfoLog("Transform feedback varying %s does not exist in the vertex shader.", tfVaryingName.c_str());
+                               return false;
+                       }
+               }
+
+               if(transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
+                  totalComponents > sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS)
+               {
+                       appendToInfoLog("Transform feedback varying total components (%d) exceed the maximum separate components (%d).",
+                                       totalComponents, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
+                       return false;
+               }
+
+               totalLinkedVaryingsComponents = totalComponents;
+
+               return true;
+       }
+
+       // Links the code of the vertex and pixel shader by matching up their varyings,
+       // compiling them into binaries, determining the attribute mappings, and collecting
+       // a list of uniforms
+       void Program::link()
+       {
+               unlink();
+
+               resetUniformBlockBindings();
+
+               if(!fragmentShader || !fragmentShader->isCompiled())
+               {
+                       return;
+               }
+
+               if(!vertexShader || !vertexShader->isCompiled())
+               {
+                       return;
+               }
+
+               vertexBinary = new sw::VertexShader(vertexShader->getVertexShader());
+               pixelBinary = new sw::PixelShader(fragmentShader->getPixelShader());
+
+               if(!linkVaryings())
+               {
+                       return;
+               }
+
+               if(!linkAttributes())
+               {
+                       return;
+               }
+
+               // Link uniform blocks before uniforms to make it easy to assign block indices to fields
+               if(!linkUniformBlocks(vertexShader, fragmentShader))
+               {
+                       return;
+               }
+
+               if(!linkUniforms(fragmentShader))
+               {
+                       return;
+               }
+
+               if(!linkUniforms(vertexShader))
+               {
+                       return;
+               }
+
+               if(!linkTransformFeedback())
+               {
+                       return;
+               }
+
+               linked = true;   // Success
+       }
+
+       // Determines the mapping between GL attributes and vertex stream usage indices
+       bool Program::linkAttributes()
+       {
+               unsigned int usedLocations = 0;
+
+               // Link attributes that have a binding location
+               for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); ++attribute)
+               {
+                       int location = getAttributeBinding(*attribute);
+
+                       if(location != -1)   // Set by glBindAttribLocation
+                       {
+                               int rows = VariableRegisterCount(attribute->type);
+
+                               if(rows + location > MAX_VERTEX_ATTRIBS)
+                               {
+                                       appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+                                       return false;
+                               }
+
+                               // In GLSL 3.00, attribute aliasing produces a link error
+                               // In GLSL 1.00, attribute aliasing is allowed
+                               if(egl::getClientVersion() >= 3)
+                               {
+                                       for(int i = 0; i < rows; i++)
+                                       {
+                                               if(!linkedAttribute[location + i].name.empty())
+                                               {
+                                                       appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute->name.c_str(), linkedAttribute[location].name.c_str(), location);
+                                                       return false;
+                                               }
+                                       }
+                               }
+
+                               for(int i = 0; i < rows; i++)
+                               {
+                                       linkedAttribute[location + i] = *attribute;
+                                       usedLocations |= 1 << (location + i);
+                               }
+                       }
+               }
+
+               // Link attributes that don't have a binding location
+               for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); ++attribute)
+               {
+                       int location = getAttributeBinding(*attribute);
+
+                       if(location == -1)   // Not set by glBindAttribLocation
+                       {
+                               int rows = VariableRegisterCount(attribute->type);
+                               int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
+
+                               if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
+                               {
+                                       appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
+                                       return false;   // Fail to link
+                               }
+
+                               for(int i = 0; i < rows; i++)
+                               {
+                                       linkedAttribute[availableIndex + i] = *attribute;
+                               }
+                       }
+               }
+
+               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+               {
+                       int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);
+                       int rows = std::max(VariableRegisterCount(linkedAttribute[attributeIndex].type), 1);
+
+                       for(int r = 0; r < rows; r++)
+                       {
+                               attributeStream[attributeIndex++] = index++;
+                       }
+               }
+
+               return true;
+       }
+
+       int Program::getAttributeBinding(const glsl::Attribute &attribute)
+       {
+               if(attribute.location != -1)
+               {
+                       return attribute.location;
+               }
+
+               for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
+               {
+                       if(attributeBinding[location].find(attribute.name.c_str()) != attributeBinding[location].end())
+                       {
+                               return location;
+                       }
+               }
+
+               return -1;
+       }
+
+       bool Program::linkUniforms(const Shader *shader)
+       {
+               const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;
+
+               for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
+               {
+                       const glsl::Uniform &uniform = activeUniforms[uniformIndex];
+
+                       unsigned int blockIndex = GL_INVALID_INDEX;
+                       if(uniform.blockId >= 0)
+                       {
+                               const glsl::ActiveUniformBlocks &activeUniformBlocks = shader->activeUniformBlocks;
+                               ASSERT(static_cast<size_t>(uniform.blockId) < activeUniformBlocks.size());
+                               blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].name);
+                               ASSERT(blockIndex != GL_INVALID_INDEX);
+                       }
+                       if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex)))
+                       {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
+       bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo)
+       {
+               if(IsSamplerUniform(type))
+           {
+                       int index = registerIndex;
+
+                       do
+                       {
+                               if(shader == GL_VERTEX_SHADER)
+                               {
+                                       if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               samplersVS[index].active = true;
+
+                                               switch(type)
+                                               {
+                                               default:                      UNREACHABLE(type);
+                                               case GL_INT_SAMPLER_2D:
+                                               case GL_UNSIGNED_INT_SAMPLER_2D:
+                                               case GL_SAMPLER_2D_SHADOW:
+                                               case GL_SAMPLER_2D:           samplersVS[index].textureType = TEXTURE_2D;       break;
+                                               case GL_INT_SAMPLER_CUBE:
+                                               case GL_UNSIGNED_INT_SAMPLER_CUBE:
+                                               case GL_SAMPLER_CUBE_SHADOW:
+                                               case GL_SAMPLER_CUBE:         samplersVS[index].textureType = TEXTURE_CUBE;     break;
+                                               case GL_INT_SAMPLER_3D:
+                                               case GL_UNSIGNED_INT_SAMPLER_3D:
+                                               case GL_SAMPLER_3D_OES:       samplersVS[index].textureType = TEXTURE_3D;       break;
+                                               case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;
+                                               case GL_INT_SAMPLER_2D_ARRAY:
+                                               case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+                                               case GL_SAMPLER_2D_ARRAY_SHADOW:
+                                               case GL_SAMPLER_2D_ARRAY:     samplersVS[index].textureType = TEXTURE_2D_ARRAY; break;
+                                               }
+
+                                               samplersVS[index].logicalTextureUnit = 0;
+                                       }
+                                       else
+                                       {
+                                          appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+                                          return false;
+                                       }
+                               }
+                               else if(shader == GL_FRAGMENT_SHADER)
+                               {
+                                       if(index < MAX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               samplersPS[index].active = true;
+
+                                               switch(type)
+                                               {
+                                               default:                      UNREACHABLE(type);
+                                               case GL_INT_SAMPLER_2D:
+                                               case GL_UNSIGNED_INT_SAMPLER_2D:
+                                               case GL_SAMPLER_2D_SHADOW:
+                                               case GL_SAMPLER_2D:           samplersPS[index].textureType = TEXTURE_2D;       break;
+                                               case GL_INT_SAMPLER_CUBE:
+                                               case GL_UNSIGNED_INT_SAMPLER_CUBE:
+                                               case GL_SAMPLER_CUBE_SHADOW:
+                                               case GL_SAMPLER_CUBE:         samplersPS[index].textureType = TEXTURE_CUBE;     break;
+                                               case GL_INT_SAMPLER_3D:
+                                               case GL_UNSIGNED_INT_SAMPLER_3D:
+                                               case GL_SAMPLER_3D_OES:       samplersPS[index].textureType = TEXTURE_3D;       break;
+                                               case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;
+                                               case GL_INT_SAMPLER_2D_ARRAY:
+                                               case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+                                               case GL_SAMPLER_2D_ARRAY_SHADOW:
+                                               case GL_SAMPLER_2D_ARRAY:     samplersPS[index].textureType = TEXTURE_2D_ARRAY; break;
+                                               }
+
+                                               samplersPS[index].logicalTextureUnit = 0;
+                                       }
+                                       else
+                                       {
+                                               appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
+                                               return false;
+                                       }
+                               }
+                               else UNREACHABLE(shader);
+
+                               index++;
+                       }
+                       while(index < registerIndex + static_cast<int>(arraySize));
+           }
+
+               Uniform *uniform = 0;
+               GLint location = getUniformLocation(name);
+
+               if(location >= 0)   // Previously defined, types must match
+               {
+                       uniform = uniforms[uniformIndex[location].index];
+
+                       if(uniform->type != type)
+                       {
+                               appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+                               return false;
+                       }
+
+                       if(uniform->precision != precision)
+                       {
+                               appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+                               return false;
+                       }
+               }
+               else
+               {
+                       uniform = new Uniform(type, precision, name, arraySize, blockInfo);
+               }
+
+               if(!uniform)
+               {
+                       return false;
+               }
+
+               if(shader == GL_VERTEX_SHADER)
+               {
+                       uniform->vsRegisterIndex = registerIndex;
+               }
+               else if(shader == GL_FRAGMENT_SHADER)
+               {
+                       uniform->psRegisterIndex = registerIndex;
+               }
+               else UNREACHABLE(shader);
+
+               if(location == -1)   // Not previously defined
+               {
+                       uniforms.push_back(uniform);
+                       unsigned int index = static_cast<unsigned int>(uniforms.size() - 1);
+
+                       for(int i = 0; i < uniform->size(); i++)
+                       {
+                               uniformIndex.push_back(UniformLocation(name, i, index));
+                       }
+               }
+
+               if(shader == GL_VERTEX_SHADER)
+               {
+                       if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
+                       {
+                               appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
+                               return false;
+                       }
+               }
+               else if(shader == GL_FRAGMENT_SHADER)
+               {
+                       if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
+                       {
+                               appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
+                               return false;
+                       }
+               }
+               else UNREACHABLE(shader);
+
+               return true;
+       }
+
+       bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)
+       {
+               // validate blocks for the same member types
+               if(block1.fields.size() != block2.fields.size())
+               {
+                       return false;
+               }
+               if(block1.arraySize != block2.arraySize)
+               {
+                       return false;
+               }
+               if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)
+               {
+                       return false;
+               }
+               const size_t numBlockMembers = block1.fields.size();
+               for(size_t blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
+               {
+                       const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];
+                       const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];
+                       if(member1.name != member2.name ||
+                          member1.arraySize != member2.arraySize ||
+                          member1.precision != member2.precision ||
+                          member1.type != member2.type)
+                       {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)
+       {
+               const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;
+               const glsl::ActiveUniformBlocks &fragmentUniformBlocks = fragmentShader->activeUniformBlocks;
+               // Check that interface blocks defined in the vertex and fragment shaders are identical
+               typedef std::map<std::string, const glsl::UniformBlock*> UniformBlockMap;
+               UniformBlockMap linkedUniformBlocks;
+               for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
+               {
+                       const glsl::UniformBlock &vertexUniformBlock = vertexUniformBlocks[blockIndex];
+                       linkedUniformBlocks[vertexUniformBlock.name] = &vertexUniformBlock;
+               }
+               for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
+               {
+                       const glsl::UniformBlock &fragmentUniformBlock = fragmentUniformBlocks[blockIndex];
+                       UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentUniformBlock.name);
+                       if(entry != linkedUniformBlocks.end())
+                       {
+                               const glsl::UniformBlock &vertexUniformBlock = *entry->second;
+                               if(!areMatchingUniformBlocks(vertexUniformBlock, fragmentUniformBlock, vertexShader, fragmentShader))
+                               {
+                                       return false;
+                               }
+                       }
+               }
+               for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)
+               {
+                       const glsl::UniformBlock &uniformBlock = vertexUniformBlocks[blockIndex];
+                       if(!defineUniformBlock(vertexShader, uniformBlock))
+                       {
+                               return false;
+                       }
+               }
+               for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)
+               {
+                       const glsl::UniformBlock &uniformBlock = fragmentUniformBlocks[blockIndex];
+                       if(!defineUniformBlock(fragmentShader, uniformBlock))
+                       {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       bool Program::defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block)
+       {
+               GLuint blockIndex = getUniformBlockIndex(block.name);
+
+               if(blockIndex == GL_INVALID_INDEX)
+               {
+                       const std::vector<int>& fields = block.fields;
+                       std::vector<unsigned int> memberUniformIndexes;
+                       for(size_t i = 0; i < fields.size(); ++i)
+                       {
+                               memberUniformIndexes.push_back(fields[i]);
+                       }
+
+                       if(block.arraySize > 0)
+                       {
+                               int regIndex = block.registerIndex;
+                               int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
+                               for(unsigned int i = 0; i < block.arraySize; ++i, regIndex += regInc)
+                               {
+                                       uniformBlocks.push_back(new UniformBlock(block.name, i, block.dataSize, memberUniformIndexes));
+                                       uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), regIndex);
+                               }
+                       }
+                       else
+                       {
+                               uniformBlocks.push_back(new UniformBlock(block.name, GL_INVALID_INDEX, block.dataSize, memberUniformIndexes));
+                               uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), block.registerIndex);
+                       }
+               }
+               else
+               {
+                       int regIndex = block.registerIndex;
+                       int regInc = block.dataSize / (glsl::BlockLayoutEncoder::BytesPerComponent * glsl::BlockLayoutEncoder::ComponentsPerRegister);
+                       int nbBlocks = (block.arraySize > 0) ? block.arraySize : 1;
+                       for(int i = 0; i < nbBlocks; ++i, regIndex += regInc)
+                       {
+                               uniformBlocks[blockIndex + i]->setRegisterIndex(shader->getType(), regIndex);
+                       }
+               }
+
+               return true;
+       }
+
+       bool Program::applyUniform(GLint location, float* data)
+       {
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+
+               if(targetUniform->psRegisterIndex != -1)
+               {
+                       device->setPixelShaderConstantF(targetUniform->psRegisterIndex, data, targetUniform->registerCount());
+               }
+
+               if(targetUniform->vsRegisterIndex != -1)
+               {
+                       device->setVertexShaderConstantF(targetUniform->vsRegisterIndex, data, targetUniform->registerCount());
+               }
+
+               return true;
+       }
+
+       bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
+       {
+               int vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][1] = 0;
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 1;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
+       {
+               int vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 2;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
+       {
+               int vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][3] = 0;
+
+                       v += 3;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
+       {
+               int vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = (v[0] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][1] = (v[1] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][2] = (v[2] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+                       vector[i][3] = (v[3] == GL_FALSE ? 0x00000000 : 0xFFFFFFFF);
+
+                       v += 4;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               float vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = 0;
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 1;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               float vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 2;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               float vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = v[2];
+                       vector[i][3] = 0;
+
+                       v += 3;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+       {
+               return applyUniform(location, (float*)v);
+       }
+
+       bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = 0; matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[2];     matrix[i][1][1] = value[3];     matrix[i][1][2] = 0; matrix[i][1][3] = 0;
+
+                       value += 4;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2]; matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[3];     matrix[i][1][1] = value[4];     matrix[i][1][2] = value[5]; matrix[i][1][3] = 0;
+
+                       value += 6;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 1) / 2][2][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2]; matrix[i][0][3] = value[3];
+                       matrix[i][1][0] = value[4];     matrix[i][1][1] = value[5];     matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];
+
+                       value += 8;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2];     matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[3];     matrix[i][1][1] = value[4];     matrix[i][1][2] = value[5];     matrix[i][1][3] = 0;
+                       matrix[i][2][0] = value[6];     matrix[i][2][1] = value[7];     matrix[i][2][2] = value[8];     matrix[i][2][3] = 0;
+
+                       value += 9;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = 0; matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[2];     matrix[i][1][1] = value[3];     matrix[i][1][2] = 0; matrix[i][1][3] = 0;
+                       matrix[i][2][0] = value[4];     matrix[i][2][1] = value[5];     matrix[i][2][2] = 0; matrix[i][2][3] = 0;
+
+                       value += 6;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 2) / 3][3][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = value[2];     matrix[i][0][3] = value[3];
+                       matrix[i][1][0] = value[4];     matrix[i][1][1] = value[5];     matrix[i][1][2] = value[6];     matrix[i][1][3] = value[7];
+                       matrix[i][2][0] = value[8];     matrix[i][2][1] = value[9];     matrix[i][2][2] = value[10];    matrix[i][2][3] = value[11];
+
+                       value += 12;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               return applyUniform(location, (float*)value);
+       }
+
+       bool Program::applyUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];     matrix[i][0][2] = 0; matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[2];     matrix[i][1][1] = value[3];     matrix[i][1][2] = 0; matrix[i][1][3] = 0;
+                       matrix[i][2][0] = value[4];     matrix[i][2][1] = value[5];     matrix[i][2][2] = 0; matrix[i][2][3] = 0;
+                       matrix[i][3][0] = value[6];     matrix[i][3][1] = value[7];     matrix[i][3][2] = 0; matrix[i][3][3] = 0;
+
+                       value += 8;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value)
+       {
+               float matrix[(MAX_UNIFORM_VECTORS + 3) / 4][4][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       matrix[i][0][0] = value[0];     matrix[i][0][1] = value[1];  matrix[i][0][2] = value[2];  matrix[i][0][3] = 0;
+                       matrix[i][1][0] = value[3];     matrix[i][1][1] = value[4];  matrix[i][1][2] = value[5];  matrix[i][1][3] = 0;
+                       matrix[i][2][0] = value[6];     matrix[i][2][1] = value[7];  matrix[i][2][2] = value[8];  matrix[i][2][3] = 0;
+                       matrix[i][3][0] = value[9];     matrix[i][3][1] = value[10]; matrix[i][3][2] = value[11]; matrix[i][3][3] = 0;
+
+                       value += 12;
+               }
+
+               return applyUniform(location, (float*)matrix);
+       }
+
+       bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
+       {
+               GLint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[i];
+                       vector[i][1] = 0;
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               if(IsSamplerUniform(targetUniform->type))
+               {
+                       if(targetUniform->psRegisterIndex != -1)
+                       {
+                               for(int i = 0; i < count; i++)
+                               {
+                                       unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
+
+                                       if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               ASSERT(samplersPS[samplerIndex].active);
+                                               samplersPS[samplerIndex].logicalTextureUnit = v[i];
+                                       }
+                               }
+                       }
+
+                       if(targetUniform->vsRegisterIndex != -1)
+                       {
+                               for(int i = 0; i < count; i++)
+                               {
+                                       unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
+
+                                       if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               ASSERT(samplersVS[samplerIndex].active);
+                                               samplersVS[samplerIndex].logicalTextureUnit = v[i];
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       return applyUniform(location, (float*)vector);
+               }
+
+               return true;
+       }
+
+       bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
+       {
+               GLint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 2;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
+       {
+               GLint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = v[2];
+                       vector[i][3] = 0;
+
+                       v += 3;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
+       {
+               GLint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = v[2];
+                       vector[i][3] = v[3];
+
+                       v += 4;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform1uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               GLuint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[i];
+                       vector[i][1] = 0;
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+               }
+
+               Uniform *targetUniform = uniforms[uniformIndex[location].index];
+               if(IsSamplerUniform(targetUniform->type))
+               {
+                       if(targetUniform->psRegisterIndex != -1)
+                       {
+                               for(int i = 0; i < count; i++)
+                               {
+                                       unsigned int samplerIndex = targetUniform->psRegisterIndex + i;
+
+                                       if(samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               ASSERT(samplersPS[samplerIndex].active);
+                                               samplersPS[samplerIndex].logicalTextureUnit = v[i];
+                                       }
+                               }
+                       }
+
+                       if(targetUniform->vsRegisterIndex != -1)
+                       {
+                               for(int i = 0; i < count; i++)
+                               {
+                                       unsigned int samplerIndex = targetUniform->vsRegisterIndex + i;
+
+                                       if(samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+                                       {
+                                               ASSERT(samplersVS[samplerIndex].active);
+                                               samplersVS[samplerIndex].logicalTextureUnit = v[i];
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       return applyUniform(location, (float*)vector);
+               }
+
+               return true;
+       }
+
+       bool Program::applyUniform2uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               GLuint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = 0;
+                       vector[i][3] = 0;
+
+                       v += 2;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform3uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               GLuint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = v[2];
+                       vector[i][3] = 0;
+
+                       v += 3;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       bool Program::applyUniform4uiv(GLint location, GLsizei count, const GLuint *v)
+       {
+               GLuint vector[MAX_UNIFORM_VECTORS][4];
+
+               for(int i = 0; i < count; i++)
+               {
+                       vector[i][0] = v[0];
+                       vector[i][1] = v[1];
+                       vector[i][2] = v[2];
+                       vector[i][3] = v[3];
+
+                       v += 4;
+               }
+
+               return applyUniform(location, (float*)vector);
+       }
+
+       void Program::appendToInfoLog(const char *format, ...)
+       {
+               if(!format)
+               {
+                       return;
+               }
+
+               char info[1024];
+
+               va_list vararg;
+               va_start(vararg, format);
+               vsnprintf(info, sizeof(info), format, vararg);
+               va_end(vararg);
+
+               size_t infoLength = strlen(info);
+
+               if(!infoLog)
+               {
+                       infoLog = new char[infoLength + 2];
+                       strcpy(infoLog, info);
+                       strcpy(infoLog + infoLength, "\n");
+               }
+               else
+               {
+                       size_t logLength = strlen(infoLog);
+                       char *newLog = new char[logLength + infoLength + 2];
+                       strcpy(newLog, infoLog);
+                       strcpy(newLog + logLength, info);
+                       strcpy(newLog + logLength + infoLength, "\n");
+
+                       delete[] infoLog;
+                       infoLog = newLog;
+               }
+       }
+
+       void Program::resetInfoLog()
+       {
+               if(infoLog)
+               {
+                       delete[] infoLog;
+                       infoLog = 0;
+               }
+       }
+
+       // Returns the program object to an unlinked state, before re-linking, or at destruction
+       void Program::unlink()
+       {
+               delete vertexBinary;
+               vertexBinary = 0;
+               delete pixelBinary;
+               pixelBinary = 0;
+
+               for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+               {
+                       linkedAttribute[index].name.clear();
+                       attributeStream[index] = -1;
+               }
+
+               for(int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
+               {
+                       samplersPS[index].active = false;
+               }
+
+               for(int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
+               {
+                       samplersVS[index].active = false;
+               }
+
+               while(!uniforms.empty())
+               {
+                       delete uniforms.back();
+                       uniforms.pop_back();
+               }
+
+               while(!uniformBlocks.empty())
+               {
+                       delete uniformBlocks.back();
+                       uniformBlocks.pop_back();
+               }
+
+               uniformIndex.clear();
+               transformFeedbackLinkedVaryings.clear();
+
+               delete[] infoLog;
+               infoLog = 0;
+
+               linked = false;
+       }
+
+       bool Program::isLinked() const
+       {
+               return linked;
+       }
+
+       bool Program::isValidated() const
+       {
+               return validated;
+       }
+
+       GLint Program::getBinaryLength() const
+       {
+               UNIMPLEMENTED();
+               return 0;
+       }
+
+       void Program::release()
+       {
+               referenceCount--;
+
+               if(referenceCount == 0 && orphaned)
+               {
+                       resourceManager->deleteProgram(handle);
+               }
+       }
+
+       void Program::addRef()
+       {
+               referenceCount++;
+       }
+
+       unsigned int Program::getRefCount() const
+       {
+               return referenceCount;
+       }
+
+       unsigned int Program::getSerial() const
+       {
+               return serial;
+       }
+
+       unsigned int Program::issueSerial()
+       {
+               return currentSerial++;
+       }
+
+       size_t Program::getInfoLogLength() const
+       {
+               if(!infoLog)
+               {
+                       return 0;
+               }
+               else
+               {
+                  return strlen(infoLog) + 1;
+               }
+       }
+
+       void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *buffer)
+       {
+               int index = 0;
+
+               if(bufSize > 0)
+               {
+                       if(infoLog)
+                       {
+                               index = std::min(bufSize - 1, (int)strlen(infoLog));
+                               memcpy(buffer, infoLog, index);
+                       }
+
+                       buffer[index] = '\0';
+               }
+
+               if(length)
+               {
+                       *length = index;
+               }
+       }
+
+       void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
+       {
+               int total = 0;
+
+               if(vertexShader && (total < maxCount))
+               {
+                       shaders[total++] = vertexShader->getName();
+               }
+
+               if(fragmentShader && (total < maxCount))
+               {
+                       shaders[total++] = fragmentShader->getName();
+               }
+
+               if(count)
+               {
+                       *count = total;
+               }
+       }
+
+       void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+       {
+               // Skip over inactive attributes
+               unsigned int activeAttribute = 0;
+               unsigned int attribute;
+               for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+               {
+                       if(linkedAttribute[attribute].name.empty())
+                       {
+                               continue;
+                       }
+
+                       if(activeAttribute == index)
+                       {
+                               break;
+                       }
+
+                       activeAttribute++;
+               }
+
+               if(bufsize > 0)
+               {
+                       const char *string = linkedAttribute[attribute].name.c_str();
+
+                       strncpy(name, string, bufsize);
+                       name[bufsize - 1] = '\0';
+
+                       if(length)
+                       {
+                               *length = static_cast<GLsizei>(strlen(name));
+                       }
+               }
+
+               *size = 1;   // Always a single 'type' instance
+
+               *type = linkedAttribute[attribute].type;
+       }
+
+       size_t Program::getActiveAttributeCount() const
+       {
+               int count = 0;
+
+               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+               {
+                       if(!linkedAttribute[attributeIndex].name.empty())
+                       {
+                               count++;
+                       }
+               }
+
+               return count;
+       }
+
+       GLint Program::getActiveAttributeMaxLength() const
+       {
+               int maxLength = 0;
+
+               for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+               {
+                       if(!linkedAttribute[attributeIndex].name.empty())
+                       {
+                               maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);
+                       }
+               }
+
+               return maxLength;
+       }
+
+       void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+       {
+               if(bufsize > 0)
+               {
+                       std::string string = uniforms[index]->name;
+
+                       if(uniforms[index]->isArray())
+                       {
+                               string += "[0]";
+                       }
+
+                       strncpy(name, string.c_str(), bufsize);
+                       name[bufsize - 1] = '\0';
+
+                       if(length)
+                       {
+                               *length = static_cast<GLsizei>(strlen(name));
+                       }
+               }
+
+               *size = uniforms[index]->size();
+
+               *type = uniforms[index]->type;
+       }
+
+       size_t Program::getActiveUniformCount() const
+       {
+               return uniforms.size();
+       }
+
+       GLint Program::getActiveUniformMaxLength() const
+       {
+               int maxLength = 0;
+
+               size_t numUniforms = uniforms.size();
+               for(size_t uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+               {
+                       if(!uniforms[uniformIndex]->name.empty())
+                       {
+                               int length = (int)(uniforms[uniformIndex]->name.length() + 1);
+                               if(uniforms[uniformIndex]->isArray())
+                               {
+                                       length += 3;  // Counting in "[0]".
+                               }
+                               maxLength = std::max(length, maxLength);
+                       }
+               }
+
+               return maxLength;
+       }
+
+       GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
+       {
+               const Uniform& uniform = *uniforms[index];
+               switch(pname)
+               {
+               case GL_UNIFORM_TYPE:         return static_cast<GLint>(uniform.type);
+               case GL_UNIFORM_SIZE:         return static_cast<GLint>(uniform.size());
+               case GL_UNIFORM_NAME_LENGTH:  return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
+               case GL_UNIFORM_BLOCK_INDEX:  return uniform.blockInfo.index;
+               case GL_UNIFORM_OFFSET:       return uniform.blockInfo.offset;
+               case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
+               case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
+               case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
+               default:
+                       UNREACHABLE(pname);
+                       break;
+               }
+               return 0;
+       }
+
+       void Program::getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const
+       {
+               ASSERT(index < getActiveUniformBlockCount());
+
+               const UniformBlock &uniformBlock = *uniformBlocks[index];
+
+               if(bufSize > 0)
+               {
+                       std::string string = uniformBlock.name;
+
+                       if(uniformBlock.isArrayElement())
+                       {
+                               std::ostringstream elementIndex;
+                               elementIndex << uniformBlock.elementIndex;
+                               string += "[" + elementIndex.str()  + "]";
+                       }
+
+                       strncpy(name, string.c_str(), bufSize);
+                       name[bufSize - 1] = '\0';
+
+                       if(length)
+                       {
+                               *length = static_cast<GLsizei>(strlen(name));
+                       }
+               }
+       }
+
+       size_t Program::getActiveUniformBlockCount() const
+       {
+               return uniformBlocks.size();
+       }
+
+       GLint Program::getActiveUniformBlockMaxLength() const
+       {
+               GLint maxLength = 0;
+
+               if(isLinked())
+               {
+                       size_t numUniformBlocks = getActiveUniformBlockCount();
+                       for(size_t uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
+                       {
+                               const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];
+                               if(!uniformBlock.name.empty())
+                               {
+                                       GLint length = static_cast<GLint>(uniformBlock.name.length() + 1);
+
+                                       // Counting in "[0]".
+                                       const GLint arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
+
+                                       maxLength = std::max(length + arrayLength, maxLength);
+                               }
+                       }
+               }
+
+               return maxLength;
+       }
+
+       void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
+       {
+               transformFeedbackVaryings.resize(count);
+               for(GLsizei i = 0; i < count; i++)
+               {
+                       transformFeedbackVaryings[i] = varyings[i];
+               }
+
+               transformFeedbackBufferMode = bufferMode;
+       }
+
+       void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
+       {
+               if(linked)
+               {
+                       ASSERT(index < transformFeedbackLinkedVaryings.size());
+                       const LinkedVarying &varying = transformFeedbackLinkedVaryings[index];
+                       GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
+                       if(length)
+                       {
+                               *length = lastNameIdx;
+                       }
+                       if(size)
+                       {
+                               *size = varying.size;
+                       }
+                       if(type)
+                       {
+                               *type = varying.type;
+                       }
+                       if(name)
+                       {
+                               memcpy(name, varying.name.c_str(), lastNameIdx);
+                               name[lastNameIdx] = '\0';
+                       }
+               }
+       }
+
+       GLsizei Program::getTransformFeedbackVaryingCount() const
+       {
+               if(linked)
+               {
+                       return static_cast<GLsizei>(transformFeedbackLinkedVaryings.size());
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+
+       GLsizei Program::getTransformFeedbackVaryingMaxLength() const
+       {
+               if(linked)
+               {
+                       GLsizei maxSize = 0;
+                       for(size_t i = 0; i < transformFeedbackLinkedVaryings.size(); i++)
+                       {
+                               const LinkedVarying &varying = transformFeedbackLinkedVaryings[i];
+                               maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
+                       }
+
+                       return maxSize;
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+
+       GLenum Program::getTransformFeedbackBufferMode() const
+       {
+               return transformFeedbackBufferMode;
+       }
+
+       void Program::flagForDeletion()
+       {
+               orphaned = true;
+       }
+
+       bool Program::isFlaggedForDeletion() const
+       {
+               return orphaned;
+       }
+
+       void Program::validate()
+       {
+               resetInfoLog();
+
+               if(!isLinked())
+               {
+                       appendToInfoLog("Program has not been successfully linked.");
+                       validated = false;
+               }
+               else
+               {
+                       applyUniforms();
+                       if(!validateSamplers(true))
+                       {
+                               validated = false;
+                       }
+                       else
+                       {
+                               validated = true;
+                       }
+               }
+       }
+
+       bool Program::validateSamplers(bool logErrors)
+       {
+               // if any two active samplers in a program are of different types, but refer to the same
+               // texture image unit, and this is the current program, then ValidateProgram will fail, and
+               // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+
+               TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+
+               for(unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; i++)
+               {
+                       textureUnitType[i] = TEXTURE_UNKNOWN;
+               }
+
+               for(unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+               {
+                       if(samplersPS[i].active)
+                       {
+                               unsigned int unit = samplersPS[i].logicalTextureUnit;
+
+                               if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+                               {
+                                       if(logErrors)
+                                       {
+                                               appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+                                       }
+
+                                       return false;
+                               }
+
+                               if(textureUnitType[unit] != TEXTURE_UNKNOWN)
+                               {
+                                       if(samplersPS[i].textureType != textureUnitType[unit])
+                                       {
+                                               if(logErrors)
+                                               {
+                                                       appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+                                               }
+
+                                               return false;
+                                       }
+                               }
+                               else
+                               {
+                                       textureUnitType[unit] = samplersPS[i].textureType;
+                               }
+                       }
+               }
+
+               for(unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
+               {
+                       if(samplersVS[i].active)
+                       {
+                               unsigned int unit = samplersVS[i].logicalTextureUnit;
+
+                               if(unit >= MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+                               {
+                                       if(logErrors)
+                                       {
+                                               appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+                                       }
+
+                                       return false;
+                               }
+
+                               if(textureUnitType[unit] != TEXTURE_UNKNOWN)
+                               {
+                                       if(samplersVS[i].textureType != textureUnitType[unit])
+                                       {
+                                               if(logErrors)
+                                               {
+                                                       appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+                                               }
+
+                                               return false;
+                                       }
+                               }
+                               else
+                               {
+                                       textureUnitType[unit] = samplersVS[i].textureType;
+                               }
+                       }
+               }
+
+               return true;
+       }
+}