Today, I'm going to write an article to briefly introduce OpenGL4.5 A new extension introduced ARB_direct_state_access, This extension is OpenGL A new feature introduced is Direct State Acess, Hereinafter collectively referred to as DSA.
So what is DSA, And why introduce DSA Well ?
understand OpenGL Of all know , It's designed to be a state machine based API, Every time you bind resources , Texture binding , Modifying the rendering state and so on will change a global state machine . The biggest problem with this design is that it is easy to cause state leakage , You may just want to set a parameter for the texture , But change the texture binding of the state machine , And if you don't change this state , It's going to leak all the way to the rest DrawCall in . This is based on OpenGL Rendering engine design brings a lot of problems , Most engines have their own way to ensure that they have a DrawCall It's not going to leak to another DrawCall, This leads to some very difficult debugging BUG.
So in order to alleviate this problem to a certain extent ,OpenGL It's introduced DSA.DSA One allows you to access object Without binding to the global state machine . Such as no DSA when , You need to bind one first buffer Of object, To allocate storage for it , Upload data, etc , And with DSA, You can go directly to object, Allocate storage for it , Upload data , Avoid binding it to a state machine .
But why do I say it's remission to a certain extent , because DSA Binding cannot be avoided completely , When you will buffer perhaps texture When it's really used in the rendering process , You still have to bind them to context . For example, in front of you through DSA The way to assign a buffer object, And uploaded data for it , Now you want to use it for a certain time DrawCall As uniform data , You need to call glBindBufferRange(GL_UNIFORM_BUFFER,object,...). take object Bind to the specified Target On .
Even so , With DSA Still can bring a lot of convenience for program design . You just need to bind when you're actually drawing object, Instead of binding it at various initialization times , To a certain extent, it reduces the number of state machine switching .
I'll give you a few simple examples DSA The introduction of a new API And the old API Contrast between
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);