25

浅谈OpenGL之DSA

 3 years ago
source link: http://www.cnblogs.com/hellobb/p/13943969.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

今天准备写一篇文章简单介绍一下OpenGL4.5引入的一个新的扩展ARB_direct_state_access,这个扩展为OpenGL引入了一个新的特性就是Direct State Acess,下文统称为DSA。

那么什么是DSA,又为什么要引入DSA呢?

了解OpenGL的都知道,它的设计是一个基于状态机的API,你的每一次资源绑定,纹理绑定,修改渲染状态等等都会改变一个全局的状态机。这种设计的最大问题就是容易造成状态泄露,你可能只是想为纹理设置一个参数,但是却要改变状态机的纹理绑定,而这个状态你如果不修改,会一直泄露到其他的DrawCall中。这就给基于OpenGL的渲染引擎设计带来很多的问题,大多数引擎都会通过自己的方式来确保一个DrawCall的状态不会泄露到另一个DrawCall,从而导致一些非常难以调试的BUG。

那么为了从一定程度上缓解这个问题,OpenGL就引入了DSA。DSA可以让你直接访问一个object的状态而不需要绑定到全局状态机上 。比如没有DSA时,你需要先绑定一个buffer的object,才能为它分配存储空间,上传数据等,而有了DSA,你就可以直接访问object,为它分配存储,上传数据,避免将其绑定到状态机上。

但是我为什么说是一定程度上缓解呢,因为DSA不能完全避免绑定,当你将buffer或者texture真正用到渲染进程上时,你还是要将它们绑定到上下文里。比如前面你通过DSA的方式分配了一个buffer object,也为它上传了数据,现在你想将其用到某次DrawCall中作为uniform数据,你就需要调用glBindBufferRange(GL_UNIFORM_BUFFER,object,...)。将object绑定到指定Target上。

虽然如此,有了DSA还是可以为程序设计带来很多的方便。你仅仅需要在真正绘制的时候绑定object,而不是在各种初始化时就要绑定它,从一定程度上减少了状态机切换的次数。

下面我就简单列举几个DSA引入的新的API和旧的API之间的对比

Program

Without DSA:

glUseProgram(progId);
glUniform1f(loc, x);

With DSA:

glProgramUniform1fEXT(progId, loc, x);

Texture

Without DSA:

glGenTextures(1, &name); 
glBindTexture(GL_TEXTURE_2D, name); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height); 
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

With DSA:

glCreateTextures(GL_TEXTURE_2D, 1, &name);
glTextureParameteri(name, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTextureParameteri(name, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); 
glTextureParameteri(name, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTextureParameteri(name, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTextureStorage2D(name, 1, GL_RGBA8, width, height); 
glTextureSubImage2D(name, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

Framebuffer

Without DSA:

glGenFramebuffers(1, &fbo); 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tid, 0);

With DSA:

glCreateFramebuffers(1, &fbo); 
glNamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0, tex, 0); 
glNamedFramebufferTexture(fbo, GL_DEPTH_ATTACHMENT, depthTex, 0);

Buffer

Without DSA

struct vertex_t { vec3 pos, nrm; vec2 tex; }; glBindVertexArray(vao); 
glBindVertexBuffer(0, vbo, 0, sizeof(vertex_t)); 
glEnableVertexAttribArray(0); 
glEnableVertexAttribArray(1); 
glEnableVertexAttribArray(2); 
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, offsetof(vertex_t, pos)); 
glVertexAttribFormat(1, 3, GL_FLOAT, GL_FALSE, offsetof(vertex_t, nrm)); 
glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, offsetof(vertex_t, tex)); 
glVertexAttribBinding(0, 0); 
glVertexAttribBinding(1, 0); 
glVertexAttribBinding(2, 0);

With DSA

glVertexArrayVertexBuffer(vao, 0, data->vbo, 0, sizeof(vertex_t)); 
glEnableVertexArrayAttrib(vao, 0); 
glEnableVertexArrayAttrib(vao, 1); 
glEnableVertexArrayAttrib(vao, 2); 
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, offsetof(vertex_t, pos)); 
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, offsetof(vertex_t, nrm)); 
glVertexArrayAttribFormat(vao, 2, 2, GL_FLOAT, GL_FALSE, offsetof(vertex_t, tex)); 
glVertexArrayAttribBinding(vao, 0, 0); 
glVertexArrayAttribBinding(vao, 1, 0); 
glVertexArrayAttribBinding(vao, 2, 0);

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK