http://luluathena.com/
rss
email
twitter
facebook
  • About me
  • map

在GLES中使用Separate Shader Objects

1 comment
Posted on 1月 26 2014 by luluathena

一些介绍

在苹果的Best Practices for Shaders中,介绍到了Separate Shader Objects,用于加快shader编译和链接的速度,减少program和shader object的占用。

对于许多项目来说,vertex shader和fragment shader都是复用的,例如一个vertex shader配上各种fragment shader,实现不同的渲染效果,我们将其称为一个program。在没有实现Separate Shader Objects之前,一个vertex shader要为每个program编译和链接一遍,最后导致生成了大量的shader 和program。

iOS上支持EXT_separate_shader_objects扩展,让我们能够分别编译链接两种shader,然后使用program pipeline来搭配shader。demo里有3个vs , 12个ps 共计15个program,编译链接加上一些初始化数据需要270+ms,使用了Separate Shader Objects之后,仅需编译链接3个vs和12个ps,耗时80+ms。

一些栗子

关于如何使用Separate Shader Objects这里 有篇文章给了详细的例子。OpenGL的WIKI上也有很多细节的说明。你可以仍然使用传统的流程, 创建和编译shader,然后创建和链接一个program,只需要加上一句:

C++
1
glProgramParameter(program, GL_PROGRAM_SEPARABLE, GL_TRUE);

另外一种更简练的用法是:

C++
1
GLuint glCreateShaderProgramv​(GLenum type​, GLsizei count​, const char **strings​);

如果没有特殊的需求,比较推荐用第二种方法,但也有些缺陷,例如无法再设置任何的pre-link parameters到program中。在之前的博文中,我提到通过glBindAttribLocation来绑定attribute到VBO,在glLinkProgram之前调用。如果使用了glCreateShaderProgramv​,就无法再这样做了。

好消息是,我们可以在shader中解决这个问题。我在这篇文章里找到了答案:

C++
1
2
3
4
5
// GLSL code:
#extension GL_EXT_separate_shader_objects : enable
layout(location = 0) attribute vec4 myPostion;
layout(location = 1) attribute vec3 myNormal;
void main() { ... }

对于不支持EXT_separate_shader_objects扩展的设备来说,上面那段shader代码会编译出错。考虑到兼容性,需要把代码改成这样:

C++
1
2
3
4
5
6
7
8
9
10
11
12
// GLSL code:
#extension GL_EXT_separate_shader_objects : enable
 
#ifdef GL_EXT_separate_shader_objects
#define UseLayout(x) layout(location = x)
#else
#define UseLayout(x)
#endif
 
UseLayout(0) attribute vec4 myPostion;
UseLayout(1) attribute vec3 myNormal;
void main() { ... }

如果设备不支持这个扩展的话,只会在第2行打个warning,不影响使用。

然后,通过glGenProgramPipelines​创建pipeline,将vertex shader和fragment shader绑定到pipeline的各个stage上,在渲染时,调用glBindProgramPipeline​来启用某个pipeline。值得一提的是,如果你的程序混用了传统program和pipeline,建议在之前先调用glUseProgram(0),防止生效的是program而不是pipeline。

一些坑

切换到Separate Shader Objects,遇到了一个shader编译错误“implementation limit of 32 varying components exceeded”。也就是上一篇博文里提到的,将texCoord的运算提前到vertex shader中进行,我申请了16个vec2的varying。

在传统program的编译链接中,这样写是没问题的,因为16个vec2没有超过32个components(一个x\y\z分量即一个component)。不清楚为什么shader program就不支持。我试着改成8个vec4,就没有问题了。但是我又不能使用zw分量来访问纹理,在之前的博文里提到了,这样很低效。于是,我只能减少varying的使用了。

另一个问题是,有些材质渲染不出来了。前面的几篇文章里也有提到,由于单独编译链接一个shader,无法在链接时对shader之间的输入输出做匹配。当vertex shader和fragment shader之间出现了mismatch,不会产生错误,但是shader的某些输入会出现undefined的情况。

例如vertex shader中定义:

C++
1
2
varying vec4 color;
varying vec4 texcoord;

而fragment shader中仅仅使用了texcoord,就会导致渲染效果不对。

目前只发现了这两个问题, 总的来说还是值得使用的,等以后踩了坑,再来补充: P


  Tags: iOS, OpenGL ES Category: 总结|感想

One Comment

  1. 王烁说道:
    一月 15, 2015 8:12 上午

    学习OpenGL ES3.1的时候无意中发现你的文章,厉害,看日期咱俩应该是同届。认识一下~我的个人网站www.geekfaner.com。

    回复

Leave a Reply

点击这里取消回复。




分类目录

  • 生活 (217)
    • 不高兴 (65)
    • 伪文艺 (40)
    • 没头脑 (114)
  • 程序 (71)
    • 总结|感想 (19)
    • 笔记|翻译 (34)
    • 算法|应用 (17)
  • 绘画 (30)
    • SAI|PS (14)
    • 彩铅 (17)

标签

Bezier bloom BluePrint3D Cache cloth simulation coq CUDA D3D9 D3D10 Deferred Lighting Dynamic Texture Lookups evernote facial animation Gesture glsl iOS mali MSVC2008 NPAR OpenCV OpenGL OpenGL ES PBR PowerVR Python QT Ray Tracing SAI Self Calibration SSAO Stereo Match trimesh 优化 学习 工作 总结 手势 破窗理论 钢笔路径
2018年四月
一 二 三 四 五 六 日
« 4月    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

近期文章

  • GDC2017游记
  • 从0开始pbr
  • 不好意思称作2015总结的总结
  • 迟到的2014年度总结
  • 毕业两年多后

文章归档


  • About me
  • map
Powered by Wordpress  |  Designed by WebTreats