[Mesa-dev] [PATCH 8/9] mesa: add Uniform Buffer Object API implementation
Brian Paul
brianp at vmware.com
Mon Oct 17 08:42:21 PDT 2011
On 10/16/2011 04:37 PM, vlj wrote:
> ---
> src/mesa/main/bufferobj.c | 2 +
> src/mesa/main/uniforms.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
> src/mesa/main/uniforms.h | 15 ++++
> 3 files changed, 204 insertions(+), 0 deletions(-)
>
> diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
> index c453f9c..cddb0b4 100644
> --- a/src/mesa/main/bufferobj.c
> +++ b/src/mesa/main/bufferobj.c
> @@ -98,6 +98,8 @@ get_buffer_target(struct gl_context *ctx, GLenum target)
> return&ctx->Texture.BufferObject;
> }
> break;
> + case GL_UNIFORM_BUFFER:
> + return&ctx->UniformBufferObject.UniformObj;
We should have an extension check here as with some of the other cases:
case GL_UNIFORM_BUFFER:
if (ctx->Extensions.ARB_uniform_buffer_object)
return &ctx->UniformBufferObject.UniformObj;
}
> default:
> return NULL;
> }
> diff --git a/src/mesa/main/uniforms.c b/src/mesa/main/uniforms.c
> index fe1ce6d..253e5cf 100644
> --- a/src/mesa/main/uniforms.c
> +++ b/src/mesa/main/uniforms.c
I'm thinking this new code should go into a new file (ubo.c) because
uniforms.c is rather large already and on the surface it doesn't look
like there's a lot of code sharing with what's in uniforms.c
> @@ -45,12 +45,14 @@
> #include "main/shaderapi.h"
> #include "main/shaderobj.h"
> #include "main/uniforms.h"
> +#include "main/hash.h"
> #include "program/prog_parameter.h"
> #include "program/prog_statevars.h"
> #include "program/prog_uniform.h"
> #include "program/prog_instruction.h"
>
>
> +
> static GLenum
> base_uniform_type(GLenum type)
> {
> @@ -1064,6 +1066,121 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
> uniform->Initialized = GL_TRUE;
> }
>
> +static void
> +_mesa_query_ubo_general(struct gl_context *ctx, struct gl_shader_program *shProg, GLint ubo_index,
> + GLenum query, int* data)
> +{
> + if(ubo_index> shProg->UBOCount || ubo_index< 0)
> + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformBlock(uniformBlockIndex)");
'return' after generating the error.
> +
> + struct ubo current_ubo = *(shProg->UniformBufferObject[ubo_index]);
> +
> + switch(query)
> + {
> + case GL_UNIFORM_BLOCK_BINDING:
> + *data = current_ubo.BoundBuffer;
> + break;
> + case GL_UNIFORM_BLOCK_DATA_SIZE:
> + *data = 0;
> + break;
> + case GL_UNIFORM_BLOCK_NAME_LENGTH:
> + *data = strlen(current_ubo.Name);
> + break;
> + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
> + *data = current_ubo.NumberOfVariables;
> + break;
> + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
> + case GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER:
> + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
> + *data = 0;
> + break;
> + default:
> + break;
I suspect we should generate a GL_INVALID_ENUM error for the default
case here.
> + }
> +}
> +
> +/**
> + * TODO : Switch to hash table
> + */
> +static GLuint
> +getIndices(const struct gl_shader_program* prog, const char* name)
get_indices(const struct gl_shader_program *prog, const char *name)
> +{
> + unsigned i,k;
> + for (k = 0; k< prog->Uniforms->Size; k++)
> + {
> + struct gl_uniform* current_uniform =&(prog->Uniforms->Uniforms[k]);
> + if(strcmp(name,current_uniform->Name)==0)
> + {
> + return k;
> + }
> + }
> + for (i = 0;i< prog->UBOVariableCount; i++)
> + {
> + struct UBOVariableInfo* var = prog->IndexedUniformsInUBO[i];
> + if(strcmp(name,var->Name)==0)
> + {
> + return i + prog->Uniforms->Size;
> + }
> + }
> + return GL_INVALID_INDEX;
> +}
> +
> +static void
> +_mesa_get_ubo_name(struct gl_context *ctx, struct gl_shader_program *shProg, GLint index,
> + GLsizei bufsize, GLsizei* length, char* buffer)
> +{
> + if(index>= shProg->UBOCount || index< 0) {
> + _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockName(uniformBlockIndex)");
> + return;
> + }
> +
> + struct ubo current_ubo = *(shProg->UniformBufferObject[index]);
> + GLsizei temp_length = strlen(current_ubo.Name);
We need to put declarations before code so we can compile with MSVC.
So put these var decls at the top of the function.
> + if(bufsize - 1< temp_length) {
> + _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockName(bufSize)");
> + return;
> + }
> +
> + memcpy(buffer,current_ubo.Name,temp_length);
> + buffer[temp_length] = '\0';
> + if(length != NULL)
> + *length = temp_length;
> +}
> +
> +static void
> +_mesa_link_buffer_uniform(struct gl_context* ctx,struct gl_shader_program *shProg, GLint ubo_index,
> + GLint buffer_index)
> +{
> + if(ubo_index> shProg->UBOCount || ubo_index< 0)
> + _mesa_error(ctx, GL_INVALID_VALUE, "UniformBlockBinding(uniformBlockIndex)");
> +
> + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
> +
> + shProg->UniformBufferObject[ubo_index]->BoundBuffer = buffer_index;
> +}
> +
> +static
> +GLint GetLoneUniformInfo(struct gl_shader_program* sh, GLuint index, GLenum pname) {
> + uint n = sh->Uniforms->Size;
> + if(index>= n) {
> + struct UBOVariableInfo *var = sh->IndexedUniformsInUBO[index - n];
> + switch(pname) {
> + case GL_UNIFORM_TYPE:
> + return var->Type;
> + case GL_UNIFORM_SIZE:
> + case GL_UNIFORM_BLOCK_NAME_LENGTH:
> + case GL_UNIFORM_BLOCK_INDEX:
> + return var->UBO->Index;
> + case GL_UNIFORM_OFFSET:
> + return var->Offset;
> + case GL_UNIFORM_ARRAY_STRIDE:
> + case GL_UNIFORM_MATRIX_STRIDE:
> + return var->Stride;
> + case GL_UNIFORM_IS_ROW_MAJOR:
> + return sh->UniformBufferObject[var->UBO->Index]->MatrixLayout == rowmajor;
> + }
Add default case to raise GL_INVALID_ENUM?
> + }
> +}
>
> void GLAPIENTRY
> _mesa_Uniform1fARB(GLint location, GLfloat v0)
> @@ -1452,6 +1569,69 @@ _mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
> type, name);
> }
>
> +void GLAPIENTRY
> +_mesa_GetActiveUniformBlockInfo(GLuint program,GLuint ubo_index,GLenum pname, GLint* params)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "GetActiveUniformBlockiv");
> + _mesa_query_ubo_general(ctx,shProg,ubo_index,pname,params);
> +}
> +
> +void GLAPIENTRY
> +_mesa_GetActiveUniformBlockName(GLuint program,GLuint ubo_index,GLsizei bufsize, GLint* length, char* name)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "GetActiveUniformBlockName");
> + _mesa_get_ubo_name(ctx,shProg,ubo_index,bufsize,length,name);
> +}
> +
> +/* Note : location and index are the same */
> +void GLAPIENTRY
> +_mesa_GetUniformIndices(GLuint program, GLsizei number_of_variables, const char** names, GLuint* indices)
> +{
> + unsigned i;
> + GET_CURRENT_CONTEXT(ctx);
> +
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "GetUniformIndices");
> + for (i=0; i< number_of_variables; i++)
> + {
> + indices[i] = getIndices(shProg,names[i]);
> + }
> +}
> +
> +void GLAPIENTRY
> +_mesa_GetActiveUniformName(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, char* uniformName)
> +{
> + GET_CURRENT_CONTEXT(ctx);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "GetActiveUniformName");
> + const char* name = shProg->Uniforms->Uniforms[index].Name;
We need to check for shProg==NULL (in case 'program' is invalid) and
we need to check that 'index' isn't out of bounds (and raise
GL_INVALID_VALUE, probably).
It looks like quite a bit of error checking is missing in this file,
actually. The "Errors" section of the extension spec should list
everything you need to check.
> + unsigned n = strlen(name);
> + if(n + 1<= bufsize) {
> + memcpy(uniformName,name,n);
> + uniformName[n]='\0';
> + }
> + if(length) {
> + *length = n;
> + }
> +}
> +
> +void GLAPIENTRY
> +_mesa_GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* param)
> +{
> + unsigned k;
> + GET_CURRENT_CONTEXT(ctx);
> + struct gl_shader_program *shProg =
> + _mesa_lookup_shader_program_err(ctx, program, "GetActiveUniformsiv");
> +
> +
> + for(k = 0; k< uniformCount; k++) {
> + param[k] = GetLoneUniformInfo(shProg,uniformIndices[k],pname);
> + }
> +}
>
> /**
> * Plug in shader uniform-related functions into API dispatch table.
> @@ -1510,5 +1690,12 @@ _mesa_init_shader_uniform_dispatch(struct _glapi_table *exec)
> SET_GetnUniformuivARB(exec, _mesa_GetnUniformuivARB);
> SET_GetnUniformdvARB(exec, _mesa_GetnUniformdvARB); /* GL 4.0 */
>
> + /* GL_ARB_Uniform_Buffer_Object */
> + SET_GetActiveUniformBlockiv(exec, _mesa_GetActiveUniformBlockInfo);
> + SET_GetActiveUniformBlockName(exec, _mesa_GetActiveUniformBlockName);
> + SET_GetUniformIndices(exec, _mesa_GetUniformIndices);
> + SET_GetActiveUniformName(exec, _mesa_GetActiveUniformName);
> + SET_GetActiveUniformsiv(exec,_mesa_GetActiveUniformsiv);
> +
> #endif /* FEATURE_GL */
> }
> diff --git a/src/mesa/main/uniforms.h b/src/mesa/main/uniforms.h
> index b024cb3..dfcf16b 100644
> --- a/src/mesa/main/uniforms.h
> +++ b/src/mesa/main/uniforms.h
> @@ -169,6 +169,21 @@ _mesa_GetnUniformdvARB(GLhandleARB, GLint, GLsizei, GLdouble *);
> extern GLint GLAPIENTRY
> _mesa_GetUniformLocationARB(GLhandleARB, const GLcharARB *);
>
> +void GLAPIENTRY
> +_mesa_GetActiveUniformBlockInfo(GLuint, GLuint, GLenum, GLint *);
> +
> +extern void GLAPIENTRY
> +_mesa_GetActiveUniformBlockName(GLuint, GLuint, GLsizei, GLint *, char *);
> +
> +extern void GLAPIENTRY
> +_mesa_GetUniformIndices(GLuint, GLsizei, const char **, GLuint *);
> +
> +extern void GLAPIENTRY
> +_mesa_GetActiveUniformName(GLuint, GLuint, GLsizei, GLsizei*, char*);
> +
> +void GLAPIENTRY
> +_mesa_GetActiveUniformsiv(GLuint, GLsizei, const GLuint*, GLenum, GLint*);
> +
> GLint
> _mesa_get_uniform_location(struct gl_context *ctx, struct gl_shader_program *shProg,
> const GLchar *name);
After putting this code into a new ubo.c file, run 'indent' on it per
the "Development Notes" on the website to fix the formatting. Thanks.
-Brian
More information about the mesa-dev
mailing list