[Mesa-dev] [PATCH 16/17] mesa: add Uniform Buffer Object API implementation

Vincent Lejeune vljn at ovi.com
Sun Dec 25 10:20:11 PST 2011


   v2:Move implementation to ubo.cpp and ubo.h as suggested by
   Brian Paul
---
 src/mesa/main/api_exec.c                     |    2 +
 src/mesa/main/bufferobj.c                    |   11 +
 src/mesa/main/ubo.cpp                        |  369 ++++++++++++++++++++++++++
 src/mesa/main/ubo.h                          |   39 +++
 src/mesa/sources.mak                         |    1 +
 src/mesa/state_tracker/st_cb_bufferobjects.c |    6 +-
 6 files changed, 427 insertions(+), 1 deletions(-)
 create mode 100644 src/mesa/main/ubo.cpp
 create mode 100644 src/mesa/main/ubo.h

diff --git a/src/mesa/main/api_exec.c b/src/mesa/main/api_exec.c
index e0bf90d..c908719 100644
--- a/src/mesa/main/api_exec.c
+++ b/src/mesa/main/api_exec.c
@@ -102,6 +102,7 @@
 #if FEATURE_ARB_shader_objects
 #include "shaderapi.h"
 #include "uniforms.h"
+#include "ubo.h"
 #endif
 #include "syncobj.h"
 #include "main/dispatch.h"
@@ -307,6 +308,7 @@ _mesa_create_exec_table(void)
 #if FEATURE_ARB_shader_objects
    _mesa_init_shader_dispatch(exec);
    _mesa_init_shader_uniform_dispatch(exec);
+   _mesa_init_shader_uniform_buffer_objects(exec);
 #endif
 
    /* 2. GL_EXT_blend_color */
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index b7e59e8..d74b78c 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;
    default:
       return NULL;
    }
@@ -734,6 +736,10 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
 
          break;
 #endif
+#if FEATURE_ARB_uniform_buffer_object
+      case GL_UNIFORM_BUFFER:
+         break;
+#endif
       default:
          _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
          break;
@@ -756,6 +762,11 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
          _mesa_bind_buffer_range_for_transform_feedback(ctx, index, bufObj, 0, size);
          break;
 #endif
+#if FEATURE_ARB_uniform_buffer_object
+      case GL_UNIFORM_BUFFER:
+         ctx->UniformBufferObject.BindingPoint[index] = bufObj;
+         break;
+#endif
       default: /* should not go here */
          break;
    }
diff --git a/src/mesa/main/ubo.cpp b/src/mesa/main/ubo.cpp
new file mode 100644
index 0000000..f8f6445
--- /dev/null
+++ b/src/mesa/main/ubo.cpp
@@ -0,0 +1,369 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2011  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009-2011  VMware, Inc.  All Rights Reserved.
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright (C) 2011 Vincent Lejeune.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * API implementation of GL_ARB_uniform_buffer_object.
+ *
+ * Every uniform (in an UBO or not) is given an index that identifies it when
+ * calling one of these functions. Strictly speaking, such an index doesn't
+ * need to match location for classic uniform ; others drivers however use this
+ * approach so we're also matching them for compatibility purpose.
+ */
+
+#include <stdint.h>
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/dispatch.h"
+#include "main/image.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "program/hash_table.h"
+#include "program/prog_parameter.h"
+#include "program/prog_statevars.h"
+#include "program/prog_instruction.h"
+#include "main/ubo.h"
+#include "main/bufferobj.h"
+
+static void
+get_ubo_info(struct gl_context *ctx,
+             struct gl_shader_program *shProg, GLint ubo_index,
+             GLenum query, int *data, bool& pname_is_valid)
+{
+   pname_is_valid = true;
+
+   struct gl_uniform_buffer_object current_ubo =
+      shProg->UniformBufferObject[ubo_index];
+
+   switch (query) {
+   case GL_UNIFORM_BLOCK_BINDING:
+      *data = current_ubo.BindingPoint;                 // TODO : find a nice way to get buffer id
+      break;
+   case GL_UNIFORM_BLOCK_DATA_SIZE:
+      *data = current_ubo.Size;
+      printf("%s size is %d\n",current_ubo.Name,*data);
+      break;
+   case GL_UNIFORM_BLOCK_NAME_LENGTH:
+      *data = strlen(current_ubo.Name) + 1;
+      break;
+   case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+      *data = current_ubo.NumberOfVariables;
+      break;
+   case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+      *data = current_ubo.ReferencedByVS;
+      break;
+   case GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER:
+      *data = current_ubo.ReferencedByGS;
+      break;
+   case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+      *data = current_ubo.ReferencedByFS;
+      break;
+   default:
+      pname_is_valid = false;
+      break;
+   }
+   return;
+}
+
+static GLuint
+get_indice(const struct gl_shader_program *prog, const char *name)
+{
+   unsigned index;
+   if (prog->NamedAccessUBOVariables->get(index, name)) {
+      return index;
+   }
+
+   return GL_INVALID_INDEX;
+}
+
+static void
+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 gl_uniform_buffer_object current_ubo =
+      shProg->UniformBufferObject[index];
+
+   _mesa_copy_string(buffer,bufsize,length,current_ubo.Name);
+
+   return;
+}
+
+static void
+get_uniform_variable_name(struct gl_context *ctx,
+                          struct gl_shader_program *sh, GLuint index,
+                          GLsizei bufsize, GLsizei * length,
+                          char *uniformName)
+{
+
+   _mesa_copy_string(uniformName,bufsize,length,sh->IndexedUBOVariables[index].Name);
+   return;
+}
+
+static GLint
+get_uniform_variable_info(struct gl_shader_program *sh, GLuint index,
+                          GLenum pname, bool& pname_is_valid)
+{
+   pname_is_valid = true;
+   uint starting_index = sh->NumUserUniformStorage;
+   if (index >= starting_index) {
+      const struct gl_indexed_ubo_variable& var =
+         sh->IndexedUBOVariables[index - starting_index];
+      switch (pname) {
+      case GL_UNIFORM_TYPE:
+         return var.Type;
+      case GL_UNIFORM_SIZE:
+         if (var.Stride > 0)
+            return var.Size;
+         else
+            return 1;
+      case GL_UNIFORM_NAME_LENGTH:
+         return strlen(var.Name) + 1;
+      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 ==
+            UBO_MATRIX_LAYOUT_ROW_MAJOR;
+      default:
+         pname_is_valid = false;
+      }
+   }
+
+   return GL_INVALID_VALUE;
+}
+
+static void
+bind_uniform(struct gl_context *ctx, struct gl_shader_program *sh, GLuint index, GLuint binding)
+{
+   if (index > sh->UBOCount || index < 0)
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "UniformBlockBinding(uniformIndex)");
+
+   ctx->UniformBufferObject.UBOIndexes[binding] = sh->UniformBufferObject[index].Index + 1;
+}
+
+/** Note : the following functions should be able to run even if program has failed to build
+ * (BUT ! a link attempt must have occured for this program before) :
+ * - GetUniformBlockIndex
+ * - GetActiveUniformBlockName
+ * - GetActiveUniformBlockiv
+ * - GetUniformIndices
+ * - GetActiveUniformName
+ * - GetActiveUniform
+ * - GetActiveUniformsiv
+ *
+ * The spec is not clear what is the behaviour in failed link case.
+ */
+
+void GLAPIENTRY
+_mesa_GetActiveUniformBlockiv(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");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetActiveUniformBlockiv(program not linked)");
+      return;
+   }
+   if (ubo_index >= shProg->UBOCount) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockiv(uniformBlockIndex)");
+      return;
+   }
+   bool pname_status;
+   get_ubo_info(ctx, shProg, ubo_index, pname, params, pname_status);
+   if (!pname) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "GetActiveUniformBlockiv(pname)");
+      return;
+   }
+}
+
+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");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetActiveUniformBlockName(program not linked)");
+      return;
+   }
+   if (bufsize < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockName(bufSize)");
+   }
+   if (ubo_index >= shProg->UBOCount) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockName(uniformBlockIndex)");
+      return;
+   }
+
+   get_ubo_name(ctx, shProg, ubo_index, bufsize, length, name);
+}
+
+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");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetUniformIndices(program not linked)");
+      return;
+   }
+   if (number_of_variables < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetUniformIndices(uniformCount)");
+      return;
+   }
+
+   for (i = 0; i < number_of_variables; i++) {
+      indices[i] = get_indice(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");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetActiveUniformName(program not linked)");
+      return;
+   }
+   if (bufsize < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformName(bufSize)");
+      return;
+   }
+   if (index > (shProg->NumUserUniformStorage + shProg->IndexedVariableCount)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformName(uniformIndex)");
+      return;
+   }
+
+   get_uniform_variable_name(ctx, shProg, index, bufsize, length,
+                             uniformName);
+}
+
+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");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetActiveUniformsiv(program not linked)");
+      return;
+   }
+   if (uniformCount < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformiv(uniformCount)");
+      return;
+   }
+   const unsigned active_uniforms = shProg->NumUserUniformStorage + shProg->IndexedVariableCount;
+   for (k = 0; k < uniformCount; k++) {
+      if (uniformIndices[k] > active_uniforms) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformsiv(uniformIndices)");
+         return;
+      }
+   }
+
+   bool pname_status;
+   param[0] = get_uniform_variable_info(shProg, uniformIndices[0], pname,pname_status);
+   if (!pname) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "GetActiveUniformsiv(pname)");
+      return;
+   }
+   for (k = 1; k < uniformCount; k++) {
+      param[k] = get_uniform_variable_info(shProg, uniformIndices[k], pname,pname_status);
+   }
+}
+
+void GLAPIENTRY
+_mesa_UniformBlockBinding(GLuint prog, GLuint uboIndex, GLuint uboBinding)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg =
+         _mesa_lookup_shader_program_err(ctx, prog, "UniformBlockBinding(program)");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "UniformBlockBinding(program not linked)");
+      return;
+   }
+   if (uboIndex >= shProg->UBOCount) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "GetActiveUniformBlockName(uniformBlockIndex)");
+      return;
+   }
+
+   bind_uniform(ctx,shProg,uboIndex,uboBinding);
+}
+
+GLuint GLAPIENTRY
+_mesa_GetActiveUniformBlockIndex(GLuint prog, const char* uniformBlockName)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg =
+         _mesa_lookup_shader_program_err(ctx, prog, "UniformBlockBinding(program)");
+   if (!shProg->LinkStatus) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "GetActiveUnifromBlockIndex(program not linked)");
+      return GL_INVALID_VALUE;
+   }
+   for (unsigned i = 0; i < shProg->UBOCount; i++)
+   {
+      if (strcmp(uniformBlockName,shProg->UniformBufferObject[i].Name)==0)
+         return i;
+   }
+   return GL_INVALID_VALUE;
+}
+
+void
+_mesa_init_shader_uniform_buffer_objects(struct _glapi_table *exec)
+{
+/* GL_ARB_Uniform_Buffer_Object */
+   SET_GetUniformBlockIndex(exec,_mesa_GetActiveUniformBlockIndex);
+   SET_GetActiveUniformBlockiv(exec, _mesa_GetActiveUniformBlockiv);
+   SET_GetActiveUniformBlockName(exec, _mesa_GetActiveUniformBlockName);
+   SET_GetUniformIndices(exec, _mesa_GetUniformIndices);
+   SET_GetActiveUniformName(exec, _mesa_GetActiveUniformName);
+   SET_GetActiveUniformsiv(exec, _mesa_GetActiveUniformsiv);
+   SET_UniformBlockBinding(exec,_mesa_UniformBlockBinding);
+}
diff --git a/src/mesa/main/ubo.h b/src/mesa/main/ubo.h
new file mode 100644
index 0000000..99862fa
--- /dev/null
+++ b/src/mesa/main/ubo.h
@@ -0,0 +1,39 @@
+#ifndef UBO_H
+#define UBO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "glheader.h"
+struct _glapi_table;
+
+void GLAPIENTRY
+_mesa_GetActiveUniformBlockiv (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 *);
+
+void _mesa_init_shader_uniform_buffer_objects (struct _glapi_table *exec);
+
+void GLAPIENTRY
+_mesa_UniformBlockBinding(GLuint prog, GLuint uboIndex, GLuint uboBinding);
+
+GLuint GLAPIENTRY
+_mesa_GetActiveUniformBlockIndex(GLuint prog, const char* uniformBlockName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // UBO_H
diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak
index e72a1ce..c87b4be 100644
--- a/src/mesa/sources.mak
+++ b/src/mesa/sources.mak
@@ -106,6 +106,7 @@ MAIN_SOURCES = \
 MAIN_CXX_SOURCES = \
 	main/ff_fragment_shader.cpp \
 	main/shader_query.cpp \
+	main/ubo.cpp \
 	main/uniform_query.cpp
 
 MATH_SOURCES = \
diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.c b/src/mesa/state_tracker/st_cb_bufferobjects.c
index adac92f..c8ee6d7 100644
--- a/src/mesa/state_tracker/st_cb_bufferobjects.c
+++ b/src/mesa/state_tracker/st_cb_bufferobjects.c
@@ -128,7 +128,8 @@ st_bufferobj_subdata(struct gl_context *ctx,
     */
    pipe_buffer_write(st_context(ctx)->pipe,
 		     st_obj->buffer,
-		     offset, size, data);
+                 offset, size, data);
+
 }
 
 
@@ -195,6 +196,9 @@ st_bufferobj_data(struct gl_context *ctx,
    case GL_ELEMENT_ARRAY_BUFFER_ARB:
       bind = PIPE_BIND_INDEX_BUFFER;
       break;
+   case GL_UNIFORM_BUFFER:
+      bind = PIPE_BIND_CONSTANT_BUFFER;
+      break;
    default:
       bind = 0;
    }
-- 
1.7.7



More information about the mesa-dev mailing list