-// 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 "Buffer.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::BlockInfo::BlockInfo(const glsl::Uniform& uniform, int blockIndex, bool rowMajorLayout)\r
- {\r
- static unsigned int registerSizeStd140 = 4; // std140 packing requires dword alignment\r
-\r
- if(blockIndex >= 0)\r
- {\r
- index = blockIndex;\r
- offset = uniform.offset * registerSizeStd140;\r
- isRowMajorMatrix = rowMajorLayout;\r
- int componentSize = UniformTypeSize(UniformComponentType(uniform.type));\r
- int rowCount = VariableRowCount(uniform.type);\r
- if(rowCount > 1)\r
- {\r
- int colCount = VariableColumnCount(uniform.type);\r
- int matrixComponentCount = (isRowMajorMatrix ? colCount : rowCount);\r
- matrixStride = (rowCount > 1) ? matrixComponentCount * componentSize : 0;\r
- arrayStride = (uniform.arraySize > 0) ? matrixStride * (isRowMajorMatrix ? rowCount : colCount) : 0;\r
- }\r
- else\r
- {\r
- matrixStride = 0;\r
- int componentCount = UniformComponentCount(uniform.type);\r
- arrayStride = (uniform.arraySize > 0) ? componentSize * componentCount : 0;\r
- }\r
- }\r
- else\r
- {\r
- index = -1;\r
- offset = -1;\r
- arrayStride = -1;\r
- matrixStride = -1;\r
- isRowMajorMatrix = false;\r
- }\r
- }\r
-\r
- Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,\r
- const BlockInfo &blockInfo)\r
- : type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo)\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() * VariableRegisterCount(type);\r
- }\r
-\r
- UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes) :\r
- name(name), elementIndex(elementIndex), dataSize(dataSize), memberUniformIndexes(memberUniformIndexes), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)\r
- {\r
- }\r
-\r
- void UniformBlock::setRegisterIndex(GLenum shader, unsigned int registerIndex)\r
- {\r
- switch(shader)\r
- {\r
- case GL_VERTEX_SHADER:\r
- vsRegisterIndex = registerIndex;\r
- break;\r
- case GL_FRAGMENT_SHADER:\r
- psRegisterIndex = registerIndex;\r
- break;\r
- default:\r
- UNREACHABLE(shader);\r
- }\r
- }\r
-\r
- bool UniformBlock::isArrayElement() const\r
- {\r
- return elementIndex != GL_INVALID_INDEX;\r
- }\r
-\r
- bool UniformBlock::isReferencedByVertexShader() const\r
- {\r
- return vsRegisterIndex != GL_INVALID_INDEX;\r
- }\r
-\r
- bool UniformBlock::isReferencedByFragmentShader() const\r
- {\r
- return psRegisterIndex != GL_INVALID_INDEX;\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
- LinkedVarying::LinkedVarying()\r
- {\r
- }\r
-\r
- LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei sizet)\r
- : name(name), type(type), size(size)\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
- transformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS;\r
-\r
- infoLog = 0;\r
- validated = false;\r
-\r
- resetUniformBlockBindings();\r
- unlink();\r
-\r
- orphaned = false;\r
- retrievableBinary = 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(shader->getType());\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(shader->getType());\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(type);\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(type);\r
- }\r
-\r
- return TEXTURE_2D;\r
- }\r
-\r
- GLint Program::getUniformLocation(const std::string &name) const\r
- {\r
- size_t subscript = GL_INVALID_INDEX;\r
- std::string baseName = es2::ParseUniformName(name, &subscript);\r
-\r
- unsigned int numUniforms = uniformIndex.size();\r
- for(unsigned int location = 0; location < numUniforms; location++)\r
- {\r
- const int index = uniformIndex[location].index;\r
- const bool isArray = uniforms[index]->isArray();\r
-\r
- if(uniformIndex[location].name == baseName &&\r
- ((isArray && uniformIndex[location].element == subscript) ||\r
- (subscript == GL_INVALID_INDEX)))\r
- {\r
- return location;\r
- }\r
- }\r
-\r
- return -1;\r
- }\r
-\r
- GLuint Program::getUniformIndex(const std::string &name) const\r
- {\r
- size_t subscript = GL_INVALID_INDEX;\r
- std::string baseName = es2::ParseUniformName(name, &subscript);\r
-\r
- // The app is not allowed to specify array indices other than 0 for arrays of basic types\r
- if(subscript != 0 && subscript != GL_INVALID_INDEX)\r
- {\r
- return GL_INVALID_INDEX;\r
- }\r
-\r
- unsigned int numUniforms = uniforms.size();\r
- for(unsigned int index = 0; index < numUniforms; index++)\r
- {\r
- if(uniforms[index]->name == baseName)\r
- {\r
- if(uniforms[index]->isArray() || subscript == GL_INVALID_INDEX)\r
- {\r
- return index;\r
- }\r
- }\r
- }\r
-\r
- return GL_INVALID_INDEX;\r
- }\r
-\r
- void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const\r
- {\r
- ASSERT(uniformBlockIndex < getActiveUniformBlockCount());\r
-\r
- const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];\r
-\r
- switch(pname)\r
- {\r
- case GL_UNIFORM_BLOCK_DATA_SIZE:\r
- *params = static_cast<GLint>(uniformBlock.dataSize);\r
- break;\r
- case GL_UNIFORM_BLOCK_NAME_LENGTH:\r
- *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));\r
- break;\r
- case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:\r
- *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());\r
- break;\r
- case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:\r
- {\r
- for(unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)\r
- {\r
- params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);\r
- }\r
- }\r
- break;\r
- case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:\r
- *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());\r
- break;\r
- case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:\r
- *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());\r
- break;\r
- default: UNREACHABLE(pname);\r
- }\r
- }\r
-\r
- GLuint Program::getUniformBlockIndex(const std::string &name) const\r
- {\r
- size_t subscript = GL_INVALID_INDEX;\r
- std::string baseName = es2::ParseUniformName(name, &subscript);\r
-\r
- unsigned int numUniformBlocks = getActiveUniformBlockCount();\r
- for(unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)\r
- {\r
- const UniformBlock &uniformBlock = *uniformBlocks[blockIndex];\r
- if(uniformBlock.name == baseName)\r
- {\r
- const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);\r
- if(subscript == uniformBlock.elementIndex || arrayElementZero)\r
- {\r
- return blockIndex;\r
- }\r
- }\r
- }\r
-\r
- return GL_INVALID_INDEX;\r
- }\r
-\r
- void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)\r
- {\r
- uniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;\r
- }\r
-\r
- GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const\r
- {\r
- return uniformBlockBindings[uniformBlockIndex];\r
- }\r
-\r
- void Program::resetUniformBlockBindings()\r
- {\r
- for(unsigned int blockId = 0; blockId < MAX_UNIFORM_BUFFER_BINDINGS; blockId++)\r
- {\r
- uniformBlockBindings[blockId] = 0;\r
- }\r
- }\r
-\r
- bool Program::setUniformfv(GLint location, GLsizei count, const GLfloat *v, int numElements)\r
- {\r
- ASSERT(numElements >= 1 && numElements <= 4);\r
-\r
- static GLenum floatType[] = { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 };\r
- static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };\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
- int index = numElements - 1;\r
- if(targetUniform->type == floatType[index])\r
- {\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat)* numElements,\r
- v, numElements * sizeof(GLfloat)* count);\r
- }\r
- else if(targetUniform->type == boolType[index])\r
- {\r
- GLboolean *boolParams = (GLboolean*)targetUniform->data + uniformIndex[location].element * numElements;\r
-\r
- for(int i = 0; i < count * numElements; i++)\r
- {\r
- boolParams[i] = (v[i] == 0.0f) ? GL_FALSE : GL_TRUE;\r
- }\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)\r
- {\r
- return setUniformfv(location, count, v, 1);\r
- }\r
-\r
- bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)\r
- {\r
- return setUniformfv(location, count, v, 2);\r
- }\r
-\r
- bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)\r
- {\r
- return setUniformfv(location, count, v, 3);\r
- }\r
-\r
- bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)\r
- {\r
- return setUniformfv(location, count, v, 4);\r
- }\r
-\r
- bool Program::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum type)\r
- {\r
- int numElements;\r
- switch(type)\r
- {\r
- case GL_FLOAT_MAT2:\r
- numElements = 4;\r
- break;\r
- case GL_FLOAT_MAT2x3:\r
- case GL_FLOAT_MAT3x2:\r
- numElements = 6;\r
- break;\r
- case GL_FLOAT_MAT2x4:\r
- case GL_FLOAT_MAT4x2:\r
- numElements = 8;\r
- break;\r
- case GL_FLOAT_MAT3:\r
- numElements = 9;\r
- break;\r
- case GL_FLOAT_MAT3x4:\r
- case GL_FLOAT_MAT4x3:\r
- numElements = 12;\r
- break;\r
- case GL_FLOAT_MAT4:\r
- numElements = 16;\r
- break;\r
- default:\r
- return false;\r
- }\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 != type)\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
- GLfloat* dst = reinterpret_cast<GLfloat*>(targetUniform->data + uniformIndex[location].element * sizeof(GLfloat) * numElements);\r
-\r
- if(transpose == GL_FALSE)\r
- {\r
- memcpy(dst, value, numElements * sizeof(GLfloat) * count);\r
- }\r
- else\r
- {\r
- const int rowSize = VariableRowCount(type);\r
- const int colSize = VariableColumnCount(type);\r
- for(int n = 0; n < count; ++n)\r
- {\r
- for(int i = 0; i < colSize; ++i)\r
- {\r
- for(int j = 0; j < rowSize; ++j)\r
- {\r
- dst[i * rowSize + j] = value[j * colSize + i];\r
- }\r
- }\r
- dst += numElements;\r
- value += numElements;\r
- }\r
- }\r
-\r
-\r
- return true;\r
- }\r
-\r
- bool Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2);\r
- }\r
-\r
- bool Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x3);\r
- }\r
-\r
- bool Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT2x4);\r
- }\r
-\r
- bool Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3);\r
- }\r
-\r
- bool Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x2);\r
- }\r
-\r
- bool Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT3x4);\r
- }\r
-\r
- bool Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4);\r
- }\r
-\r
- bool Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x2);\r
- }\r
-\r
- bool Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)\r
- {\r
- return setUniformMatrixfv(location, count, transpose, value, GL_FLOAT_MAT4x3);\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 || IsSamplerUniform(targetUniform->type))\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::setUniformiv(GLint location, GLsizei count, const GLint *v, int numElements)\r
- {\r
- static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };\r
- static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };\r
- static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };\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
- int index = numElements - 1;\r
- if(targetUniform->type == intType[index] || targetUniform->type == uintType[index])\r
- {\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint)* numElements,\r
- v, numElements * sizeof(GLint)* count);\r
- }\r
- else if(targetUniform->type == boolType[index])\r
- {\r
- GLboolean *boolParams = new GLboolean[count * numElements];\r
-\r
- for(int i = 0; i < count * numElements; i++)\r
- {\r
- boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;\r
- }\r
-\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,\r
- boolParams, numElements * 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
- return setUniformiv(location, count, v, 2);\r
- }\r
-\r
- bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)\r
- {\r
- return setUniformiv(location, count, v, 3);\r
- }\r
-\r
- bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)\r
- {\r
- return setUniformiv(location, count, v, 4);\r
- }\r
-\r
- bool Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *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 || IsSamplerUniform(targetUniform->type))\r
- {\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint),\r
- v, sizeof(GLuint)* 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::setUniformuiv(GLint location, GLsizei count, const GLuint *v, int numElements)\r
- {\r
- static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };\r
- static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };\r
- static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };\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
- int index = numElements - 1;\r
- if(targetUniform->type == uintType[index] || targetUniform->type == intType[index])\r
- {\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint)* numElements,\r
- v, numElements * sizeof(GLuint)* count);\r
- }\r
- else if(targetUniform->type == boolType[index])\r
- {\r
- GLboolean *boolParams = new GLboolean[count * numElements];\r
-\r
- for(int i = 0; i < count * numElements; i++)\r
- {\r
- boolParams[i] = (v[i] == 0) ? GL_FALSE : GL_TRUE;\r
- }\r
-\r
- memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLboolean)* numElements,\r
- boolParams, numElements * sizeof(GLboolean)* count);\r
-\r
- delete[] boolParams;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- bool Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)\r
- {\r
- return setUniformuiv(location, count, v, 2);\r
- }\r
-\r
- bool Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)\r
- {\r
- return setUniformuiv(location, count, v, 3);\r
- }\r
-\r
- bool Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)\r
- {\r
- return setUniformuiv(location, count, v, 4);\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 && static_cast<unsigned int>(*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
- case GL_UNSIGNED_INT:\r
- {\r
- GLuint *uintParams = (GLuint*)targetUniform->data + uniformIndex[location].element * count;\r
-\r
- for(unsigned int i = 0; i < count; i++)\r
- {\r
- params[i] = (float)uintParams[i];\r
- }\r
- }\r
- break;\r
- default: UNREACHABLE(targetUniform->type);\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 && static_cast<unsigned int>(*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
- case GL_UNSIGNED_INT:\r
- memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLint),\r
- count * sizeof(GLint));\r
- break;\r
- default: UNREACHABLE(targetUniform->type);\r
- }\r
-\r
- return true;\r
- }\r
-\r
- bool Program::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *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 && static_cast<unsigned int>(*bufSize) < count * sizeof(GLuint))\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] = (GLuint)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] = (GLuint)floatParams[i];\r
- }\r
- }\r
- break;\r
- case GL_INT:\r
- case GL_UNSIGNED_INT:\r
- memcpy(params, targetUniform->data + uniformIndex[location].element * count * sizeof(GLuint),\r
- count * sizeof(GLuint));\r
- break;\r
- default: UNREACHABLE(targetUniform->type);\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
- GLuint *ui = (GLuint*)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_MAT2x3: applyUniformMatrix2x3fv(location, size, f); break;\r
- case GL_FLOAT_MAT2x4: applyUniformMatrix2x4fv(location, size, f); break;\r
- case GL_FLOAT_MAT3x2: applyUniformMatrix3x2fv(location, size, f); break;\r
- case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, size, f); break;\r
- case GL_FLOAT_MAT3x4: applyUniformMatrix3x4fv(location, size, f); break;\r
- case GL_FLOAT_MAT4x2: applyUniformMatrix4x2fv(location, size, f); break;\r
- case GL_FLOAT_MAT4x3: applyUniformMatrix4x3fv(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_SAMPLER_2D_ARRAY:\r
- case GL_SAMPLER_2D_SHADOW:\r
- case GL_SAMPLER_CUBE_SHADOW:\r
- case GL_SAMPLER_2D_ARRAY_SHADOW:\r
- case GL_INT_SAMPLER_2D:\r
- case GL_UNSIGNED_INT_SAMPLER_2D:\r
- case GL_INT_SAMPLER_CUBE:\r
- case GL_UNSIGNED_INT_SAMPLER_CUBE:\r
- case GL_INT_SAMPLER_3D:\r
- case GL_UNSIGNED_INT_SAMPLER_3D:\r
- case GL_INT_SAMPLER_2D_ARRAY:\r
- case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:\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
- case GL_UNSIGNED_INT: applyUniform1uiv(location, size, ui); break;\r
- case GL_UNSIGNED_INT_VEC2: applyUniform2uiv(location, size, ui); break;\r
- case GL_UNSIGNED_INT_VEC3: applyUniform3uiv(location, size, ui); break;\r
- case GL_UNSIGNED_INT_VEC4: applyUniform4uiv(location, size, ui); break;\r
- default:\r
- UNREACHABLE(targetUniform->type);\r
- }\r
-\r
- targetUniform->dirty = false;\r
- }\r
- }\r
- }\r
-\r
- void Program::applyUniformBuffers()\r
- {\r
- GLint vertexUniformBuffers[IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS];\r
- GLint fragmentUniformBuffers[IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS];\r
-\r
- for(unsigned int registerIndex = 0; registerIndex < IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS; ++registerIndex)\r
- {\r
- vertexUniformBuffers[registerIndex] = -1;\r
- }\r
-\r
- for(unsigned int registerIndex = 0; registerIndex < IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS; ++registerIndex)\r
- {\r
- fragmentUniformBuffers[registerIndex] = -1;\r
- }\r
-\r
- for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)\r
- {\r
- UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];\r
- GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];\r
-\r
- // Unnecessary to apply an unreferenced standard or shared UBO\r
- if(!uniformBlock.isReferencedByVertexShader() && !uniformBlock.isReferencedByFragmentShader())\r
- {\r
- continue;\r
- }\r
-\r
- if(uniformBlock.isReferencedByVertexShader())\r
- {\r
- unsigned int registerIndex = uniformBlock.vsRegisterIndex;\r
- ASSERT(vertexUniformBuffers[registerIndex] == -1);\r
- vertexUniformBuffers[registerIndex] = blockBinding;\r
- }\r
-\r
- if(uniformBlock.isReferencedByFragmentShader())\r
- {\r
- unsigned int registerIndex = uniformBlock.psRegisterIndex;\r
- ASSERT(fragmentUniformBuffers[registerIndex] == -1);\r
- fragmentUniformBuffers[registerIndex] = blockBinding;\r
- }\r
- }\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 = VariableRegisterSize(output->type);\r
- int registers = VariableRegisterCount(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
- bool Program::gatherTransformFeedbackLinkedVaryings()\r
- {\r
- // Varyings have already been validated in linkVaryings()\r
- glsl::VaryingList &vsVaryings = vertexShader->varyings;\r
-\r
- for(std::vector<std::string>::iterator trVar = transformFeedbackVaryings.begin(); trVar != transformFeedbackVaryings.end(); ++trVar)\r
- {\r
- bool found = false;\r
- for(glsl::VaryingList::iterator var = vsVaryings.begin(); var != vsVaryings.end(); ++var)\r
- {\r
- if(var->name == (*trVar))\r
- {\r
- transformFeedbackLinkedVaryings.push_back(LinkedVarying(var->name, var->type, var->size()));\r
- found = true;\r
- break;\r
- }\r
- }\r
-\r
- if(!found)\r
- {\r
- return false;\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
- resetUniformBlockBindings();\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
- // Link uniform blocks before uniforms to make it easy to assign block indices to fields\r
- if(!linkUniformBlocks(vertexShader, fragmentShader))\r
- {\r
- return;\r
- }\r
-\r
- if(!linkUniforms(fragmentShader))\r
- {\r
- return;\r
- }\r
-\r
- if(!linkUniforms(vertexShader))\r
- {\r
- return;\r
- }\r
-\r
- if(!gatherTransformFeedbackLinkedVaryings())\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);\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 = VariableRegisterCount(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);\r
-\r
- if(location == -1) // Not set by glBindAttribLocation\r
- {\r
- int rows = VariableRegisterCount(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(VariableRegisterCount(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 glsl::Attribute &attribute)\r
- {\r
- if(attribute.location != -1)\r
- {\r
- return attribute.location;\r
- }\r
-\r
- for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)\r
- {\r
- if(attributeBinding[location].find(attribute.name.c_str()) != attributeBinding[location].end())\r
- {\r
- return location;\r
- }\r
- }\r
-\r
- return -1;\r
- }\r
-\r
- bool Program::linkUniforms(const 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
- int blockIndex = -1;\r
- bool isRowMajorMatrix = false;\r
- if(uniform.blockId >= 0)\r
- {\r
- const glsl::ActiveUniformBlocks &activeUniformBlocks = shader->activeUniformBlocks;\r
- ASSERT(static_cast<size_t>(uniform.blockId) < activeUniformBlocks.size());\r
- blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].getName());\r
- ASSERT(blockIndex != GL_INVALID_INDEX);\r
- isRowMajorMatrix = activeUniformBlocks[uniform.blockId].isRowMajorLayout;\r
- }\r
- if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex, isRowMajorMatrix)))\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, const Uniform::BlockInfo& blockInfo)\r
- {\r
- if(IsSamplerUniform(type))\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
-\r
- switch(type)\r
- {\r
- default: UNREACHABLE(type);\r
- case GL_INT_SAMPLER_2D:\r
- case GL_UNSIGNED_INT_SAMPLER_2D:\r
- case GL_SAMPLER_2D_SHADOW:\r
- case GL_SAMPLER_2D: samplersVS[index].textureType = TEXTURE_2D; break;\r
- case GL_INT_SAMPLER_CUBE:\r
- case GL_UNSIGNED_INT_SAMPLER_CUBE:\r
- case GL_SAMPLER_CUBE_SHADOW:\r
- case GL_SAMPLER_CUBE: samplersVS[index].textureType = TEXTURE_CUBE; break;\r
- case GL_INT_SAMPLER_3D:\r
- case GL_UNSIGNED_INT_SAMPLER_3D:\r
- case GL_SAMPLER_3D_OES: samplersVS[index].textureType = TEXTURE_3D; break;\r
- case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;\r
- case GL_INT_SAMPLER_2D_ARRAY:\r
- case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:\r
- case GL_SAMPLER_2D_ARRAY_SHADOW:\r
- case GL_SAMPLER_2D_ARRAY: samplersVS[index].textureType = TEXTURE_2D_ARRAY; break;\r
- }\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
- \r
- switch(type)\r
- {\r
- default: UNREACHABLE(type);\r
- case GL_INT_SAMPLER_2D:\r
- case GL_UNSIGNED_INT_SAMPLER_2D:\r
- case GL_SAMPLER_2D_SHADOW:\r
- case GL_SAMPLER_2D: samplersPS[index].textureType = TEXTURE_2D; break;\r
- case GL_INT_SAMPLER_CUBE:\r
- case GL_UNSIGNED_INT_SAMPLER_CUBE:\r
- case GL_SAMPLER_CUBE_SHADOW:\r
- case GL_SAMPLER_CUBE: samplersPS[index].textureType = TEXTURE_CUBE; break;\r
- case GL_INT_SAMPLER_3D:\r
- case GL_UNSIGNED_INT_SAMPLER_3D:\r
- case GL_SAMPLER_3D_OES: samplersPS[index].textureType = TEXTURE_3D; break;\r
- case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;\r
- case GL_INT_SAMPLER_2D_ARRAY:\r
- case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:\r
- case GL_SAMPLER_2D_ARRAY_SHADOW:\r
- case GL_SAMPLER_2D_ARRAY: samplersPS[index].textureType = TEXTURE_2D_ARRAY; break;\r
- }\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(shader);\r
-\r
- index++;\r
- }\r
- while(index < registerIndex + static_cast<int>(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, blockInfo);\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(shader);\r
-\r
- if(location == -1) // Not previously defined\r
- {\r
- uniforms.push_back(uniform);\r
- unsigned int index = uniforms.size() - 1;\r
-\r
- for(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(shader);\r
-\r
- return true;\r
- }\r
-\r
- bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)\r
- {\r
- // validate blocks for the same member types\r
- if(block1.fields.size() != block2.fields.size())\r
- {\r
- return false;\r
- }\r
- if(block1.arraySize != block2.arraySize)\r
- {\r
- return false;\r
- }\r
- if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)\r
- {\r
- return false;\r
- }\r
- const unsigned int numBlockMembers = block1.fields.size();\r
- for(unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)\r
- {\r
- const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];\r
- const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];\r
- if(member1.name != member2.name ||\r
- member1.arraySize != member2.arraySize ||\r
- member1.precision != member2.precision ||\r
- member1.type != member2.type)\r
- {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)\r
- {\r
- const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;\r
- const glsl::ActiveUniformBlocks &fragmentUniformBlocks = fragmentShader->activeUniformBlocks;\r
- // Check that interface blocks defined in the vertex and fragment shaders are identical\r
- typedef std::map<std::string, const glsl::UniformBlock*> UniformBlockMap;\r
- UniformBlockMap linkedUniformBlocks;\r
- for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)\r
- {\r
- const glsl::UniformBlock &vertexUniformBlock = vertexUniformBlocks[blockIndex];\r
- linkedUniformBlocks[vertexUniformBlock.name] = &vertexUniformBlock;\r
- }\r
- for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)\r
- {\r
- const glsl::UniformBlock &fragmentUniformBlock = fragmentUniformBlocks[blockIndex];\r
- UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentUniformBlock.name);\r
- if(entry != linkedUniformBlocks.end())\r
- {\r
- const glsl::UniformBlock &vertexUniformBlock = *entry->second;\r
- if(!areMatchingUniformBlocks(vertexUniformBlock, fragmentUniformBlock, vertexShader, fragmentShader))\r
- {\r
- return false;\r
- }\r
- }\r
- }\r
- for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)\r
- {\r
- const glsl::UniformBlock &uniformBlock = vertexUniformBlocks[blockIndex];\r
- if(!defineUniformBlock(vertexShader, uniformBlock))\r
- {\r
- return false;\r
- }\r
- }\r
- for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)\r
- {\r
- const glsl::UniformBlock &uniformBlock = fragmentUniformBlocks[blockIndex];\r
- if(!defineUniformBlock(fragmentShader, uniformBlock))\r
- {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- bool Program::defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block)\r
- {\r
- GLuint blockIndex = getUniformBlockIndex(block.getName());\r
-\r
- if(blockIndex == GL_INVALID_INDEX)\r
- {\r
- const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;\r
- const std::vector<int>& fields = block.fields;\r
- std::vector<unsigned int> memberUniformIndexes;\r
- for(size_t i = 0; i < fields.size(); ++i)\r
- {\r
- memberUniformIndexes.push_back(fields[i]);\r
- }\r
-\r
- if(block.arraySize > 0)\r
- {\r
- for(unsigned int i = 0; i < block.arraySize; ++i)\r
- {\r
- uniformBlocks.push_back(new UniformBlock(block.getName(), i, block.dataSize, memberUniformIndexes));\r
- uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), block.registerIndex);\r
- }\r
- }\r
- else\r
- {\r
- uniformBlocks.push_back(new UniformBlock(block.getName(), GL_INVALID_INDEX, block.dataSize, memberUniformIndexes));\r
- uniformBlocks[uniformBlocks.size() - 1]->setRegisterIndex(shader->getType(), block.registerIndex);\r
- }\r
- }\r
- else\r
- {\r
- uniformBlocks[blockIndex]->setRegisterIndex(shader->getType(), block.registerIndex);\r
- }\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::applyUniformMatrix2x3fv(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] = 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
-\r
- value += 6;\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::applyUniformMatrix2x4fv(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] = value[2]; matrix[i][0][3] = value[3];\r
- matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];\r
-\r
- value += 8;\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::applyUniformMatrix3x2fv(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] = 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
- matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;\r
-\r
- value += 6;\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::applyUniformMatrix3x4fv(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] = value[3];\r
- matrix[i][1][0] = value[4]; matrix[i][1][1] = value[5]; matrix[i][1][2] = value[6]; matrix[i][1][3] = value[7];\r
- matrix[i][2][0] = value[8]; matrix[i][2][1] = value[9]; matrix[i][2][2] = value[10]; matrix[i][2][3] = value[11];\r
-\r
- value += 12;\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::applyUniformMatrix4x2fv(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] = 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
- matrix[i][2][0] = value[4]; matrix[i][2][1] = value[5]; matrix[i][2][2] = 0; matrix[i][2][3] = 0;\r
- matrix[i][3][0] = value[6]; matrix[i][3][1] = value[7]; matrix[i][3][2] = 0; matrix[i][3][3] = 0;\r
-\r
- value += 8;\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::applyUniformMatrix4x3fv(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
- matrix[i][3][0] = value[9]; matrix[i][3][1] = value[10]; matrix[i][3][2] = value[11]; matrix[i][3][3] = 0;\r
-\r
- value += 12;\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::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(IsSamplerUniform(targetUniform->type))\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(IsSamplerUniform(targetUniform->type))\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
- bool Program::applyUniform1uiv(GLint location, GLsizei count, const GLuint *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(IsSamplerUniform(targetUniform->type))\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(IsSamplerUniform(targetUniform->type))\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::applyUniform2uiv(GLint location, GLsizei count, const GLuint *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::applyUniform3uiv(GLint location, GLsizei count, const GLuint *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::applyUniform4uiv(GLint location, GLsizei count, const GLuint *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
- while(!uniformBlocks.empty())\r
- {\r
- delete uniformBlocks.back();\r
- uniformBlocks.pop_back();\r
- }\r
-\r
- uniformIndex.clear();\r
- transformFeedbackLinkedVaryings.clear();\r
-\r
- delete[] infoLog;\r
- infoLog = 0;\r
-\r
- linked = false;\r
- }\r
-\r
- bool Program::isLinked() const\r
- {\r
- return linked;\r
- }\r
-\r
- bool Program::isValidated() const \r
- {\r
- return validated;\r
- }\r
-\r
- GLint Program::getBinaryLength() const\r
- {\r
- UNIMPLEMENTED();\r
- return 0;\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 && (total < maxCount))\r
- {\r
- shaders[total++] = vertexShader->getName();\r
- }\r
-\r
- if(fragmentShader && (total < maxCount))\r
- {\r
- shaders[total++] = fragmentShader->getName();\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
- size_t 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
- size_t 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
- GLint Program::getActiveUniformi(GLuint index, GLenum pname) const\r
- {\r
- const Uniform& uniform = *uniforms[index];\r
- switch(pname)\r
- {\r
- case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);\r
- case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.size());\r
- case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));\r
- case GL_UNIFORM_BLOCK_INDEX: return uniform.blockInfo.index;\r
- case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;\r
- case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;\r
- case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;\r
- case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);\r
- default:\r
- UNREACHABLE(pname);\r
- break;\r
- }\r
- return 0;\r
- }\r
-\r
- void Program::getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const\r
- {\r
- ASSERT(index < getActiveUniformBlockCount());\r
-\r
- const UniformBlock &uniformBlock = *uniformBlocks[index];\r
-\r
- if(bufSize > 0)\r
- {\r
- std::string string = uniformBlock.name;\r
-\r
- if(uniformBlock.isArrayElement())\r
- {\r
- std::ostringstream elementIndex;\r
- elementIndex << uniformBlock.elementIndex;\r
- string += "[" + elementIndex.str() + "]";\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
-\r
- size_t Program::getActiveUniformBlockCount() const\r
- {\r
- return uniformBlocks.size();\r
- }\r
-\r
- GLint Program::getActiveUniformBlockMaxLength() const\r
- {\r
- int maxLength = 0;\r
-\r
- if(isLinked())\r
- {\r
- unsigned int numUniformBlocks = getActiveUniformBlockCount();\r
- for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)\r
- {\r
- const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];\r
- if(!uniformBlock.name.empty())\r
- {\r
- const int length = uniformBlock.name.length() + 1;\r
-\r
- // Counting in "[0]".\r
- const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);\r
-\r
- maxLength = std::max(length + arrayLength, maxLength);\r
- }\r
- }\r
- }\r
-\r
- return maxLength;\r
- }\r
-\r
- void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)\r
- {\r
- transformFeedbackVaryings.resize(count);\r
- for(GLsizei i = 0; i < count; i++)\r
- {\r
- transformFeedbackVaryings[i] = varyings[i];\r
- }\r
-\r
- transformFeedbackBufferMode = bufferMode;\r
- }\r
-\r
- void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const\r
- {\r
- if(linked)\r
- {\r
- ASSERT(index < transformFeedbackLinkedVaryings.size());\r
- const LinkedVarying &varying = transformFeedbackLinkedVaryings[index];\r
- GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));\r
- if(length)\r
- {\r
- *length = lastNameIdx;\r
- }\r
- if(size)\r
- {\r
- *size = varying.size;\r
- }\r
- if(type)\r
- {\r
- *type = varying.type;\r
- }\r
- if(name)\r
- {\r
- memcpy(name, varying.name.c_str(), lastNameIdx);\r
- name[lastNameIdx] = '\0';\r
- }\r
- }\r
- }\r
-\r
- GLsizei Program::getTransformFeedbackVaryingCount() const\r
- {\r
- if(linked)\r
- {\r
- return static_cast<GLsizei>(transformFeedbackLinkedVaryings.size());\r
- }\r
- else\r
- {\r
- return 0;\r
- }\r
- }\r
-\r
- GLsizei Program::getTransformFeedbackVaryingMaxLength() const\r
- {\r
- if(linked)\r
- {\r
- GLsizei maxSize = 0;\r
- for(size_t i = 0; i < transformFeedbackLinkedVaryings.size(); i++)\r
- {\r
- const LinkedVarying &varying = transformFeedbackLinkedVaryings[i];\r
- maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));\r
- }\r
-\r
- return maxSize;\r
- }\r
- else\r
- {\r
- return 0;\r
- }\r
- }\r
-\r
- GLenum Program::getTransformFeedbackBufferMode() const\r
- {\r
- return transformFeedbackBufferMode;\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;
+ }
+}