MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = MAX_UNIFORM_BLOCKS_COMPONENTS + 4 * FRAGMENT_UNIFORM_VECTORS,\r
MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = MAX_UNIFORM_BLOCKS_COMPONENTS + 4 * VERTEX_UNIFORM_VECTORS,\r
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 4,\r
+ MAX_UNIFORM_BUFFER_BINDINGS = 36,\r
};\r
\r
#endif // sw_Config_hpp\r
return size() * VariableRowCount(type);\r
}\r
\r
+ UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) :\r
+ name(name), elementIndex(elementIndex), dataSize(dataSize), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)\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
infoLog = 0;\r
validated = false;\r
\r
+ resetUniformBlockBindings();\r
unlink();\r
\r
orphaned = false;\r
return TEXTURE_2D;\r
}\r
\r
- GLint Program::getUniformLocation(std::string name)\r
+ GLint Program::getUniformLocation(const std::string &name) const\r
{\r
- int subscript = 0;\r
-\r
- // Strip any trailing array operator and retrieve the subscript\r
- size_t open = name.find_last_of('[');\r
- size_t close = name.find_last_of(']');\r
- if(open != std::string::npos && close == name.length() - 1)\r
- {\r
- subscript = atoi(name.substr(open + 1).c_str());\r
- name.erase(open);\r
- }\r
+ 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
- if(uniformIndex[location].name == name &&\r
- uniformIndex[location].element == subscript)\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
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();\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
unlink();\r
\r
+ resetUniformBlockBindings();\r
+\r
if(!fragmentShader || !fragmentShader->isCompiled())\r
{\r
return;\r
return -1;\r
}\r
\r
- bool Program::linkUniforms(Shader *shader)\r
+ bool Program::linkUniforms(const Shader *shader)\r
{\r
const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;\r
\r
linked = false;\r
}\r
\r
- bool Program::isLinked()\r
+ bool Program::isLinked() const\r
{\r
return linked;\r
}\r
return maxLength;\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
+ string += "[";\r
+ string += std::to_string(uniformBlock.elementIndex);\r
+ string += "]";\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
+ GLint 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::flagForDeletion()\r
{\r
orphaned = true;\r
short vsRegisterIndex;\r
};\r
\r
+ // Helper struct representing a single shader uniform block\r
+ struct UniformBlock\r
+ {\r
+ // use GL_INVALID_INDEX for non-array elements\r
+ UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize);\r
+\r
+ bool isArrayElement() const;\r
+ bool isReferencedByVertexShader() const;\r
+ bool isReferencedByFragmentShader() const;\r
+\r
+ const std::string name;\r
+ const unsigned int elementIndex;\r
+ const unsigned int dataSize;\r
+\r
+ std::vector<unsigned int> memberUniformIndexes;\r
+\r
+ unsigned int psRegisterIndex;\r
+ unsigned int vsRegisterIndex;\r
+ };\r
+\r
// Struct used for correlating uniforms/elements of uniform arrays to handles\r
struct UniformLocation\r
{\r
GLint getSamplerMapping(sw::SamplerType type, unsigned int samplerIndex);\r
TextureType getSamplerTextureType(sw::SamplerType type, unsigned int samplerIndex);\r
\r
- GLint getUniformLocation(std::string name);\r
+ GLuint getUniformIndex(const std::string &name) const;\r
+ GLuint getUniformBlockIndex(const std::string &name) const;\r
+ void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);\r
+ GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;\r
+ void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;\r
+\r
+ GLint getUniformLocation(const std::string &name) const;\r
bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v);\r
bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v);\r
bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v);\r
void applyUniforms();\r
\r
void link();\r
- bool isLinked();\r
+ bool isLinked() const;\r
int getInfoLogLength() const;\r
void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);\r
void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);\r
GLint getActiveUniformCount() const;\r
GLint getActiveUniformMaxLength() const;\r
\r
+ void getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const;\r
+ GLint getActiveUniformBlockCount() const;\r
+ GLint getActiveUniformBlockMaxLength() const;\r
+\r
void addRef();\r
void release();\r
unsigned int getRefCount() const;\r
\r
private:\r
void unlink();\r
+ void resetUniformBlockBindings();\r
\r
bool linkVaryings();\r
\r
bool linkAttributes();\r
int getAttributeBinding(const std::string &name);\r
\r
- bool linkUniforms(Shader *shader);\r
+ bool linkUniforms(const Shader *shader);\r
bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex);\r
bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v);\r
bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v);\r
glsl::Attribute linkedAttribute[MAX_VERTEX_ATTRIBS];\r
int attributeStream[MAX_VERTEX_ATTRIBS];\r
\r
+ GLuint uniformBlockBindings[MAX_UNIFORM_BUFFER_BINDINGS];\r
+\r
struct Sampler\r
{\r
bool active;\r
UniformArray uniforms;\r
typedef std::vector<UniformLocation> UniformIndex;\r
UniformIndex uniformIndex;\r
+ typedef std::vector<UniformBlock*> UniformBlockArray;\r
+ UniformBlockArray uniformBlocks;\r
\r
bool linked;\r
bool orphaned; // Flag to indicate that the program can be deleted when no longer in use\r
delete vertexShader;
}
-GLenum VertexShader::getType()
+GLenum VertexShader::getType() const
{
return GL_VERTEX_SHADER;
}
delete pixelShader;
}
-GLenum FragmentShader::getType()
+GLenum FragmentShader::getType() const
{
return GL_FRAGMENT_SHADER;
}
\r
virtual ~Shader();\r
\r
- virtual GLenum getType() = 0;\r
+ virtual GLenum getType() const = 0;\r
GLuint getName() const;\r
\r
void deleteSource();\r
\r
~VertexShader();\r
\r
- virtual GLenum getType();\r
+ virtual GLenum getType() const;\r
int getSemanticIndex(const std::string &attributeName);\r
\r
virtual sw::Shader *getShader() const;\r
\r
~FragmentShader();\r
\r
- virtual GLenum getType();\r
+ virtual GLenum getType() const;\r
\r
virtual sw::Shader *getShader() const;\r
virtual sw::PixelShader *getPixelShader() const;\r
IMPLEMENTATION_MAX_COLOR_ATTACHMENTS = MAX_COLOR_ATTACHMENTS,\r
IMPLEMENTATION_MAX_DRAW_BUFFERS = 8,\r
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,\r
- IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS = 36,\r
+ IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS = MAX_UNIFORM_BUFFER_BINDINGS,\r
IMPLEMENTATION_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 1,\r
};\r
\r
return error(GL_INVALID_VALUE);\r
}\r
\r
+ egl::GLint clientVersion = egl::getClientVersion();\r
+\r
switch(pname)\r
{\r
case GL_DELETE_STATUS:\r
case GL_ACTIVE_UNIFORM_MAX_LENGTH:\r
*params = programObject->getActiveUniformMaxLength();\r
return;\r
+ case GL_ACTIVE_UNIFORM_BLOCKS:\r
+ if(clientVersion >= 3)\r
+ {\r
+ *params = programObject->getActiveUniformBlockCount();\r
+ return;\r
+ }\r
+ else return error(GL_INVALID_ENUM);\r
+ case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:\r
+ if(clientVersion >= 3)\r
+ {\r
+ *params = programObject->getActiveUniformBlockMaxLength();\r
+ return;\r
+ }\r
+ else return error(GL_INVALID_ENUM);\r
default:\r
return error(GL_INVALID_ENUM);\r
}\r
TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",\r
program, uniformCount, uniformNames, uniformIndices);\r
\r
+ if (uniformCount < 0)\r
+ {\r
+ return error(GL_INVALID_VALUE);\r
+ }\r
+\r
es2::Context *context = es2::getContext();\r
\r
if(context)\r
{\r
return error(GL_INVALID_OPERATION);\r
}\r
- }\r
\r
- UNIMPLEMENTED();\r
+ if(!programObject->isLinked())\r
+ {\r
+ for(int uniformId = 0; uniformId < uniformCount; uniformId++)\r
+ {\r
+ uniformIndices[uniformId] = GL_INVALID_INDEX;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for(int uniformId = 0; uniformId < uniformCount; uniformId++)\r
+ {\r
+ uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);\r
+ }\r
+ }\r
+ }\r
}\r
\r
GL_APICALL void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)\r
{\r
return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);\r
}\r
- }\r
\r
- UNIMPLEMENTED();\r
- return GL_INVALID_INDEX;\r
+ return programObject->getUniformBlockIndex(uniformBlockName);\r
+ }\r
}\r
\r
GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)\r
TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",\r
program, uniformBlockIndex, pname, params);\r
\r
- switch(pname)\r
- {\r
- case GL_UNIFORM_BLOCK_BINDING:\r
- case GL_UNIFORM_BLOCK_DATA_SIZE:\r
- case GL_UNIFORM_BLOCK_NAME_LENGTH:\r
- case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:\r
- case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:\r
- case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:\r
- case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:\r
- break;\r
- default:\r
- return error(GL_INVALID_ENUM);\r
- }\r
-\r
es2::Context *context = es2::getContext();\r
\r
if(context)\r
{\r
return error(GL_INVALID_OPERATION);\r
}\r
- }\r
\r
- UNIMPLEMENTED();\r
+ switch(pname)\r
+ {\r
+ case GL_UNIFORM_BLOCK_BINDING:\r
+ *params = static_cast<GLint>(program->getUniformBlockBinding(uniformBlockIndex));\r
+ break;\r
+ case GL_UNIFORM_BLOCK_DATA_SIZE:\r
+ case GL_UNIFORM_BLOCK_NAME_LENGTH:\r
+ case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:\r
+ case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:\r
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:\r
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:\r
+ program->getActiveUniformBlockiv(uniformBlockIndex, pname, params);\r
+ break;\r
+ default:\r
+ return error(GL_INVALID_ENUM);\r
+ }\r
+ }\r
}\r
\r
GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)\r
{\r
return error(GL_INVALID_OPERATION);\r
}\r
- }\r
\r
- UNIMPLEMENTED();\r
+ programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);\r
+ }\r
}\r
\r
GL_APICALL void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)\r
TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",\r
program, uniformBlockIndex, uniformBlockBinding);\r
\r
+ if(uniformBlockBinding >= es2::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS)\r
+ {\r
+ return error(GL_INVALID_VALUE);\r
+ }\r
+\r
es2::Context *context = es2::getContext();\r
\r
if(context)\r
{\r
return error(GL_INVALID_VALUE);\r
}\r
- }\r
\r
- UNIMPLEMENTED();\r
+ programObject->bindUniformBlock(uniformBlockIndex, uniformBlockIndex);\r
+ }\r
}\r
\r
GL_APICALL void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)\r
\r
return false;\r
}\r
+\r
+ std::string ParseUniformName(const std::string &name, size_t *outSubscript)\r
+ {\r
+ // Strip any trailing array operator and retrieve the subscript\r
+ size_t open = name.find_last_of('[');\r
+ size_t close = name.find_last_of(']');\r
+ bool hasIndex = (open != std::string::npos) && (close == name.length() - 1);\r
+ if(!hasIndex)\r
+ {\r
+ if(outSubscript)\r
+ {\r
+ *outSubscript = GL_INVALID_INDEX;\r
+ }\r
+ return name;\r
+ }\r
+\r
+ if(outSubscript)\r
+ {\r
+ int index = atoi(name.substr(open + 1).c_str());\r
+ if(index >= 0)\r
+ {\r
+ *outSubscript = index;\r
+ }\r
+ else\r
+ {\r
+ *outSubscript = GL_INVALID_INDEX;\r
+ }\r
+ }\r
+\r
+ return name.substr(0, open);\r
+ }\r
}\r
\r
namespace es2sw\r
bool IsColorRenderable(GLenum internalformat);\r
bool IsDepthRenderable(GLenum internalformat);\r
bool IsStencilRenderable(GLenum internalformat);\r
+\r
+ // Parse the base uniform name and array index. Returns the base name of the uniform. outSubscript is\r
+ // set to GL_INVALID_INDEX if the provided name is not an array or the array index is invalid.\r
+ std::string ParseUniformName(const std::string &name, size_t *outSubscript);\r
}\r
\r
namespace es2sw\r