Understanding WebGL State
I recently gave a similar answer, but I just said that there's quite a lot and gave a link to the spec, without copy pasting anything. Lesson learned, I can fix that. But just a fair warning, if people call WebGL "stateful" they mean it. But the document, that contains all the errors WebGL can generate under which conditions is called the spec. I'm not copying over all the possible errors, because that would easily double it, if not more.
First, because are you explicitly asked about binding targets, here is how you query all of those, not counting extensions:
gl.getParameter( gl.ARRAY_BUFFER_BINDING);
gl.getParameter( gl.ELEMENT_ARRAY_BUFFER_BINDING);
gl.getParameter( gl.FRAMEBUFFER_BINDING);
gl.getParameter( gl.RENDERBUFFER_BINDING);
gl.getParameter( gl.TEXTURE_BINDING_2D);
gl.getParameter( gl.TEXTURE_BINDING_CUBE_MAP);
Now you don't have to go through this huge list to find those. But if you write a framework, and want to understand the state, you may want to use all the others, too.
getParameter(GLenum pname)
pname returned type
ACTIVE_TEXTURE GLenum
ALIASED_LINE_WIDTH_RANGE Float32Array (with 2 elements)
ALIASED_POINT_SIZE_RANGE Float32Array (with 2 elements)
ALPHA_BITS GLint
ARRAY_BUFFER_BINDING WebGLBuffer
BLEND GLboolean
BLEND_COLOR Float32Array (with 4 values)
BLEND_DST_ALPHA GLenum
BLEND_DST_RGB GLenum
BLEND_EQUATION_ALPHA GLenum
BLEND_EQUATION_RGB GLenum
BLEND_SRC_ALPHA GLenum
BLEND_SRC_RGB GLenum
BLUE_BITS GLint
COLOR_CLEAR_VALUE Float32Array (with 4 values)
COLOR_WRITEMASK sequence<GLboolean> (with 4 values)
COMPRESSED_TEXTURE_FORMATS Uint32Array
CULL_FACE GLboolean
CULL_FACE_MODE GLenum
CURRENT_PROGRAM WebGLProgram
DEPTH_BITS GLint
DEPTH_CLEAR_VALUE GLfloat
DEPTH_FUNC GLenum
DEPTH_RANGE Float32Array (with 2 elements)
DEPTH_TEST GLboolean
DEPTH_WRITEMASK GLboolean
DITHER GLboolean
ELEMENT_ARRAY_BUFFER_BINDING WebGLBuffer
FRAMEBUFFER_BINDING WebGLFramebuffer
FRONT_FACE GLenum
GENERATE_MIPMAP_HINT GLenum
GREEN_BITS GLint
IMPLEMENTATION_COLOR_READ_FORMAT GLenum
IMPLEMENTATION_COLOR_READ_TYPE GLenum
LINE_WIDTH GLfloat
MAX_COMBINED_TEXTURE_IMAGE_UNITS GLint
MAX_CUBE_MAP_TEXTURE_SIZE GLint
MAX_FRAGMENT_UNIFORM_VECTORS GLint
MAX_RENDERBUFFER_SIZE GLint
MAX_TEXTURE_IMAGE_UNITS GLint
MAX_TEXTURE_SIZE GLint
MAX_VARYING_VECTORS GLint
MAX_VERTEX_ATTRIBS GLint
MAX_VERTEX_TEXTURE_IMAGE_UNITS GLint
MAX_VERTEX_UNIFORM_VECTORS GLint
MAX_VIEWPORT_DIMS Int32Array (with 2 elements)
PACK_ALIGNMENT GLint
POLYGON_OFFSET_FACTOR GLfloat
POLYGON_OFFSET_FILL GLboolean
POLYGON_OFFSET_UNITS GLfloat
RED_BITS GLint
RENDERBUFFER_BINDING WebGLRenderbuffer
RENDERER DOMString
SAMPLE_BUFFERS GLint
SAMPLE_COVERAGE_INVERT GLboolean
SAMPLE_COVERAGE_VALUE GLfloat
SAMPLES GLint
SCISSOR_BOX Int32Array (with 4 elements)
SCISSOR_TEST GLboolean
SHADING_LANGUAGE_VERSION DOMString
STENCIL_BACK_FAIL GLenum
STENCIL_BACK_FUNC GLenum
STENCIL_BACK_PASS_DEPTH_FAIL GLenum
STENCIL_BACK_PASS_DEPTH_PASS GLenum
STENCIL_BACK_REF GLint
STENCIL_BACK_VALUE_MASK GLuint
STENCIL_BACK_WRITEMASK GLuint
STENCIL_BITS GLint
STENCIL_CLEAR_VALUE GLint
STENCIL_FAIL GLenum
STENCIL_FUNC GLenum
STENCIL_PASS_DEPTH_FAIL GLenum
STENCIL_PASS_DEPTH_PASS GLenum
STENCIL_REF GLint
STENCIL_TEST GLboolean
STENCIL_VALUE_MASK GLuint
STENCIL_WRITEMASK GLuint
SUBPIXEL_BITS GLint
TEXTURE_BINDING_2D WebGLTexture
TEXTURE_BINDING_CUBE_MAP WebGLTexture
UNPACK_ALIGNMENT GLint
UNPACK_COLORSPACE_CONVERSION_WEBGL GLenum
UNPACK_FLIP_Y_WEBGL GLboolean
UNPACK_PREMULTIPLY_ALPHA_WEBGL GLboolean
VENDOR DOMString
VERSION DOMString
VIEWPORT Int32Array (with 4 elements)
enableVertexAttribArray
and vertexAttribPointer
are setting the state of a vertex attribute array at a specific index, and don't have anything to do with the program. You can also query all this state, by aforementioned index.
getVertexAttrib (GLuint index, GLenum pname )
pname returned type
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING WebGLBuffer
VERTEX_ATTRIB_ARRAY_ENABLED GLboolean
VERTEX_ATTRIB_ARRAY_SIZE GLint
VERTEX_ATTRIB_ARRAY_STRIDE GLint
VERTEX_ATTRIB_ARRAY_TYPE GLenum
VERTEX_ATTRIB_ARRAY_NORMALIZED GLboolean
CURRENT_VERTEX_ATTRIB Float32Array (with 4 elements)
If you now look at the state of the program, there isn't much overlap. One could even go as far as make experiments and see yourself how the states change.
getProgramParameter(WebGLProgram? program, GLenum pname)
pname returned type
DELETE_STATUS GLboolean
LINK_STATUS GLboolean
VALIDATE_STATUS GLboolean
ATTACHED_SHADERS GLint
ACTIVE_ATTRIBUTES GLint
ACTIVE_UNIFORMS GLint
Or maybe you want to check how your shader is doing. Still no real overlap in sight.
getShaderParameter(WebGLShader? shader, GLenum pname)
pname returned type
SHADER_TYPE GLenum
DELETE_STATUS GLboolean
COMPILE_STATUS GLboolean
You saw getVertexAttrib
returns a buffer, so that seems relevant. The buffer itself isn't that much more exciting than say a plain ArrayBuffer. The contents are just not in javacript, but far away in gpu land, doing hard work to support the family at home.
getBufferParameter(GLenum target, GLenum pname)
pname returned type
BUFFER_SIZE GLint
BUFFER_USAGE GLenum
So probably programs and vertex arrays don't have that much in common. Difficult to deduce by guessing, but really simple to find out if you know ( or abstract away ) all those getters.
For completeness, and to help you understand state, I also copy over all the other things.
getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname)
pname returned type
FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE GLenum
FRAMEBUFFER_ATTACHMENT_OBJECT_NAME WebGLRenderbuffer or WebGLTexture
FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL GLint
FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE GLint
getRenderbufferParameter(GLenum target, GLenum pname)
pname returned type
RENDERBUFFER_WIDTH GLint
RENDERBUFFER_HEIGHT GLint
RENDERBUFFER_INTERNAL_FORMAT GLenum
RENDERBUFFER_RED_SIZE GLint
RENDERBUFFER_GREEN_SIZE GLint
RENDERBUFFER_BLUE_SIZE GLint
RENDERBUFFER_ALPHA_SIZE GLint
RENDERBUFFER_DEPTH_SIZE GLint
RENDERBUFFER_STENCIL_SIZE GLint
getTexParameter(GLenum target, GLenum pname)
pname returned type
TEXTURE_MAG_FILTER GLenum
TEXTURE_MIN_FILTER GLenum
TEXTURE_WRAP_S GLenum
TEXTURE_WRAP_T GLenum
I didn't give up moderating it just yet. So maybe you want to check the value of your uniforms. That's really useful sometimes.
getUniform(WebGLProgram? program, WebGLUniformLocation? location)
Here a few more really useful getters:
getActiveAttrib(WebGLProgram? program, GLuint index)
getActiveUniform(WebGLProgram? program, GLuint index)
And of course the ones everbody loves:
getUniformLocation(WebGLProgram? program, DOMString name)
getAttribLocation(WebGLProgram? program, DOMString name)
getProgramInfoLog(WebGLProgram? program)
getShaderInfoLog(WebGLShader? shader)
getShaderSource(WebGLShader? shader)
getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
getSupportedExtensions()
Oh here that one actually belongs to the vertex attributes, almost forgot. It's separate for important legacy reasons.
getVertexAttribOffset(GLuint index, GLenum pname)
( pname has to be VERTEX_ATTRIB_ARRAY_POINTER
on that one. )
Unless I forgot something, that's basically all of WebGL state. It may seem like a lot, but I personally found all of it to be really helpful to understand how things work. Without those you are basically blindfolded and have to just guess all the time, and follow tutorials telling you the exact order you have to call functions in, which doesn't work well with WebGL - just because there are so many things, but also mistakes you can do.
Screenius answer is pretty complete.
Here is a webgl state diagram
The terser version is:
In WebGL 1.0, uniforms are per program, texture filtering and wrapping is per texture. Everything else is global. That includes all attributes and all texture units.
Pasted from some previous answers that cover this
You can think of attributes and texture units like this
gl = {
arrayBuffer: someBuffer,
vertexArray: {
elementArrayBuffer: someOtherBuffer,
attributes: [],
},
};
When you call gl.bindBuffer
you're just setting one of 2 global variables in the gl state.
gl.bindBuffer = function(bindPoint, buffer) {
switch (bindPoint) {
case: this.ARRAY_BUFFER:
this.arrayBuffer = buffer;
break;
case: this.ELEMENT_ARRAY_BUFFER:
this.vertexArray.elementArrayBuffer = buffer;
break;
}
};
When you call gl.vertexAttribPointer
it copies current value of arrayBuffer
to the specified attribute.
gl.vertexAttribPointer = function(index, size, type, normalized, stride, offset) {
var attribute = this.vertexArray.attributes[index];
attribute.size = size;
attribute.type = type;
attribute.normalized = normalized;
attribute.stride = stride;
attribute.offset = offset;
attribute.buffer = this.arrayBuffer; // copies the current buffer reference.
};
Textures work similarly
gl = {
activeTextureUnit: 0,
textureUnits: [],
};
gl.activeTexture
sets which texture unit you're working on.
gl.activeTexture = function(unit) {
this.activeTextureUnit = unit - this.TEXTURE_0; // make it zero based.
};
Every texture unit has both a TEXTURE_2D
and a TEXTURE_CUBEMAP
so gl.bindTexture(b, t)
is effectively
gl.bindTexture = function(bindPoint, texture) {
var textureUnit = this.textureUnits[this.activeTextureUnit];
switch (bindPoint) {
case this.TEXTURE_2D:
textureUnit.texture2D = texture;
break;
case this.TEXTURE_CUBEMAP:
textureUnit.textureCubeMap = texture;
break;
}
};
The rest is global state like the clear color, viewport, the blend settings, the stencil settings, the enable/disable stuff like DEPTH_TEST
, SCISSOR_TEST
Just a side note: If you enable the extension OES_vertex_array_object the vertexArray
in the example above becomes its own object that you can bind with bindVertexArrayOES
.