前言
直接状态访问( DSA ) 是一种修改 OpenGL 对象而无需将它们绑定到上下文的方法。这允许在本地上下文中修改对象状态,而不会影响应用程序所有部分共享的全局状态,即直接访问一个对象的状态而不需要绑定到全局状态机上。它还使 API 更加面向对象,因为可以清楚地识别修改对象状态的函数。
在 2014 年发布的 OpenGL4.5 标准,ARB_direct_state_access 扩展进入核心。在没有 DSA 的时代,需要按照状态机模式 bind 对象为当前操作对象后在进行全局操作。
文档:https://www.khronos.org/opengl/wiki/Direct_State_Access
文档:https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_direct_state_access.txt
正文
OpenGL 之前一直采用状态机模式进行操作,如顶点初始化数据:
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
先调用 bind 绑定对象为状态机的全局对象,后面的操作虽然没有指定这个对象,但还是可以正确的对该对象进行操作。在代码复杂的时候,如果 bind 和操作没有匹配上就很尴尬了。频繁的切换 bind,驱动层频繁查找与解引用,影响性能。
在 2014 年发布的 OpenGL4.5 标准,ARB_direct_state_access 扩展进入核心。
一些接口命名上的更新:
这里有一些不同点。以前的 glGen* 系列函数只生成对象 id,内部没有初始化相关状态,这是在 glBind* 时进行的;而 4.5 的 DSA 提供的 glCreate* 系列函数,生成 id 的同时也进行了初始化。还有就是,很多 DSA 函数,都需要配合 glCreate* 来使用,不能用于 glGen* 。
对比
顶点不使用DSA:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
顶点使用DSA:
glCreateVertexArrays(1, &vao);
glCreateBuffers(1, &vbo);
glNamedBufferStorage(vbo, sizeof(vertices), vertices, GL_DYNAMIC_STORAGE_BIT);
glVertexArrayVertexBuffer(vao, 0, vbo, 0, 3*sizeof(float));
glEnableVertexArrayAttrib(vao, 0);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vao, 0, 0);
以下来自参考博客
着色器程序不使用DSA:
glUseProgram(progId);
glUniform1f(loc, x);
着色器程序使用DSA:
glProgramUniform1fEXT(progId, loc, x);
纹理不使用 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);
纹理使用 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);
帧缓冲不使用DSA:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tid, 0);
帧缓冲使用DSA:
glCreateFramebuffers(1, &fbo);
glNamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0, tex, 0);
glNamedFramebufferTexture(fbo, GL_DEPTH_ATTACHMENT, depthTex, 0);
缓冲不使用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);
缓冲使用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);
参考
文档:https://www.khronos.org/opengl/wiki/Direct_State_Access
文档:https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_direct_state_access.txt
博客:https://zhuanlan.zhihu.com/p/23257409
博客:https://zhuanlan.zhihu.com/p/33504469