[Mesa-dev] [PATCH 6/6] mesa/st: add ARB_uniform_buffer_object support

Brian Paul brianp at vmware.com
Thu Dec 6 07:17:41 PST 2012


On 12/05/2012 11:24 PM, Dave Airlie wrote:
> From: Dave Airlie<airlied at redhat.com>
>
> this adds UBO support to the state tracker, it works with softpipe
> as-is.
>
> It uses UARL + CONST[x][ADDR[0].x] type constructs.
>
> Signed-off-by: Dave Airlie<airlied at redhat.com>
> ---
>   src/mesa/state_tracker/st_atom.c             |  2 +
>   src/mesa/state_tracker/st_atom.h             |  2 +
>   src/mesa/state_tracker/st_atom_constbuf.c    | 70 +++++++++++++++++++++++++++-
>   src/mesa/state_tracker/st_cb_bufferobjects.c |  3 ++
>   src/mesa/state_tracker/st_extensions.c       | 13 ++++++
>   src/mesa/state_tracker/st_glsl_to_tgsi.cpp   | 63 ++++++++++++++++++++++---
>   6 files changed, 146 insertions(+), 7 deletions(-)
>
> diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c
> index 102fee9..091bd55 100644
> --- a/src/mesa/state_tracker/st_atom.c
> +++ b/src/mesa/state_tracker/st_atom.c
> @@ -64,6 +64,8 @@ static const struct st_tracked_state *atoms[] =
>      &st_update_vs_constants,
>      &st_update_gs_constants,
>      &st_update_fs_constants,
> +&st_upload_vs_ubos,
> +&st_upload_fs_ubos,
>      &st_update_pixel_transfer,
>
>      /* this must be done after the vertex program update */
> diff --git a/src/mesa/state_tracker/st_atom.h b/src/mesa/state_tracker/st_atom.h
> index 6c7d09f..ca79b44 100644
> --- a/src/mesa/state_tracker/st_atom.h
> +++ b/src/mesa/state_tracker/st_atom.h
> @@ -67,6 +67,8 @@ extern const struct st_tracked_state st_finalize_textures;
>   extern const struct st_tracked_state st_update_fs_constants;
>   extern const struct st_tracked_state st_update_gs_constants;
>   extern const struct st_tracked_state st_update_vs_constants;
> +extern const struct st_tracked_state st_upload_fs_ubos;
> +extern const struct st_tracked_state st_upload_vs_ubos;
>   extern const struct st_tracked_state st_update_pixel_transfer;
>
>
> diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c
> index 580393e..ea0cf0e 100644
> --- a/src/mesa/state_tracker/st_atom_constbuf.c
> +++ b/src/mesa/state_tracker/st_atom_constbuf.c
> @@ -45,7 +45,7 @@
>   #include "st_atom.h"
>   #include "st_atom_constbuf.h"
>   #include "st_program.h"
> -
> +#include "st_cb_bufferobjects.h"
>
>   /**
>    * Pass the given program parameters to the graphics pipe as a
> @@ -175,3 +175,71 @@ const struct st_tracked_state st_update_gs_constants = {
>      },
>      update_gs_constants					/* update */
>   };
> +
> +static void st_upload_ubos(struct st_context *st,
> +                           struct gl_shader *shader,
> +                           unsigned shader_type)
> +{
> +   int i;
> +   struct pipe_constant_buffer cb = { 0 };
> +   assert(shader_type == PIPE_SHADER_VERTEX ||
> +          shader_type == PIPE_SHADER_FRAGMENT);

Is that assertion is really needed?  Will this function need changes 
for GS?


> +
> +   if (!shader)
> +      return;
> +
> +   for (i = 0; i<  shader->NumUniformBlocks; i++) {

'i' should be declared unsigned above to match the type of 
NumUniformBlocks, otherwise we'll get a signed/unsigned comparison 
warning with MSVC.


> +      struct gl_uniform_buffer_binding *binding;
> +      struct st_buffer_object *st_obj;
> +
> +      binding =&st->ctx->UniformBufferBindings[shader->UniformBlocks[i].Binding];
> +      st_obj = st_buffer_object(binding->BufferObject);
> +      pipe_resource_reference(&cb.buffer, st_obj->buffer);
> +
> +      cb.buffer_size = st_obj->buffer->width0 - binding->Offset;
> +
> +      st->pipe->set_constant_buffer(st->pipe, shader_type, 1 + i,&cb);
> +      pipe_resource_reference(&cb.buffer, NULL);
> +   }
> +}
> +
> +static void upload_vs_ubos(struct st_context *st)
> +{
> +   struct gl_shader_program *prog = st->ctx->Shader.CurrentVertexProgram;
> +
> +   if (!prog)
> +      return;
> +
> +   st_upload_ubos(st, prog->_LinkedShaders[MESA_SHADER_VERTEX], PIPE_SHADER_VERTEX);
> +}
> +
> +const struct st_tracked_state st_upload_vs_ubos = {
> +   "st_upload_vs_ubos",
> +   {
> +      (_NEW_PROGRAM | _NEW_BUFFER_OBJECT),
> +      ST_NEW_VERTEX_PROGRAM,
> +   },
> +   upload_vs_ubos
> +};
> +
> +static void upload_fs_ubos(struct st_context *st)
> +{
> +   struct gl_shader_program *prog = st->ctx->Shader.CurrentFragmentProgram;
> +
> +   if (!prog)
> +      return;
> +
> +   st_upload_ubos(st, prog->_LinkedShaders[MESA_SHADER_FRAGMENT], PIPE_SHADER_FRAGMENT);
> +
> +}
> +
> +const struct st_tracked_state st_upload_fs_ubos = {
> +   "st_upload_fs_ubos",
> +   {
> +      (_NEW_PROGRAM | _NEW_BUFFER_OBJECT),
> +      ST_NEW_FRAGMENT_PROGRAM,
> +   },
> +   upload_fs_ubos
> +};
> +
> +
> diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.c b/src/mesa/state_tracker/st_cb_bufferobjects.c
> index ac38128..7d1c05a 100644
> --- a/src/mesa/state_tracker/st_cb_bufferobjects.c
> +++ b/src/mesa/state_tracker/st_cb_bufferobjects.c
> @@ -198,6 +198,9 @@ st_bufferobj_data(struct gl_context *ctx,
>      case GL_TRANSFORM_FEEDBACK_BUFFER:
>         bind = PIPE_BIND_STREAM_OUTPUT;
>         break;
> +   case GL_UNIFORM_BUFFER:
> +      bind = PIPE_BIND_CONSTANT_BUFFER;
> +      break;
>      default:
>         bind = 0;
>      }
> diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
> index ccb1f36..d76cfdb 100644
> --- a/src/mesa/state_tracker/st_extensions.c
> +++ b/src/mesa/state_tracker/st_extensions.c
> @@ -70,6 +70,8 @@ void st_init_limits(struct st_context *st)
>      struct pipe_screen *screen = st->pipe->screen;
>      struct gl_constants *c =&st->ctx->Const;
>      gl_shader_type sh;
> +   boolean can_ubo = TRUE;
> +   int max_const_buffers;
>
>      c->MaxTextureLevels
>         = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS),
> @@ -218,6 +220,14 @@ void st_init_limits(struct st_context *st)
>         options->EmitNoIndirectUniform = !screen->get_shader_param(screen, sh,
>                                           PIPE_SHADER_CAP_INDIRECT_CONST_ADDR);
>
> +      if (options->EmitNoIndirectUniform)
> +         can_ubo = FALSE;
> +
> +      max_const_buffers = screen->get_shader_param(screen, sh,
> +                                                   PIPE_SHADER_CAP_MAX_CONST_BUFFERS);

Maybe add a comment describing where 12 comes from?


> +      if (max_const_buffers<  12)
> +         can_ubo = FALSE;
> +
>         if (options->EmitNoLoops)
>            options->MaxUnrollIterations = MIN2(screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS), 65536);
>         else
> @@ -251,6 +261,9 @@ void st_init_limits(struct st_context *st)
>
>      c->GLSLSkipStrictMaxVaryingLimitCheck =
>         screen->get_param(screen, PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS);
> +
> +   if (can_ubo)
> +      st->ctx->Extensions.ARB_uniform_buffer_object = GL_TRUE;
>   }
>
>
> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> index ae3b8b2..e8a174c 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> @@ -107,6 +107,7 @@ public:
>         else
>            this->swizzle = SWIZZLE_XYZW;
>         this->negate = 0;
> +      this->index2D = 0;
>         this->type = type ? type->base_type : GLSL_TYPE_ERROR;
>         this->reladdr = NULL;
>      }
> @@ -116,6 +117,18 @@ public:
>         this->type = type;
>         this->file = file;
>         this->index = index;
> +      this->index2D = 0;
> +      this->swizzle = SWIZZLE_XYZW;
> +      this->negate = 0;
> +      this->reladdr = NULL;
> +   }
> +
> +   st_src_reg(gl_register_file file, int index, int type, int index2D)
> +   {
> +      this->type = type;
> +      this->file = file;
> +      this->index = index;
> +      this->index2D = index2D;
>         this->swizzle = SWIZZLE_XYZW;
>         this->negate = 0;
>         this->reladdr = NULL;
> @@ -126,6 +139,7 @@ public:
>         this->type = GLSL_TYPE_ERROR;
>         this->file = PROGRAM_UNDEFINED;
>         this->index = 0;
> +      this->index2D = 0;
>         this->swizzle = 0;
>         this->negate = 0;
>         this->reladdr = NULL;
> @@ -135,6 +149,7 @@ public:
>
>      gl_register_file file; /**<  PROGRAM_* from Mesa */
>      int index; /**<  temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
> +   int index2D;
>      GLuint swizzle; /**<  SWIZZLE_XYZWONEZERO swizzles from Mesa. */
>      int negate; /**<  NEGATE_XYZW mask from mesa */
>      int type; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */
> @@ -183,6 +198,7 @@ st_src_reg::st_src_reg(st_dst_reg reg)
>      this->swizzle = SWIZZLE_XYZW;
>      this->negate = 0;
>      this->reladdr = reg.reladdr;
> +   this->index2D = 0;
>   }
>
>   st_dst_reg::st_dst_reg(st_src_reg reg)
> @@ -1873,10 +1889,29 @@ glsl_to_tgsi_visitor::visit(ir_expression *ir)
>         assert(!"GLSL 1.30 features unsupported");
>         break;
>
> -   case ir_binop_ubo_load:
> -      assert(!"not yet supported");
> -      break;
> +   case ir_binop_ubo_load: {
> +      ir_constant *uniform_block = ir->operands[0]->as_constant();
> +      st_src_reg index_reg = get_temp(glsl_type::uint_type);
> +      st_src_reg cbuf;
> +
> +      cbuf.type = glsl_type::vec4_type->base_type;
> +      cbuf.file = PROGRAM_CONSTANT;
> +      cbuf.index = 0;
> +      cbuf.index2D = uniform_block->value.u[0] + 1;
> +      cbuf.reladdr = NULL;
> +      cbuf.negate = 0;
> +
> +      assert(ir->type->is_vector() || ir->type->is_scalar());
>
> +      emit(ir, TGSI_OPCODE_USHR, st_dst_reg(index_reg), op[1], st_src_reg_for_int(4));
> +
> +      cbuf.swizzle = swizzle_for_size(ir->type->vector_elements);
> +      cbuf.reladdr = ralloc(mem_ctx, st_src_reg);
> +      memcpy(cbuf.reladdr,&index_reg, sizeof(index_reg));
> +
> +      emit(ir, TGSI_OPCODE_MOV, result_dst, cbuf);
> +      break;
> +   }
>      case ir_quadop_vector:
>         /* This operation should have already been handled.
>          */
> @@ -4061,7 +4096,7 @@ dst_register(struct st_translate *t,
>   static struct ureg_src
>   src_register(struct st_translate *t,
>                gl_register_file file,
> -             GLint index)
> +             GLint index, GLint index2D)
>   {
>      switch(file) {
>      case PROGRAM_UNDEFINED:
> @@ -4081,7 +4116,13 @@ src_register(struct st_translate *t,
>         return t->constants[index];
>      case PROGRAM_STATE_VAR:
>      case PROGRAM_CONSTANT:       /* ie, immediate */
> -      if (index<  0)
> +      if (index2D) {
> +         struct ureg_src src;
> +         src = ureg_src_register(TGSI_FILE_CONSTANT, 0);
> +         src.Dimension = 1;
> +         src.DimensionIndex = index2D;
> +         return src;
> +      } else if (index<  0)
>            return ureg_DECL_constant(t->ureg, 0);
>         else
>            return t->constants[index];
> @@ -4160,7 +4201,7 @@ translate_dst(struct st_translate *t,
>   static struct ureg_src
>   translate_src(struct st_translate *t, const st_src_reg *src_reg)
>   {
> -   struct ureg_src src = src_register(t, src_reg->file, src_reg->index);
> +   struct ureg_src src = src_register(t, src_reg->file, src_reg->index, src_reg->index2D);
>
>      src = ureg_swizzle(src,
>                         GET_SWZ(src_reg->swizzle, 0)&  0x3,
> @@ -4754,6 +4795,14 @@ st_translate_program(
>            }
>         }
>      }
> +
> +   if (program->shader_program) {
> +      unsigned num_ubos = program->shader_program->NumUniformBlocks;
> +
> +      for (i = 0; i<  num_ubos; i++) {
> +         ureg_DECL_constant2D(t->ureg, 0, program->shader_program->UniformBlocks[i].UniformBufferSize / 4, i + 1);
> +      }
> +   }
>
>      /* Emit immediate values.
>       */
> @@ -5090,6 +5139,8 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
>                || progress;
>
>            progress = do_vec_index_to_cond_assign(ir) || progress;
> +
> +         lower_ubo_reference(prog->_LinkedShaders[i], ir);
>         } while (progress);
>
>         validate_ir_tree(ir);

Otherwise the series looks great.  Thanks!

Reviewed-by: Brian Paul <brianp at vmware.com>


More information about the mesa-dev mailing list