| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /****************************************************************************
- Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos2d-x.org
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "Program.h"
- #include "GFXUtils.h"
- #include <unordered_map>
- #include <stdlib.h>
- #include <string.h>
- namespace {
- uint32_t _genID = 0;
- std::string logForOpenGLShader(GLuint shader)
- {
- GLint logLength = 0;
- GL_CHECK(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength));
- if (logLength < 1)
- return "";
- char *logBytes = (char*)malloc(sizeof(char) * logLength);
- GL_CHECK(glGetShaderInfoLog(shader, logLength, nullptr, logBytes));
- std::string ret(logBytes);
- free(logBytes);
- return ret;
- }
- std::string logForOpenGLProgram(GLuint program)
- {
- GLint logLength = 0;
- GL_CHECK(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength));
- if (logLength < 1)
- return "";
- char *logBytes = (char*)malloc(sizeof(char) * logLength);
- GL_CHECK(glGetProgramInfoLog(program, logLength, nullptr, logBytes));
- std::string ret(logBytes);
- free(logBytes);
- return ret;
- }
- bool _createShader(GLenum type, const std::string& src, GLuint* outShader)
- {
- assert(outShader != nullptr);
- GLuint shader = glCreateShader(type);
- const GLchar* sources[] = { src.c_str() };
- GL_CHECK(glShaderSource(shader, 1, sources, nullptr));
- GL_CHECK(glCompileShader(shader));
- GLint status;
- GL_CHECK(glGetShaderiv(shader, GL_COMPILE_STATUS, &status));
- if (!status)
- {
- GLsizei length;
- GL_CHECK(glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &length));
- GLchar* source = (GLchar *)malloc(sizeof(GLchar) * length);
- GL_CHECK(glGetShaderSource(shader, length, nullptr, source));
- RENDERER_LOGE("ERROR: Failed to compile shader:\n%s", source);
- std::string shaderLog = logForOpenGLShader(shader);
- RENDERER_LOGE("%s", shaderLog.c_str());
- free(source);
- *outShader = 0;
- return false;
- }
- *outShader = shader;
- return true;
- }
- #define DEF_TO_INT(pointer) (*(int*)(pointer))
- #define DEF_TO_FLOAT(pointer) (*(float*)(pointer))
- void setUniform1i(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- assert(count == 1);
- if (elementType == cocos2d::renderer::UniformElementType::INT)
- {
- glUniform1i(location, DEF_TO_INT(value));
- }
- else
- {
- float floatVal = *((float*)value);
- GLint intVal = (GLint)floatVal;
- glUniform1i(location, intVal);
- }
- }
- void setUniform1iv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform1iv(location, count, (const GLint*)value);
- }
- void setUniform2iv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform2iv(location, count, (const GLint*)value);
- }
- void setUniform3iv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform3iv(location, count, (const GLint*)value);
- }
- void setUniform4iv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform4iv(location, count, (const GLint*)value);
- }
- void setUniform1f(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- assert(count == 1);
- glUniform1f(location, DEF_TO_FLOAT(value));
- }
- void setUniform1fv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform1fv(location, count, (const GLfloat*)value);
- }
- void setUniform2fv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform2fv(location, count, (const GLfloat*)value);
- }
- void setUniform3fv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform3fv(location, count, (const GLfloat*)value);
- }
- void setUniform4fv(GLint location, GLsizei count , const void* value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniform4fv(location, count, (const GLfloat*)value);
- }
- void setUniformMatrix2fv(GLint location, GLsizei count, const void *value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniformMatrix2fv(location, count, GL_FALSE, (const GLfloat*)value);
- }
- void setUniformMatrix3fv(GLint location, GLsizei count, const void *value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniformMatrix3fv(location, count, GL_FALSE, (const GLfloat*)value);
- }
- void setUniformMatrix4fv(GLint location, GLsizei count, const void *value, cocos2d::renderer::UniformElementType elementType)
- {
- glUniformMatrix4fv(location, count, GL_FALSE, (const GLfloat*)value);
- }
- /**
- * _type2uniformCommit
- */
- std::unordered_map<GLenum, cocos2d::renderer::Program::Uniform::SetUniformCallback> _type2uniformCommit = {
- { GL_INT, setUniform1i },
- { GL_FLOAT, setUniform1f },
- { GL_FLOAT_VEC2, setUniform2fv },
- { GL_FLOAT_VEC3, setUniform3fv },
- { GL_FLOAT_VEC4, setUniform4fv },
- { GL_INT_VEC2, setUniform2iv },
- { GL_INT_VEC3, setUniform3iv },
- { GL_INT_VEC4, setUniform4iv },
- { GL_BOOL, setUniform1i },
- { GL_BOOL_VEC2, setUniform2iv },
- { GL_BOOL_VEC3, setUniform3iv },
- { GL_BOOL_VEC4, setUniform4iv },
- { GL_FLOAT_MAT2, setUniformMatrix2fv },
- { GL_FLOAT_MAT3, setUniformMatrix3fv },
- { GL_FLOAT_MAT4, setUniformMatrix4fv },
- { GL_SAMPLER_2D, setUniform1i },
- { GL_SAMPLER_CUBE, setUniform1i }
- };
- /**
- * _type2uniformArrayCommit
- */
- std::unordered_map<GLenum, cocos2d::renderer::Program::Uniform::SetUniformCallback> _type2uniformArrayCommit = {
- { GL_INT, setUniform1iv },
- { GL_FLOAT, setUniform1fv },
- { GL_FLOAT_VEC2, setUniform2fv },
- { GL_FLOAT_VEC3, setUniform3fv },
- { GL_FLOAT_VEC4, setUniform4fv },
- { GL_INT_VEC2, setUniform2iv },
- { GL_INT_VEC3, setUniform3iv },
- { GL_INT_VEC4, setUniform4iv },
- { GL_BOOL, setUniform1iv },
- { GL_BOOL_VEC2, setUniform2iv },
- { GL_BOOL_VEC3, setUniform3iv },
- { GL_BOOL_VEC4, setUniform4iv },
- { GL_FLOAT_MAT2, setUniformMatrix2fv },
- { GL_FLOAT_MAT3, setUniformMatrix3fv },
- { GL_FLOAT_MAT4, setUniformMatrix4fv },
- { GL_SAMPLER_2D, setUniform1iv },
- { GL_SAMPLER_CUBE, setUniform1iv }
- };
- } // namespace {
- RENDERER_BEGIN
- void Program::Uniform::setUniform(const void* value, UniformElementType elementType, size_t uniformCount) const
- {
- // uniformCount may bigger than size.
- if (size >= 1 && size < uniformCount) uniformCount = size;
- GLsizei count = size == -1 ? 1 : (GLsizei)uniformCount;
- _callback(location, count, value, elementType);
- }
- Program::Program()
- : _device(nullptr)
- , _id(0)
- , _linked(false)
- {
- }
- Program::~Program()
- {
- GL_CHECK(glDeleteProgram(_glID));
- }
- bool Program::init(DeviceGraphics* device, const char* vertSource, const char* fragSource)
- {
- assert(device);
- assert(vertSource);
- assert(fragSource);
- _device = device;
- _vertSource = vertSource;
- _fragSource = fragSource;
- _id = _genID++;
- _linked = false;
- return true;
- }
- void Program::link()
- {
- if (_linked) {
- return;
- }
- GLuint vertShader;
- bool ok = _createShader(GL_VERTEX_SHADER, _vertSource, &vertShader);
- if (!ok)
- return;
- GLuint fragShader;
- ok = _createShader(GL_FRAGMENT_SHADER, _fragSource, &fragShader);
- if (!ok)
- {
- glDeleteShader(vertShader);
- return;
- }
- GLuint program = glCreateProgram();
- GL_CHECK(glAttachShader(program, vertShader));
- GL_CHECK(glAttachShader(program, fragShader));
- GL_CHECK(glLinkProgram(program));
- GLint status = GL_TRUE;
- GL_CHECK(glGetProgramiv(program, GL_LINK_STATUS, &status));
- if (status == GL_FALSE)
- {
- RENDERER_LOGE("ERROR: Failed to link program: %u", program);
- std::string programLog = logForOpenGLProgram(program);
- RENDERER_LOGE("%s", programLog.c_str());
- glDeleteShader(vertShader);
- glDeleteShader(fragShader);
- glDeleteProgram(program);
- return;
- }
- glDeleteShader(vertShader);
- glDeleteShader(fragShader);
- _glID = program;
- // parse attribute
- GLint numAttributes;
- glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttributes);
- if (numAttributes > 0)
- {
- GLint length;
- glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length);
- if (length > 0)
- {
- GLchar* attribName = (GLchar*) malloc(length + 1);
- Attribute attribute;
- for (GLint i = 0; i < numAttributes; ++i) {
- // Query attribute info.
- glGetActiveAttrib(program, i, length, nullptr, &attribute.size, &attribute.type, attribName);
- attribName[length] = '\0';
- attribute.name = attribName;
- attribute.hashName = std::hash<std::string>{}(attribName);
- // Query the pre-assigned attribute location
- attribute.location = glGetAttribLocation(program, attribName);
- _attributes.push_back(std::move(attribute));
- }
- free(attribName);
- }
- }
- // Query and store uniforms from the program.
- GLint activeUniforms;
- glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
- if (activeUniforms > 0)
- {
- GLint length;
- glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &length);
- if (length > 0)
- {
- GLchar* uniformName = (GLchar*) malloc(length + 1);
- Uniform uniform;
- for (int i = 0; i < activeUniforms; ++i)
- {
- // Query uniform info.
- GL_CHECK(glGetActiveUniform(program, i, length, nullptr, &uniform.size, &uniform.type, uniformName));
- uniformName[length] = '\0';
- bool isArray = false;
- // remove possible array '[]' from uniform name
- if (length > 3)
- {
- char* c = strrchr(uniformName, '[');
- if (c)
- {
- *c = '\0';
- isArray = true;
- }
- }
- uniform.name = uniformName;
- uniform.hashName = std::hash<std::string>{}(uniformName);
- GL_CHECK(uniform.location = glGetUniformLocation(program, uniformName));
- GLenum err = glGetError();
- if (err != GL_NO_ERROR)
- {
- RENDERER_LOGE("error: 0x%x uniformName: %s", (int)err, uniformName);
- }
- assert(err == GL_NO_ERROR);
- if (!isArray)
- {
- uniform.size = -1;
- auto iter = _type2uniformCommit.find(uniform.type);
- assert(iter != _type2uniformCommit.end());
- uniform._callback = iter->second;
- }
- else
- {
- auto iter = _type2uniformArrayCommit.find(uniform.type);
- assert(iter != _type2uniformArrayCommit.end());
- uniform._callback = iter->second;
- }
- _uniforms.push_back(std::move(uniform));
- }
-
- free(uniformName);
- }
- }
- _linked = true;
- }
- RENDERER_END
|