opengl es 链接程序program

连接程序(program)用于连接你的shader和OpenGL es程序,并处理两者之间的数据交互。本文通过分析GPUImage库的GLProgram类,整理下相关知识。

1.创建program
GLuint program = glCreateProgram();
该函数将创建一个空的program对象,并返回一个非零的引用标识。program对象可以附加和移除着色器对象,一般包含顶点着色器和片元着色器。program会根据附加的着色器对象创建一些可执行文件,并使之成为当前渲染环境的一部分。

2.附加着色器

- (BOOL)compileShader:(GLuint *)shader 
                 type:(GLenum)type 
               string:(NSString *)shaderString
{
//    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();

    GLint status;
    const GLchar *source;
    
    source = 
      (GLchar *)[shaderString UTF8String];
    if (!source)
    {
        NSLog(@"Failed to load vertex shader");
        return NO;
    }
    
    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);
    
    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);

    if (status != GL_TRUE)
    {
        GLint logLength;
        glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
        if (logLength > 0)
        {
            GLchar *log = (GLchar *)malloc(logLength);
            glGetShaderInfoLog(*shader, logLength, &logLength, log);
            if (shader == &vertShader)
            {
                self.vertexShaderLog = [NSString stringWithFormat:@"%s", log];
            }
            else
            {
                self.fragmentShaderLog = [NSString stringWithFormat:@"%s", log];
            }

            free(log);
        }
    }   
    
//    CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
//    NSLog(@"Compiled in %f ms", linkTime * 1000.0);

    return status == GL_TRUE;
}

glCreateShader函数创建一个空的着色器对象,并返回一个非零的引用标识。着色器对象用于维护定义着色器的源代码字符串。可以传入GL_VERTEX_SHADER或GL_FRAGMENT_SHADER来创建顶点着色器和片元着色器。着色器对象和与之关联的数据,可以在共享上下文的环境中共享。

glShaderSource(shader,arrCount,stringArr,lengthArr)将着色器对象的源码指定为目标字符串数组中的源码,着色器对象的原有内容将被完全替换。如果长度数组为null,则假定每个字符串都是空终止的。如果不是null,源代码字符串将不被扫描或解析,只是复制到指定的着色器对象中。OpenGL复制着色器源代码字符串,因此你可以在函数返回后立即释放它。
但是,请注意Shader编译器支持是可选的,如果不确定是否支持,可以使用参数GL_SHADER_COMPILER调用glGet来查询。glShaderSource,glCompileShader,glGetShaderPrecisionFormat和glReleaseShaderCompiler将在shader编译器不支持时,生成GL_INVALID_OPERATION。

glCompileShader会编译已存储在由着色器指定的着色器对象中的源代码字符串,并将编译结果保存。你可以通过glGetShaderiv来查询。无论编译是否成功,有关编译的信息都可以通过调用glGetShaderInfoLog从着色器对象的信息日志中获取。

glGetShaderiv可以查询shader对象的状态信息。参数包括GL_SHADER_TYPE,GL_DELETE_STATUS,GL_COMPILE_STATUS,GL_INFO_LOG_LENGTH
(存储信息日志所需的字符缓冲区大小),GL_SHADER_SOURCE_LENGTH(存储着色器源码所需的字符缓冲区的大小)。

    glAttachShader(program, vertShader);

glAttachShader将着色器对象附加到指定的program对象上,以便在连接时生成可执行文件。附加操作在着色器对象生成后,就可以进行。这意味着你可以着色器对象加载源码之前,就将它附加到program对象。
多个相同类型的着色器对象可能不会附加到单个程序对象。但是,单个着色器对象可能会附加到多个程序对象。如果着色器对象在附加到程序对象时被删除,它将被标记为删除,并且直到调用glDetachShader才能将其从它所连接的所有程序对象中分离出来,删除将不会发生。

3.连接program并使用它

    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &status);
    glUseProgram(program);

glLinkProgram执行链接操作,并保存链接状态。shader将根据源码创建可执行文件,所有与program相关的用户定义的uniform将被初始化为0,并且生成一个可以访问的地址,你可以通过调用glGetUniformLocation来查询。所有未绑定到顶点属性索引的attribute,此时都将被链接器绑定。分配的位置可以通过调用glGetAttribLocation来查询。链接操作之后,program可以自由修改附加的着色器对象,编译附加的着色器对象,分离着色器对象,删除着色器对象以及附加其他着色器对象。
在调用glUseProgram之后(program已在使用中),执行链接操作,如果链接成功,glLinkProgram还会将生成的可执行文件安装为当前渲染状态的一部分;如果链接失败,其链接状态将设置为GL_FALSE,但可执行文件和关联状态将保持为当前状态的一部分,直到随后对glUseProgram的调用将其删除而不再使用为止。从使用中删除后,在成功重新链接之前,它不能成为当前状态的一部分。
由于OpenGL ES着色语言规范中规定的多种原因,以下情况链接可能会失败:顶点着色器和片段着色器都不在程序对象中、已超过实施支持的活动属性变量的数量、统一变量的存储限制已被超出、实施支持的有效统一变量的数量已被超过、顶点着色器或片段着色器缺少主要功能、在片段着色器中实际使用的变量变量在顶点着色器中没有以相同方式声明(或者根本没有声明)、对函数或变量名称的引用未解决、共享的全局声明有两种不同的类型或两种不同的初始值、一个或多个附加的着色器对象尚未成功编译(通过glCompileShader),或者加载了预编译的着色器二进制文件(通过glShaderBinary)、绑定通用属性矩阵会导致矩阵的某些行落在允许的最大值GL_MAX_VERTEX_ATTRIBS之外、找不到足够的连续顶点属性槽来绑定属性矩阵。

glUseProgram设置program为当前渲染状态的一部分。如果program为0,当前渲染状态指向无效的program,任何glDrawArrays或glDrawElements命令都会提示未定义。program对象和与之关联的数据,可以在共享上下文的环境中共享。

  1. 通过program获取着色器的属性的位置
- (void)addAttribute:(NSString *)attributeName
{
    if (![attributes containsObject:attributeName])
    {
        [attributes addObject:attributeName];
        glBindAttribLocation(program, 
                             (GLuint)[attributes indexOfObject:attributeName],
                             [attributeName UTF8String]);
    }
}
// END:addattribute
// START:indexmethods
- (GLuint)attributeIndex:(NSString *)attributeName
{
    return (GLuint)[attributes indexOfObject:attributeName];
}
- (GLuint)uniformIndex:(NSString *)uniformName
{
    return glGetUniformLocation(program, [uniformName UTF8String]);
}

glBindAttribLocation(program,index,name)用于将由program对象中的用户定义的属性变量与通用顶点属性索引相关联。name为以空结尾的字符串。index指定要绑定到此变量的通用顶点属性索引。该命令使顶点着色器可以为属性变量使用描述性名称,而不是从0到GL_MAX_VERTEX_ATTRIBS -1编号的通用变量。当程序成为当前状态的一部分时,通过通用顶点属性索引提供的值将修改由name指定的用户定义属性变量的值。发送到每个通用属性索引的值是当前状态的一部分,就像标准顶点属性(如颜色,法线和顶点位置)一样。如果通过调用glUseProgram使一个不同的程序对象成为当前对象,那么新program对象中也会绑定到索引的属性到相同的值。
如果name引用矩阵属性变量,则index引用矩阵的第一列。其他矩阵列然后自动绑定到index+n。通过调用glBindAttribLocation,可以随时显式分配程序对象的属性变量名称到通用属性索引绑定。在调用glLinkProgram之前,属性绑定不会生效。程序对象成功链接后,通用属性的索引值保持不变,直到下一次执行链接命令。应用程序不允许使用此命令绑定任何标准OpenGL顶点属性,因为它们在需要时会自动绑定。在程序对象链接后发生的任何属性绑定将在下次链接程序对象时才生效。
如果name之前被绑定,再次绑定时,以前的绑定信息将丢失。因此,不能将一个用户定义的属性变量绑定到多个索引,但可以将多个用户定义的属性变量绑定到同一个索引。

glGetUniformLocation返回program对象内指定名称的uniform的位置,名称必须是不包含空格的空终止字符串。如果uniform不存在,或者名称以"gl"开头,则返回-1;在program成功链接之前,分配给统一变量的实际位置是未知的。发生链接后,可以使用命令glGetUniformLocation来获取统一变量的位置。然后可以将此位置值传递给glUniform以设置统一变量的值或glGetUniform以查询统一变量的当前值。程序对象成功链接后,统一变量的索引值保持固定,直到发生下一个链接命令。如果链接成功,则只能在链接后查询统一的变量位置和值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容