着色器链接到Program

| 分类 cocos2d-x  | 标签 opengles  cocos2d-x 

本文为xiedantibu在学习opengles的笔记 ,转载请注明作者及出处! ###目录 —-     创建删除Program
    链接着色器到Program
    从Program中解除着色器
    opengles出错处理
    cocos2d-x中着色器绑定到Program流程
    生成可执行程序
    查询Program的相关状态
    绑定顶点属性索引到属性变量
    查询属性的信息
    获取program的log信息
    获取一致变量的索引
    查询一致变量的信息
    cocos2d-x中Program的link
    Reference


####创建删除ProgramGLuint glCreateProgram(void)

这个函数没输入参数,它返回新建项目的句柄

void glDeleteProgram(GLuint program)

program :要删除项目的句柄 着色器在使用的时候,需要链接到一个容器中,这个容器称之为着色器程序容器。通过`glCreateProgram`创建这个容器,返回这个容器的句柄。

####链接着色器到Programvoid glAttachShader(GLuint program, GLuint shader)

program :项目的句柄
shader :着色器句柄

将着色器对象shader关联到着色器程序program上。着色器对象可以在任何时候关联到着色器程序,但是它的功能只有经过程序的成功链接之后才是可用的。着色器对象可以同时关联到多个不同的着色器程序上,一个程序只能有一个顶点着色器和一个片元着色器。


####从Program中解除着色器void glDetachShader(GLuint program, GLuint shader)

program :项目的句柄 
shader :着色器句柄

如果我们需要从程序中移除一个着色器对象,从而改变着色器的操作,那么可以调用glDetachShader()函数,设置对应的着色器对象标识符来解除对象的关联


####opengles出错处理GLenum glGetError(void)

返回当前错误码,并将错误码复位成GL_NO_ERROR,如果返回GL_NO_ERROR,说明自从上次查询后,没有错误产生。

| 错误码 | 描述 | |:————-: |:—————:| |GL_NO_ERROR | 没错误产生自从上次 glGetError()调用后 | | GL_INVALID_ENUM | 枚举值超出枚举范围,错误被忽略 | | GL_INVALID_VALUE |数值超出枚举范围,错误被忽略 | |GL_INVALID_OPERATION | 命令不能被执行,在当前环境下,错误被忽略 | | GL_OUT_OF_MEMORY | 没有足够内存执行命令,如果错误产生,OpenGL ES的管线状态不确定|
OpenGL ES命令出错会产生一个错误码,错误码被记录,能够使用glGetError函数查询,在第一个被记录的错误码被查询前,不会记录新的错误码。一旦错误码被查询,当前错误码将变成GL_NO_ERROR。除了GL_OUT_OF_MEMORY错误码以外,其它的错误码将被忽略, 不影响程序运行状态。


####cocos2d-x中着色器绑定到Program流程

bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
{
_program = glCreateProgram();//创建Program
CHECK_GL_ERROR_DEBUG();//宏定义封装了glGetError
_vertShader = _fragShader = 0;//顶点着色器以及片元着色器句柄初始化
if (vShaderByteArray)//如果顶点着色器源码不为null
{
    if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray))//编译顶点着色器源码,同时赋值了顶点着色器句柄,在上文中已经详解了编译着色器内容
    {
        CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
        return false;
   }
}
if (fShaderByteArray)//如果片元着色器源码不为null
{
    if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray)) 编译片元着色器源码,同时赋值了片元着色器句柄,在上文中已经详解了编译着色器内容
    {
        CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
        return false;
    }
}
if (_vertShader)//顶点着色器句柄不为0
{
    glAttachShader(_program, _vertShader);//将顶点着色器句柄链接到Program中
}
CHECK_GL_ERROR_DEBUG(); //宏定义封装了glGetError
if (_fragShader)//片元着色器句柄不为0
{
    glAttachShader(_program, _fragShader); //将片元着色器句柄链接到Program中
}
_hashForUniforms.clear();//compileShader是个std::unordered_map<GLint, GLvoid*>类型的map,它的主要功能是通过比较统一变量的location,以及统一变量的值来判断是否需要向着色器传递相应的值。主要方法涉及到updateUniformLocation,setUniformLocationWithMatrix4fv等
CHECK_GL_ERROR_DEBUG();
return true;
}

####生成可执行程序void glLinkProgram(GLuint program)

program :项目的句柄

通过调用glLinkProgram方法,链接生成一个完整的着色器可执行程序。


####查询Program的相关状态void glGetProgramiv(GLuint program, GLenum pname, GLint *params)

program :program句柄
pname :查询条件
params :返回结果

通过glGetProgramiv方法可以检查链接是否成功. 当参数为GL_LINK_STATUS。如果返回GL_TRUE,那么链接成功,否则返回GL_FALSE

相关参数:

  1. GL_ACTIVE_ATTRIBUTES –当前正在被项目使用的属性数量
  2. GL_ACTIVE_ATTRIBUTE_MAX_LENGTH –当前正在被项目使用的属性最长字段长度
  3. GL_ACTIVE_UNIFORMS –当前正在被项目使用的一致变量
  4. GL_ACTIVE_UNIFORM_MAX_LENGTH –当前正在被项目使用的一致变量最长字段长度
  5. GL_ATTACHED_SHADERS –当前正在被项目使用的着色器数量
  6. GL_DELETE_STATUS –The GL_DELETE_STATUS query returns whether a program object has been marked for deletion
  7. GL_INFO_LOG_LENGTH – As with shader objects, program objects store an info log, the length of which can be queried for using GL_INFO_LOG_LENGTH.
  8. GL_LINK_STATUS –To check whether a link was successful, you can query for GL_LINK_STATUS.
  9. GL_VALIDATE_STATUS –检查项目当前的执行状态,当然也可以通过glValidateProgram方法检测渲染是否成功,如果你使用glValidateProgram仅仅为了调试,这将是缓慢的,不能在渲染前随时使用。 如果你的应用成功渲染,就不要使用它了

####绑定顶点属性索引到属性变量

  1. void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name)

    program :项目句柄
    index :一般的顶点属性索引
    name :属性变量名字
    

顶点着色器中使用glBindAttribLocation绑定一个普通的顶点属性索引到属性变量, 这个绑定在项目下次链接时有效,在当前链接的项目里不会改变.通过glBindAttribLocation方法需要我们预先设置一个索引值和变量绑定

  1. GLint glGetAttribLocation(GLuint program,const GLchar *name)

    program :项目句柄 name :属性变量名字

glGetAttribLocation返回一个绑定属性变量名字的普通属性索引.opengles会自动绑定所有attributes,外部程序只需通过glGetAttribLocation获取指定attribute名的index.当然如果当项目句柄不是一个有效的引用或者在绑定到项目中的顶点着色器中没有指定attribute的名字,则返回-1,表明是一个无效的属性索引。


上诉两个方法都可以将顶点属性索引绑定到属性变量中。一种是自动绑定,我们获取绑定的索引,另外一种是通过事先设置的索引绑定。当然在通过glBindAttribLocation绑定后,再调用glGetAttribLocation方法则是查询相应的attributes的属性索引,而不是重新自动绑定。


####查询属性的信息void glGetActiveAttrib(GLuint program, GLuint index,GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)

program :项目句柄
index :指定需要查询的顶点属性,值是0到GL_ACTIVE_ATTRIBUTES-1。GL_ACTIVE_ATTRIBUTES值使用glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTES, &activeAttributes)确定
bufsize :specifies the maximum number of characters that may be written into name, including the null terminator.
length :returns the number of characters written into name, excluding the null terminator, if length is not NULL.
size :返回属性的大小,指定返回单元类型的单位。如果不是数组,应该是1;如果是数组,返回数组的尺寸
type :returns the type of the attribute. Valid values are GL_FLOAT GL_FLOAT_VEC2 GL_FLOAT_VEC3 GL_FLOAT_VEC4 GL_FLOAT_MAT2 GL_FLOAT_MAT3
	   ...
name :name of the attribute variable as declared in the vertex shader.

####获取program的log信息void glGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog)

program :程序的句柄
maxLength :the size of the buffer in which to store the info log
length :the length of the info log written (minus the null terminator); if the length does not need to be known,this parameter can be NULL
infoLog :pointer to the character buffer in which to store the info log

在调用glGetProgramInfoLog之前,一般都调用glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength)方法,事先获取log长度。


####获取一致变量的索引GLint glGetUniformLocation(GLuint program, const GLchar* name)

program :handle to the program object
name :the name of the uniform for which to get the location

glGetUniformLocation方法将返回被这个一致变量名字绑定的索引,如果该变量在着色器中没有找到,将返回-1.


####查询一致变量的信息void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length,GLint *size, GLenum *type, GLchar *name)

program :程序的句柄
index :the uniform index to be queried
bufSize :the number of characters in the name array
length :if not NULL, will be written with the number of characters written into the name array (less the null terminator)
size :if the uniform variable being queried is an array, this variable will be written with the maximum array element used in the program (plus 1); if the uniform variable being queried is not an array, this value will be 1
type :will be written with the uniform type; can be GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3,GL_FLOAT_VEC4, GL_INT, GL_INT_VEC2, GL_INT_VEC3,GL_INT_VEC4, GL_UNSIGNED_INT,GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3,GL_UNSIGNED_INT_VEC4, GL_BOOL, GL_BOOL_VEC2,GL_BOOL_VEC3, GL_BOOL_VEC4, GL_FLOAT_MAT2...
name :will be written with the name of the uniform up to bufSize number of characters; this will be a null-terminated string

glGetActiveUniform()方法和glGetActiveAttrib类似,返回变量的相关信息


####cocos2d-x中Program的link

  • GLProgram::link()方法具体实现解析

    bool GLProgram::link()
    {
    CCASSERT(_program != 0, "Cannot link invalid program");//断言判断program是否可用
    GLint status = GL_TRUE;
    bindPredefinedVertexAttribs();//将预先设置的属性索引绑定到属性名字上,具体调用glBindAttribLocation
    glLinkProgram(_program);//链接生成一个完整的着色器可执行程序
    parseVertexAttribs();//解析顶点着色器的属性
    parseUniforms();//解析着色器的一致变量
    if (_vertShader)//如果着色器正连接着一个项目对象,glDeleteShader不会立刻删除着色器,而是设置删除标记,一旦着色器不再连接项目对象,才删除着色器使用的内存
    {
    	glDeleteShader(_vertShader);
    }
    if (_fragShader)
    {
    	glDeleteShader(_fragShader);
    }
       	 	_vertShader = _fragShader = 0;
    return (status == GL_TRUE);
    }
    
  • GLProgram::bindPredefinedVertexAttribs()方法具体实现

    void GLProgram::bindPredefinedVertexAttribs()
    {
    static const struct {
    const char *attributeName;//属性的名字
    int location;//属性的索引
    } attribute_locations[] =
    {
    {GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION},//POSITION属性
    {GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR},//COLOR属性
    {GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD},//纹理shux
    {GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1},
    {GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2},
    {GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3},
    {GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL},//法线属性
    };
    const int size = sizeof(attribute_locations)/sizeof(attribute_locations[0]);
    for(int i=0; i<size;i++) {
    glBindAttribLocation(_program, attribute_locations[i].location, attribute_locations[i].attributeName);//把属性名字绑定到索引上
    }
    }
    
  • parseVertexAttribs方法实现

    void GLProgram::parseVertexAttribs()
    {
    _vertexAttribs.clear();//清空存储顶点属性的unordered_map
    GLint activeAttributes;//属性的个数
    GLint length;//最长属性名字的长度
    glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);//获取属性的总个数
    if(activeAttributes > 0)
    {
    VertexAttrib attribute;
    glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length);//获取最长属性名字的长度
    if(length > 0)
    {
        GLchar* attribName = (GLchar*) alloca(length + 1);//开辟一片空间保存属性名字
        for(int i = 0; i < activeAttributes; ++i)//通过迭代activeAttributes,遍历查询属性信息。从0至GL_ACTIVE_ATTRIBUTES-1
        {
            // 查询属性信息
            glGetActiveAttrib(_program, i, length, nullptr, &attribute.size, &attribute.type, attribName);//注意传入参数i,以及返回的size,type,name
            attribName[length] = '\0';
            attribute.name = std::string(attribName);//保存属性的名字
            // Query the pre-assigned attribute location
            attribute.index = glGetAttribLocation(_program, attribName);//通过名字获取属性索引,注意比较前面的glBindAttribLocation索引
            _vertexAttribs[attribute.name] = attribute;//将获取的属性保存到map中
        }
    }
    }
    else
    {
    GLchar ErrorLog[1024];
    glGetProgramInfoLog(_program, sizeof(ErrorLog), NULL, ErrorLog);//获取program的info
    CCLOG("Error linking shader program: '%s'\n", ErrorLog);
    }
    }
    
  • GLProgram::parseUniforms()具体实现

    void GLProgram::parseUniforms()
    {
    _userUniforms.clear();//清空保存一致变量的map
    GLint activeUniforms;//一致变量在着色器中的数量
    glGetProgramiv(_program, GL_ACTIVE_UNIFORMS, &activeUniforms);//获取着色器中一致变量的总数
    if(activeUniforms > 0)
    {
    GLint length;//最长一致变量的名字长度
    glGetProgramiv(_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &length);//获取最长一致变量的名字长度
    if(length > 0)
    {
        Uniform uniform;
        GLchar* uniformName = (GLchar*)alloca(length + 1);//开辟一片空间保存一致变量名字
        for(int i = 0; i < activeUniforms; ++i)//迭代
        {
            // Query uniform info.
            glGetActiveUniform(_program, i, length, nullptr, &uniform.size, &uniform.type, uniformName);//注意传入的i,以及size,type,name
            uniformName[length] = '\0';
              //当不是以CC_开头的一致遍历的时候保存到map中
            if(strncmp("CC_", uniformName, 3) != 0) {
    
                // remove possible array '[]' from uniform name
                if(length > 3)
                {
                    char* c = strrchr(uniformName, '[');
                    if(c)
                    {
                        *c = '\0';
                    }
                }
                uniform.name = std::string(uniformName);
                uniform.location = glGetUniformLocation(_program, uniformName);//获取相应名字的索引
                GLenum __gl_error_code = glGetError(); 
                if (__gl_error_code != GL_NO_ERROR) 
                { 
                    CCLOG("error: 0x%x", (int)__gl_error_code);
                } 
                assert(__gl_error_code == GL_NO_ERROR);
                    
                _userUniforms[uniform.name] = uniform;
            }
        }
    }
    }
    else
    {
    GLchar ErrorLog[1024];
    glGetProgramInfoLog(_program, sizeof(ErrorLog), NULL, ErrorLog);//programe的log信息
    CCLOG("Error linking shader program: '%s'\n", ErrorLog);
    }
    }
    

以上就是关于cocos中着色器在program的创建链接,以及对于相应属性的编译,以及错误的处理的大体流程


####Reference

青春是一场大雨,即使感冒了,还盼回头再淋一次...image...微笑永远是一个人身上最好看的东西...


PREVIOUS     NEXT