Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding WebGL State

Tags:

webgl

Is there any documentation I can find somewhere which documents the preconditions required for WebGL calls?

I have gotten a fairly strong grasp of the WebGL basics, but now I am creating my own 'framework' and I'm after a deeper understanding.

For example, the enableVertexAttribArray call. Does this call required the current shader to be in 'use'? Where does it store this 'enabled' flag? If I switch shader programs, do I have to re-enable it afterwards when I use it again?

I'd love some kind of diagram explaining where all the 'stateful' information is being stored, and when it will go out of context.

Another example is using gl.bindBuffer, are the buffers for ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER stored in separate locations?

With all this in mind, is it recommended to have a parallel state in JavaScript to avoid running WebGL calls? i.e. storing a 'currentBuffer' object to avoid binding the same buffer over and over if its already bound. I can imagine in the general case, this becomes quite a bit of state duplication, but could be quite good for performance.

Bit of a fundamental question but hard to find info on.

like image 714
Brendan Annable Avatar asked Feb 19 '15 11:02

Brendan Annable


People also ask

Is WebGL written in C++?

WebGL runs on the GPU on your computer. As such you need to provide the code that runs on that GPU. You provide that code in the form of pairs of functions. Those 2 functions are called a vertex shader and a fragment shader and they are each written in a very strictly typed C/C++ like language called GLSL.

What is a vertex in WebGL?

WebGL handles geometry in a standard way, independently of the complexity and number of points that surfaces can have. There are two data types that are fundamental to represent the geometry of any 3D object: vertices and indices. Vertices are the points that define the corners of 3D objects.

Is WebGL low level?

For developers, WebGL provides low-level access to hardware with the familiar code structure of OpenGL ES. WebGL was originally created by Mozilla. The API is currently designed and maintained by the non-profit Khronos Group as two part code: control code and shader code.

How do buffers work in WebGL?

The bufferData function copies data from your JavaScript program into the GPU's buffer object. If there was already data in the buffer object then its current contents is deleted and the new data is added. The main error you will receive when copying data to the GPU is OUT_OF_MEMORY.


1 Answers

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.

like image 103
Winchestro Avatar answered Nov 25 '22 02:11

Winchestro